Android 对于按钮的GridView,无法识别onFling手势

Android 对于按钮的GridView,无法识别onFling手势,android,gridview,android-gesture,gesturedetector,gesturelistener,Android,Gridview,Android Gesture,Gesturedetector,Gesturelistener,基于以下代码片段,我想知道为什么在GridView按钮中不能识别onFling手势(出于个人原因,我使用按钮而不是其他视图): 以下是我的主要活动: public class MainActivity extends AppCompatActivity { private GridView grid; GestureDetector gDetector; private static final int SWIPE_MIN_DISTANCE = 120; pri

基于以下代码片段,我想知道为什么在GridView按钮中不能识别onFling手势(出于个人原因,我使用按钮而不是其他视图):

以下是我的主要活动:

public class MainActivity extends AppCompatActivity {
    private GridView grid;
    GestureDetector gDetector;

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

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

        grid = (GridView)findViewById(R.id.grid);

        // 4X4 grid.
        grid.setNumColumns(4);

        ArrayList<Button> mButtons = new ArrayList<Button>();
        Button button = null;

        for (int i = 0; i < 16; i++) {
            button = new Button(this);
            button.setText(i + "");
            mButtons.add(button);
        }

        grid.setAdapter(new CustomAdapter(this, mButtons));

        gDetector = new GestureDetector(this, new SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent event) {
                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                               float velocityY) {
                final int position = grid.pointToPosition(Math.round(e1.getX()), Math.round(e1.getY()));

                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
                    if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH
                        || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
                        return false;
                    }
                    if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(MainActivity.this, "top at index " + position, Toast.LENGTH_SHORT).show();
                    } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(MainActivity.this, "bottom at index " + position, Toast.LENGTH_SHORT).show();
                    }
                } else {
                    if (Math.abs(velocityX) < SWIPE_THRESHOLD_VELOCITY) {
                        return false;
                    }
                    if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(MainActivity.this, "left at index " + position, Toast.LENGTH_SHORT).show();
                    } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(MainActivity.this, "right at index " + position, Toast.LENGTH_SHORT).show();
                    }
                }

                return super.onFling(e1, e2, velocityX, velocityY);
            }
        });
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return gDetector.onTouchEvent(event);
}
public类MainActivity扩展了AppCompatActivity{
私有网格视图;
手势检测器;
专用静态最终整数滑动距离=120;
专用静态最终整数滑动路径=250;
专用静态最终整数滑动\u阈值\u速度=200;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
grid=(GridView)findviewbyd(R.id.grid);
//4X4网格。
网格。setNumColumns(4);
ArrayList mButtons=新的ArrayList();
按钮=空;
对于(int i=0;i<16;i++){
按钮=新按钮(此按钮);
按钮。设置文本(i+“”);
mButtons.add(按钮);
}
setAdapter(新的CustomAdapter(this,mButtons));
gDetector=new GestureDetector(这是新的SimpleOnGestureListener()){
@凌驾
公共布尔onDown(运动事件){
返回true;
}
@凌驾
公共布尔onFling(运动事件e1、运动事件e2、浮点速度X、,
浮动速度y){
final int position=grid.pointToPosition(Math.round(e1.getX()),Math.round(e1.getY());
if(Math.abs(e1.getY()-e2.getY())>swip\u MAX\u OFF\u路径){
if(Math.abs(e1.getX()-e2.getX())>刷离路径
||Math.abs(速度y)滑动最小距离){
Toast.makeText(MainActivity.this,“索引顶部”+位置,Toast.LENGTH_SHORT.show();
}else if(e2.getY()-e1.getY()>滑动最小距离){
Toast.makeText(MainActivity.this,“索引底部”+位置,Toast.LENGTH_SHORT).show();
}
}否则{
if(数学abs(速度x)<滑动阈值\u速度){
返回false;
}
if(e1.getX()-e2.getX()>滑动最小距离){
Toast.makeText(MainActivity.this,“左索引”+位置,Toast.LENGTH_SHORT).show();
}else if(e2.getX()-e1.getX()>滑动最小距离){
Toast.makeText(MainActivity.this,“位于索引右侧”+位置,Toast.LENGTH_SHORT).show();
}
}
返回super.onFling(e1、e2、velocityX、velocityY);
}
});
}
@凌驾
公共布尔onTouchEvent(运动事件){
返回gDetector.onTouchEvent(事件);
}
…这是我的CustomAdapter:

public class CustomAdapter extends BaseAdapter {
    private ArrayList<Button> mButtons = null;
    private Context ctx;

    public CustomAdapter(Context ctx, ArrayList<Button> button) {
        this.ctx = ctx;
        this.mButtons = button;
    }

    @Override
    public int getCount() {
        return mButtons.size();
    }

    @Override
    public Object getItem(int position) {return (Object) mButtons.get(position);}

    @Override
    public long getItemId(int position) {

        // Position and id are synonymous.
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Button button;

        // Assigns a view to convertView should it be null, otherwise, casts convertView to the
        // correct View type.
        if (convertView == null) {
            button = mButtons.get(position);
        } else {
            button = (Button) convertView;
        }

        return button;
    }
}
公共类CustomAdapter扩展了BaseAdapter{
私有数组列表mButtons=null;
私有上下文ctx;
公共CustomAdapter(上下文ctx、ArrayList按钮){
this.ctx=ctx;
this.mButtons=按钮;
}
@凌驾
public int getCount(){
返回mButtons.size();
}
@凌驾
公共对象getItem(int位置){return(Object)mButtons.get(position);}
@凌驾
公共长getItemId(int位置){
//位置和id是同义词。
返回位置;
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
按钮;
//为convertView指定一个视图,如果该视图为空,则将convertView强制转换为
//正确的视图类型。
if(convertView==null){
按钮=mButtons.get(位置);
}否则{
按钮=(按钮)转换视图;
}
返回按钮;
}
}
…显然,当GridView设置为wrap_内容时,滑动onFling只会在屏幕的下半部分被识别,而当GridView设置为与父项匹配时,滑动根本不起作用。下面是在wrap_内容时的网格集,滑动只在封闭的正方形中起作用,如下所示:


非常感谢。

由于按钮在到达活动的
onTouchEvent()
之前已经消耗了触摸事件,手势检测器从未通过按钮接收事件。您可能需要覆盖按钮的父视图类,例如
GridView
,以拦截触摸事件

下面是一个类
GestureDetectGridView
的示例,它扩展了
GridView

public class GestureDetectGridView extends GridView {
    private GestureDetector gDetector;
    private boolean flingConfirmed = false;
    private float mTouchX;
    private float mTouchY;

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

    // Boiler plate view constructors
    public GestureDetectGridView(Context context) {
        super(context);
        init(context);
    }

    public GestureDetectGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public GestureDetectGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @TargetApi(21)
    public GestureDetectGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    // Sets up gesture detector, moved from your original MainActivity

    private void init(final Context context) {
        gDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent event) {
                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                                   float velocityY) {
                final int position = GestureDetectGridView.this.pointToPosition(Math.round(e1.getX()), Math.round(e1.getY()));

                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
                    if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH
                            || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
                        return false;
                    }
                    if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(context, "top at index " + position, Toast.LENGTH_SHORT).show();
                    } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(context, "bottom at index " + position, Toast.LENGTH_SHORT).show();
                    }
                } else {
                    if (Math.abs(velocityX) < SWIPE_THRESHOLD_VELOCITY) {
                        return false;
                    }
                    if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(context, "left at index " + position, Toast.LENGTH_SHORT).show();
                    } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) {
                        Toast.makeText(context, "right at index " + position, Toast.LENGTH_SHORT).show();
                    }
                }
                return super.onFling(e1, e2, velocityX, velocityY);
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        gDetector.onTouchEvent(ev);
        // Determine whether we need to start intercepting all touch events
        // such that the buttons would no longer receive further touch events
        // Return true if the fling gesture is confirmed
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            flingConfirmed = false;
        } else if (action == MotionEvent.ACTION_DOWN) {
            mTouchX = ev.getX();
            mTouchY = ev.getY();
        } else {
            // short cut just in case
            if (flingConfirmed) {
                return true;
            }
            float dX = (Math.abs(ev.getX() - mTouchX));
            float dY = (Math.abs(ev.getY() - mTouchY));
            if ((dX > SWIPE_MIN_DISTANCE) || (dY > SWIPE_MIN_DISTANCE)) {
                flingConfirmed = true;
                return true;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return gDetector.onTouchEvent(ev);
    }

}
公共类GestureDetectGridView扩展GridView{
私人手势检测器;
私有布尔值flingConfirmed=false;
私人浮动mTouchX;
私人浮动mTouchY;
专用静态最终整数滑动距离=120;
专用静态最终整数滑动路径=250;
专用静态最终整数滑动\u阈值\u速度=200;
//锅炉板视图构造函数
public GestureDetectGridView(上下文){
超级(上下文);
init(上下文);
}
public GestureDetectGridView(上下文、属性集属性){
超级(上下文,attrs);
init(上下文);
}
public GestureDetectGridView(上下文上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
init(上下文);
}
@塔吉塔皮(21)
public GestureDetectGridView(上下文上下文、属性集属性、int-defStyleAttr、int-defStyleRes){
super(context、attrs、defStyleAttr、defStyleRes);
init(上下文);
}
//设置手势检测器,从原始主活动移动
私有void init(最终上下文){
GD检测器=