3

我有一个网格视图,我在其中动态添加按钮。我将 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 位置正在发生变化我可能是错的

请帮忙

4

1 回答 1

1

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

实现的主要思路如下:

  1. 使用onScrollChanged()随时跟踪滚动位置;
  2. 将选择显示为上面的单独视图GridView
  3. 跟踪所选项目是否可见(使用此问题);

因此,要获得正确的滚动回调,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);
        }
    }
}

下面是GridViews适配器。但是,其中没有任何与滚动跟踪相关的具体内容(我从这个答案中重复使用的大部分代码):

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;
    }
}
于 2013-07-25T11:33:47.557 回答