我有一个网格视图我在其中动态添加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位置会发生变化 我可能错了
请帮助
答案 0 :(得分:1)
我认为在触摸位置检测的问题方式中建议可能无效,因为有更多的高级方法来获取滚动位置。
实施的主要思路如下:
GridView
; 因此,要获得正确的滚动回调,需要稍微定制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;
}
}