开发者

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()

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