GridView with a baseAdapter: onItemClick giving wrong position
I have a weird problem with GridView. The
onItemClick(AdapterView parent, View v, int position, long id)
method is giving wrong position sometimes. The code i have:
public class ImageAdapter extends BaseAdapter {
......
}
gridview = (Gri开发者_运维问答dView) findViewById(R.id.gridview);
image_adapter = new ImageAdapter(this);
gridview.setAdapter(image_adapter);
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Log.e(TAG, "position = "+position);
}
}
My gridView is 3X3 grid and Image adapter has 9 piece on images. Based on what grid position user selects, the image pieces get shuffled.
This works fine if selecting grid position is done slowly. But if user keeps on tapping very quickly on any particular position, the "position" parameter in onItemClick method gets arbitrarily changed. Suppose my grid is
0 1 2
3 4 5
6 7 8
and user keeps on tapping at a quick pace on position 5, sometimes the "position" parameter in onItemClick reads 0 or 6.
Any idea what is the reason for this and what could be the solution?
I've got the same trouble in my project - maybe it will helps you.
You probably have an implementation of onTouchEvent in your Activity. Make it something like this:
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();//probably Click
return false;
case MotionEvent.ACTION_UP:
float currentX = event.getX();
if (this.startX-MOVE_DENSITY > currentX) {
//fling right
return true;
}
if (this.startX+MOVE_DENSITY < currentX) {
//fling left
return true;
}
default:
return false;
}
}
It's very important a returned value!!! You must have an field double startX in your class, and constant MOVE_DENSITY, which means density to detect fling move (in my case I set it to 50). Maybe not nice explanation, but my English is not well)) Hope it helps you!
Had the same issue, the following solved the issue:
grid.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
int position = i - grid.getNumColumns();
}
});
I am using HeaderGridView class: https://android.googlesource.com/platform/packages/apps/Gallery2/+/idea133/src/com/android/photos/views/HeaderGridView.java
Instead of OnItemClickListener
you would be better of using OnItemSelectedListener
I had a problem like this one. I don't know if you set gridview.setEnabled
true
and false
, but I did. If the user taps the item like crazy just before and under the gridview.setEnabled triggers, the gridview will sometimes get you the wrong position.
To solve this I made a transparent RelativeLayout
on top of the gridview which I set to gone and visible. The RelativeLayout must be android:clickable="true"
.
Based on Viacheslav's answer, I made some modification.
In my own class (Customized GridView):
public class CustomGridView extends GridView {
private int position = -1;
private float xCoor, yCoor;
private Context context;
private Drawable defaultDrawable;
//Constructors - Skipped
public void setInitPosition(int position, float x, float y) {
this.position = position;
this.xCoor = x;
this.yCoor = y;
defaultDrawable = this.getChildAt(position - this.getFirstVisiblePosition()).getBackground();
this.getChildAt(position - this.getFirstVisiblePosition()).setBackgroundColor(Color.RED/*For Example*/));
}
@Override
public boolean performClick() {
return super.performClick();
}
public int getInitialPosition() {
if(position != -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
this.getChildAt(position - this.getFirstVisiblePosition()).setBackground(defaultDrawable);
} else {
this.getChildAt(position - this.getFirstVisiblePosition()).setBackgroundColor(context.getResources().getColor(R.color.grid_selection_item_background));
}
}
return position;
}
public float xCoor() {
return xCoor;
}
public float yCoor() {
return yCoor;
}
}
In your onTouchListener:
CustomGridView gridView;
...
@Override
public boolean onTouch(View v, MotionEvent event) {
v.performClick();
int action = event.getActionMasked();
float xPosition = event.getX();
float yPosition = event.getY();
int position = listView.pointToPosition((int) xPosition, (int) yPosition);
if(position != AbsListView.INVALID_POSITION) {
if(action == MotionEvent.ACTION_DOWN) {
gridView.setInitialPosition(position, xPosition, yPosition);
}
if(action == MotionEvent.ACTION_UP) {
int checkedPosition = gridView.getInitialPosition();
if(checkedPosition == position) {
if(Math.abs(yPosition - gridView.yCoor()) < 10/*Your fling "density"*/) {
doYourAction(position);
}
}
}
}
return detector.onTouchEvent(event);
}
The position in the onTouch Callback, is the position of item in the gridView, not view Position. View position have to deducted with gridView.getFirstVisiblePosition()
精彩评论