? Android 扩大 View 的点击区域_蜘蛛资讯网 亚博APP体育官网下载路线⑧⑧,亚博APP体育官网下载路线⑧⑧,亚博娱乐在线登录平台
首页 > 调查 > 正文

汉中市拥秆汹有限公司_Android 扩大 View 的点击区域

有时候,按照视觉图做出来效果后,发现点击区域过小,不好点击,用户体验肯定不好。扩大视图,就会导致整个视觉图变得不好看。那么有没有什么办法在不改变视图大小的前提下扩大点击区域呢?

答案是有!

能够解决这个问题的前提你要对 View 的事件分发机制有一定的了解。

neng gou jie jue zhe ge wen ti de qian ti ni yao dui View de shi jian fen fa ji zhi you yi ding de liao jie.

下面我将简单介绍一下View 的事件分发机制,方便大家理解后面的解决办法。

为了更清楚的说明整个机制,采用如下的视图来说明点击的事件分发机制。下图是一个 FrameLayout (ViewGroup) 里面包含着一个 ImageView (View)。

先自定义一个?MyFrameLayout,继承FrameLayout,并实现两个点击相关的接口;具体代码如下:

public class MyFrameLayout extends FrameLayout implements OnClickListener, OnTouchListener {

    private static final String TAG = "Event";

    public MyFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.d(TAG, "MyFrameLayout init");
        setOnClickListener(this);
        setOnTouchListener(this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "MyFrameLayout dispatchTouchEvent " + event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "MyFrameLayout onTouchEvent " + event.getAction() );
        return super.onTouchEvent(event);
    }

    @Override
    public void onClick(View view) {
        Log.d(TAG, "MyFrameLayout onClick");
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        Log.d(TAG, "MyFrameLayout onTouch " + event.getAction());
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG, "MyFrameLayout onInterceptTouchEvent " + ev.getAction());

        return super.onInterceptTouchEvent(ev);
    }
}

接着,对于 ImageView 也做类似的操作,具体代码如下:

public class MyImageView extends ImageView implements OnClickListener, OnTouchListener {
    private static final String TAG = "Event";

    public MyImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.d(TAG, "MyImageView init");
        setOnClickListener(this);
        setOnTouchListener(this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "MyImageView dispatchTouchEvent  "+ event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "MyImageView onTouchEvent "+ event.getAction());
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onTouch(View arg0, MotionEvent arg1) {
        Log.d(TAG, "MyImageView onTouch " + arg1.getAction());
        return false;
    }

    @Override
    public void onClick(View arg0) {
        Log.d(TAG, "MyImageView onClick");
    }
}

这里要说明的是,只有ViewGroup才有?onInterceptTouchEvent 方法的,普通的 View 是没有的,它是不能对事件进行拦截的。

那这时候,如果我们点击里面的 ImageView,会有怎样的输出呢?结果如下图。

那如果点击外层呢?

0,1,2分别是代表?ACTION_DOWN,ACTION_UP,ACTION_MOVE;从中也可以看出一个点击动作包含一个Down,一个Up,还有多个Move操作。

