弹出gridview单元格

时间:2013-07-24 06:55:35

标签: java android android-gridview

我有一个网格视图我在其中动态添加Button。 我正在将OnTouch侦听器设置为网格视图。 我希望当我的手指在特定单元格上移动时,该单元格元素应该弹出 类似我们的Android键盘做的方式。

public class MainActivity extends Activity {
private ArrayList<Integer> data;
private GridView gv;

private TextView biggerView = null;

@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    createData();
    gv = (GridView) findViewById(R.id.grid);
    gv.setNumColumns(10);
    gv.setAdapter(new FilterButtonAdapter(data, this));

    gv.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View arg0, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                try {
                    int position = gv.pointToPosition((int) event.getX(),
                            (int) event.getY());

                    View v = (View) gv.getChildAt(position);
                    if (v != null) {
                        gv.requestFocus();
                          gv.setSelection(gv.pointToPosition( (int)
                          event.getX(), (int) event.getY()));

                    }

                    return true;
                } catch (Exception e) {
                    return true;
                }
            }

            if (event.getAction() == MotionEvent.ACTION_UP) {

                int position = gv.pointToPosition((int) event.getX(),
                        (int) event.getY());
                View v = (View) gv.getChildAt(position);
                if (v != null) {
                    gv.clearFocus();
                    TextView tv = (TextView) v.findViewById(R.id.texttoadd);
                    Toast.makeText(MainActivity.this, tv.getText(),
                            Toast.LENGTH_SHORT).show();

                }

                return true;
            }
            return false;
        }
    });

}

private void createData() {
    data = new ArrayList<Integer>();
    for (int i = 0; i < 200; i++) {
        data.add(i);
    }
}


enter code here
  

我已经写了这个代码,它给了我所选的项目,但是当项目更多时,网格被滚动,之后我没有得到我选择的项目

我已经发现滚动网格时x和y位置会发生变化 我可能错了

请帮助

1 个答案:

答案 0 :(得分:1)

我认为在触摸位置检测的问题方式中建议可能无效,因为有更多的高级方法来获取滚动位置。