再来看一段源码:

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume = false;
    if(onInterceptTouchEvent(ev)){
        consume = onTouchEvent(ev);
    } else{
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

上述的代码把三者的关系说得很清楚了,对于一个对于一个 ViewGroup 来说,点击事件产生后,首先会传递给它,这时候会调用 dispatchTouchEvent,如果这个?ViewGroup 的?onInterceptTouchEvent 返回 true ,则表示它要拦截该事件,也就会交给它的?onTouchEvent 来进行处理。如果这个?ViewGroup 的?onInterceptTouchEvent 返回 false 则会传给子元素,子元素的?dispatchTouchEvent 就会被调用,如此反复循环。这与上面一张图打出的结果是一致的。

这里还有说明的是,如果代码设置了?OnTouchListener,那么就会先调用?onTouch 方法,然后在调用?onTouchEvent。OnClickListener 是优先级最低的,所以最后才会调用?onClick。

因此,从第二张结果图也可以看出,当存在 onTouch 之后,onTouchEvent 和?onClick 两个方法都不会在调用了。

相信到这里,大家对于View的事件分发机制有一定的了解了。

这里回到开头提的那个问题,那么有什么办法可以扩大 View 的点击区域呢?

答案:在父 View 设置 OnTouchListener 对点击事件进行拦截,通过判断点击的位置,来决定是相应子 View 的事件,还是父 View 的事件。

具体实现代码如下:

public class TouchFactory {

    /** 扩展垂直方向点击区域尺寸 */
    private static final int EXT_V_SIZE = 200;

    public static View.OnTouchListener creatTouchListener(){
        return new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (expendTouchSize(v, event)) {
                    return true;
                }
                return false;
            }
        };
    }

    public static boolean expendTouchSize(View root, MotionEvent event) {
        if (root instanceof MyFrameLayout) {
            ImageView view = ((MyFrameLayout) root).getMyImageView();
            if (view != null && view.getVisibility() == View.VISIBLE) {
                Rect touchRect = new Rect();
                view.getGlobalVisibleRect(touchRect);

                int action = event.getAction();
                float x = event.getRawX();
                float y = event.getRawY();

                if ((y >= touchRect.top - EXT_V_SIZE) && (y <= touchRect.bottom + EXT_V_SIZE)) {
                    if (x >= touchRect.left) {
                        if (action == MotionEvent.ACTION_UP) {
                            Toast.makeText(view.getContext(), "touch", Toast.LENGTH_SHORT).show();
                        }
                        return true;
                    }
                }
            }
        }

        return false;
    }
}

TouchFactory 对点击事件进行了封装,并通过对点击区域的判断,来决定要不要拦截点击事件。

下面是?MyFrameLayout 的具体实现。由于是一个自定义 view, 因此,变量?myImageView 是一定为空的,所以要对其进行赋值。

public class MyFrameLayout extends FrameLayout {

    private static final String TAG = "Event";

    private MyImageView myImageView;

    public MyFrameLayout(Context context) {
        this(context, null);
    }

    public MyFrameLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyFrameLayout(Context context, AttributeSet attrs, int def) {
        super(context, attrs, def);
        init();
    }

    public void init() {
        this.setOnTouchListener(TouchFactory.creatTouchListener());
    }
    
    public MyImageView getMyImageView() {
        if (myImageView == null) {
            myImageView = findViewById(R.id.mImage);
        }
        return myImageView;
    }
}

注意事项:当对子 View 设置?OnClickListener,点击区域刚好是子 View 内部的时候,就会消耗此事见,父 View 的拦截处理就无效了,因此,一旦选择拦截来扩大点击区域,就不要再去子 View 设置点击回调来消耗点击事件了。

当前文章:http://www.vmc-ahm.com/6jebsrmd/62147-1297178-65383.html

发布时间:19:44:35

天下彩本港台开奖直播??水果奶奶主论坛??今期家婆玄机彩图今晚??马会开开奖结果??香港正版挂牌规律??神算子??www.10889A.com??黄大仙六合心水论坛??白小姐开奖??天下彩合全年资料大全??

[责任编辑: 卓密安海]

评论

?
[ 【国际锐评】美国智库:美国有可能成为“超级流氓大国” ]? [ 三星二季度营业利润率首超苹果,居全球第一 ]? [ 澳洲进口/肉质细嫩,如康旗舰店谷饲精品牛腩块1kg装39.9元(20元券) ]? [ 奥克斯董事长:欢迎监督 共同营造民族品牌质量声誉 ]? [ 德国等5国当选联合国安理会非常任理事国 明年元旦开始任期 ]? [ 《风暴英雄》未来更新早制造: 优化匹配机制 ]

?
  • 关于我们 | 蜘蛛资讯网 版权所有

    Copyright ? 2019 蜘蛛资讯网 All Rights Reserved