实施的主要思路如下:

  1. 使用onScrollChanged()随时跟踪滚动位置;
  2. 将选择显示为GridView;
  3. 上方的单独视图
  4. 跟踪所选项目是否可见(使用this question);
  5. 因此,要获得正确的滚动回调,需要稍微定制GridView

    public class ScrollAwareGridView extends GridView {
    
        /** Callback interface to report immediate scroll changes */
        public interface ImmediateScrollListener {
            void onImmediateScrollChanged();
        }
    
        /** External listener for  */
        private ImmediateScrollListener mScrollListener = null;
    
        public ScrollAwareGridView(final Context context) {
            super(context);
        }
    
        public ScrollAwareGridView(final Context context, final AttributeSet attrs) {
            super(context, attrs);
        }
    
        public ScrollAwareGridView(final Context context, final AttributeSet attrs, final int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
    
            if (null != mScrollListener) {
                mScrollListener.onImmediateScrollChanged();
            }
        }
    
        /**
         * @param listener {@link ImmediateScrollListener}
         */
        public void setImmediateScrollListener(final ImmediateScrollListener listener) {
            mScrollListener = listener;
        }
    }
    

    它将按以下方式放置在xml中(main.xml):

    <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
        <com.example.TestApp.ScrollAwareGridView
            android:id="@+id/grid"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:numColumns="3" />
    
        <!-- Selection view -->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/selectedImage"
            android:visibility="gone" />
    </RelativeLayout>
    

    在上面的xml中还有选择视图。

    Activity将处理项目的选择(但是,为了不在Activity代码中保留特定于网格的逻辑,最好将选择和滚动跟踪逻辑保留在单独的对象(网格适配器或特定网格片段)中:

    public class MyActivity extends Activity implements ScrollAwareGridView.ImmediateScrollListener, AdapterView.OnItemClickListener {
    
        private static final String TAG = "MyActivity";
    
        /** To start / pause music */
        private ImageView mSelectedImage = null;
        /** position of selected item in the adapter */
        private int mSelectedPosition;
        /** Main grid view  */
        private ScrollAwareGridView mGrid;
        /** Adapter for grid view */
        private ImageAdapter mAdapter;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Show the layout with the test view
            setContentView(R.layout.main);
    
            mSelectedImage = (ImageView) findViewById(R.id.selectedImage);
    
            mGrid = (ScrollAwareGridView) findViewById(R.id.grid);
    
            if (null != mGrid) {
                mAdapter = new ImageAdapter(this);
    
                mGrid.setAdapter(mAdapter);
    
                mGrid.setImmediateScrollListener(this);
                mGrid.setOnItemClickListener(this);
            }
        }
    
        @Override
        protected void onPause() {
            super.onPause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            mSelectedImage.setImageBitmap(null);
            mSelectedImage.setVisibility(View.GONE);
            mSelectedPosition = -1;
        }
    
        @Override
        public void onImmediateScrollChanged() {
            if (mSelectedPosition >= 0) {
                int firstPosition = mGrid.getFirstVisiblePosition(); // This is the same as child #0
                int wantedChild = mSelectedPosition - firstPosition;
    
                // Say, first visible position is 8, you want position 10, wantedChild will now be 2
                // So that means your view is child #2 in the ViewGroup:
                if (wantedChild < 0 || wantedChild >= mGrid.getChildCount()) {
                    Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
                    mSelectedImage.setVisibility(View.INVISIBLE);
                    return;
                } else {
                    mSelectedImage.setVisibility(View.VISIBLE);
                }
    
                // Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
                final View selectedView = mGrid.getChildAt(wantedChild);
    
                if (null != selectedView && mSelectedImage.getVisibility() == View.VISIBLE) {
                    // Put selected view on new position
                    final ViewGroup.MarginLayoutParams zoomedImageLayoutParams = (ViewGroup.MarginLayoutParams) mSelectedImage.getLayoutParams();
    
                    // 200 is difference between zoomed and not zoomed images dimensions
                    // TODO: Avoid hardcoded values and use resources
                    final Integer thumbnailX = mGrid.getLeft() + selectedView.getLeft() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
                    final Integer thumbnailY = mGrid.getTop() + selectedView.getTop() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
    
                    zoomedImageLayoutParams.setMargins(thumbnailX,
                            thumbnailY,
                            0,
                            0);
    
                    mSelectedImage.setLayoutParams(zoomedImageLayoutParams);
                }
            }
        }
    
        @Override
        public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
            mSelectedPosition = position;
    
            final Bitmap bm = mAdapter.getImage(position);
    
            // Obtain image from adapter, with check if image presented
            if (bm != null) {
                final ViewGroup.MarginLayoutParams zoomedImageLayoutParams = (ViewGroup.MarginLayoutParams) mSelectedImage.getLayoutParams();
    
                // 200 is difference between zoomed and not zoomed images dimensions
                // TODO: Avoid hardcoded values and use resources
                final Integer thumbnailX = mGrid.getLeft() + view.getLeft() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
                final Integer thumbnailY = mGrid.getTop() + view.getTop() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
    
                zoomedImageLayoutParams.setMargins(thumbnailX,
                        thumbnailY,
                        0,
                        0);
                zoomedImageLayoutParams.height = ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION;
                zoomedImageLayoutParams.width = ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION;
    
                mSelectedImage.setImageBitmap(bm);
                mSelectedImage.setScaleType(ImageView.ScaleType.CENTER);
                mSelectedImage.setLayoutParams(zoomedImageLayoutParams);
                mSelectedImage.setVisibility(View.VISIBLE);
            }
        }
    }
    

    以下是GridView适配器。然而,其中没有任何与滚动跟踪有关的特定内容(我从this answer重用了大部分代码):

    public class ImageAdapter extends BaseAdapter {
    
        private static final String TAG = "ImageAdapter";
        /** For creation of child ImageViews */
        private Context mContext;
    
        public static final Integer[] IMAGES_RESOURCES = {
            R.drawable.image001, R.drawable.image002, R.drawable.image003, R.drawable.image004,
            R.drawable.image005, R.drawable.image006, R.drawable.image007, R.drawable.image008,
            R.drawable.image009, R.drawable.image010, R.drawable.image011, R.drawable.image012,
            R.drawable.image013, R.drawable.image014, R.drawable.image015, R.drawable.image016,
            R.drawable.image017, R.drawable.image018, R.drawable.image019, R.drawable.image020,
            R.drawable.image021, R.drawable.image022, R.drawable.image023, R.drawable.image024,
            R.drawable.image025, R.drawable.image026, R.drawable.image027, R.drawable.image028,
            R.drawable.image029, R.drawable.image030, R.drawable.image031, R.drawable.image032,
            R.drawable.image033, R.drawable.image034, R.drawable.image035, R.drawable.image036,
            R.drawable.image037, R.drawable.image038, R.drawable.image039, R.drawable.image040,
            R.drawable.image041, R.drawable.image042, R.drawable.image043, R.drawable.image044,
            R.drawable.image045, R.drawable.image046, R.drawable.image047, R.drawable.image048,
            R.drawable.image049, R.drawable.image050
        };
    
        // TODO: use resources for that sizes, otherwise You'll GET PROBLEMS on other displays!
        public final static int GRID_ITEM_DIMENSION = 300;
        public final static int HIGHLIGHTED_GRID_ITEM_DIMENSION = 500;
    
        private Bitmap mHolder = null;
        private static final int CACHE_SIZE = 50 * 1024 * 1024; // 8 MiB cache
        /** Cache to store all decoded images */
        private LruCache<Integer, Bitmap> mBitmapsCache = new LruCache<Integer, Bitmap>(CACHE_SIZE) {
    
            @Override
            protected int sizeOf(final Integer key, final Bitmap value) {
                return value.getByteCount();
            }
    
            @Override
            protected void entryRemoved(final boolean evicted, final Integer key, final Bitmap oldValue, final Bitmap newValue) {
                if (!oldValue.equals(mHolder)) {
                    oldValue.recycle();
                }
            }
        };
    
        // Constructor
        public ImageAdapter(Context c){
            mContext = c;
            mHolder = BitmapFactory.decodeResource(c.getResources(), R.drawable.ic_launcher, null);
        }
    
        @Override
        public int getCount() {
            return IMAGES_RESOURCES.length;
        }
    
        @Override
        public Object getItem(int position) {
            return IMAGES_RESOURCES[position];
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView;
    
            if (convertView == null) {
                imageView = new ImageView(mContext);
    
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setLayoutParams(new GridView.LayoutParams(GRID_ITEM_DIMENSION, GRID_ITEM_DIMENSION));
            } else {
                imageView = (ImageView) convertView;
            }
    
            final Bitmap itemBitmap = mBitmapsCache.get(IMAGES_RESOURCES[position]);
    
            if (itemBitmap == null || itemBitmap.isRecycled()) {
                Log.e(TAG, position + " is missed, launch decode for " + IMAGES_RESOURCES[position]);
                imageView.setImageBitmap(mHolder);
                mBitmapsCache.put(IMAGES_RESOURCES[position], mHolder);
                new BitmapWorkerTask(mBitmapsCache, mContext.getResources(), this).execute(IMAGES_RESOURCES[position]);
            } else {
                Log.e(TAG, position + " is here for " + IMAGES_RESOURCES[position]);
                imageView.setImageBitmap(itemBitmap);
            }
    
            return imageView;
        }
    
        /**
         * Obtains image at position (if there's only holder, then null to be returned)
         *
         * @param position int position in the adapter
         *
         * @return {@link Bitmap} image at position or null if image is not loaded yet
         */
        public Bitmap getImage(final int position) {
    
            final Bitmap bm = mBitmapsCache.get(IMAGES_RESOURCES[position]);
    
            return ((mHolder.equals(bm) || bm == null) ? null : bm.copy(Bitmap.Config.ARGB_8888, false));
        }
    
        /** AsyncTask for decoding images from resources */
        static class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
            private int data = 0;
            private final LruCache<Integer, Bitmap> mCache;
            private final Resources mRes;
            private final BaseAdapter mAdapter;
    
            public BitmapWorkerTask(LruCache<Integer, Bitmap> cache, Resources res, BaseAdapter adapter) {
                // nothing to do here
                mCache = cache;
                mRes = res;
                mAdapter = adapter;
            }
    
            // Decode image in background.
            @Override
            protected Bitmap doInBackground(Integer... params) {
                data = params[0];
                // Use sizes for selected bitmaps for good up-scaling
                return decodeSampledBitmapFromResource(mRes, data, GRID_ITEM_DIMENSION, GRID_ITEM_DIMENSION);
            }
    
            // Once complete, see if ImageView is still around and set bitmap.
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                mCache.put(data, bitmap);
                mAdapter.notifyDataSetChanged();
            }
        }
    
        public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                             int reqWidth, int reqHeight) {
    
            // First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(res, resId, options);
    
            // Calculate inSampleSize
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            options.outHeight = GRID_ITEM_DIMENSION;
            options.outWidth = GRID_ITEM_DIMENSION;
            return BitmapFactory.decodeResource(res, resId, options);
        }
    
        public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
            // Raw height and width of image
            final int height = options.outHeight;
            final int width = options.outWidth;
            int inSampleSize = 1;
    
            if (height > reqHeight || width > reqWidth) {
    
                // Calculate ratios of height and width to requested height and width
                final int heightRatio = Math.round((float) height / (float) reqHeight);
                final int widthRatio = Math.round((float) width / (float) reqWidth);
    
                // Choose the smallest ratio as inSampleSize value, this will guarantee
                // a final image with both dimensions larger than or equal to the
                // requested height and width.
                inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
            }
    
            return inSampleSize;
        }
    }