Android View touch事件传递方式规律

上一篇给出了测试工程程序,下面要给每一层的Button添加click事件处理.

这里需要以DurianSubFrameLayout这一层进行,因为这一层刚好是一个中间层,可谓"上有老下有小"


DurianSubFrameLayout.java的代码调整一下:

/**  
 * @Title: DurianSubFrameLayout.java
 * @Package com.durian.view
 * @Description: TODO
 * @author zhibao.liu from durian organization
 * @date 2015-12-22 下午02:47:13
 * @version V1.0  
 */
package com.durian.view;

import com.durian.viewgroup.R;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

/**
 * @ClassName: DurianSubFrameLayout
 * @Description: TODO
 * @author zhibao.liu Freelancer
 * @email [email protected]
 * @date 2015-12-22 下午02:47:13
 * 
 */
public class DurianSubFrameLayout extends FrameLayout {

    private final static String TAG = "DurianSubFrameLayout";
    private int mDisplayWidth = 1200;
    private int mDisplayHeight = 1824;

    private Button mButton;
    
    private Context mContext;

    private DurianSubLinearLayout mDurianSubLinearLayout;

    public DurianSubFrameLayout(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    public DurianSubFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    public DurianSubFrameLayout(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    private void initView(Context context) {

        mContext=context;
        
        mButton = new Button(context);
        mButton.setText("Second SubFrameLayout Button");
        mButton.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(mContext, TAG+" button !", Toast.LENGTH_SHORT).show();
                Log.i(TAG,"Third SubFrameLayout button click");
            }
            
        });
        addView(mButton);

        mDurianSubLinearLayout = new DurianSubLinearLayout(context);
        addView(mDurianSubLinearLayout);

        setBackgroundDrawable(context.getResources().getDrawable(
                R.drawable.alpha_background));

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        Log.i(TAG, TAG+ " onTouchEvent");
        return super.onTouchEvent(event);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        // TODO Auto-generated method stub
        super.onLayout(changed, left, top, right, bottom);
        for (int i = 0; i < getChildCount(); i++) {

            Log.i(TAG, "*** count i : " + i);
            View child = getChildAt(i);

            if (child instanceof Button) {
                child.layout(mDisplayWidth / 2 - 250, i * mDisplayHeight / 12,
                        mDisplayWidth / 2 + 250, (i + 1) * mDisplayHeight / 12);
            } else {
                child.layout(0, i * mDisplayHeight / 12, mDisplayWidth, (i + 1)
                        * mDisplayHeight / 6);
            }

        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(mDisplayWidth, mDisplayHeight / 4);
    }

}
首先不分析程序,先给出我分析的结论,然后再看程序验证,如果有错误还请修正,非常感谢

Android View touch事件传递方式规律_第1张图片


下面用一个表格大致显示如下:

Android View touch事件传递方式规律_第2张图片

好了现在我在DurianSubFrameLayout.java容器中,修改dispatchTouchEvent方法的返回值:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return true;//super.dispatchTouchEvent(ev);
    }

运行程序,多次点击:


从上面看没有onTouch的报文出来,可想而知,事件在进入这个容器时被阻止,那么这个容器的子容器的touch事件也不会响应了.

然后将上面同样设置成返回false,效果和上面一样

然后将上面恢复,并且设置返回true:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return true;//super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        Log.i(TAG, TAG+ " onTouchEvent");
        return super.onTouchEvent(event);
    }

运行查看log :

Android View touch事件传递方式规律_第3张图片

会发现这个容器消费了touch事件,那么意味着什么呢?这个容器里面的子Button和下一级子布局容器均在不会相应touch事件了.所以点击button和自布局里面的button都不会有响应,但是这个容器的touch事件是可以响应的.

在修改一下:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        return false;//super.onInterceptTouchEvent(ev);
    }

运行结果,并且点击当前布局和下一级自布局:

sublinear是下一级的子布局log信息.

Android View touch事件传递方式规律_第4张图片


综合上述,可以发现结论基本上是正确的,但是有一个地方需要注意,

@Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        Log.i(TAG, TAG+ " onTouchEvent");
        return super.onTouchEvent(event);
    }

在这个里面,无论返回true 还是 false,里面的log都会执行,也就是说onTouchEvent里面的程序一定会执行.返回true还是false只是针对事件传递的,是对下一级的约束,不会因为这个地方返回true或者false导致里面程序不执行.但是一般很多情况下如果这个里面有自己的程序,我们一般会自己在自己程序后面增加一行return true,为了防止下一级的touch事件导致UI显示混乱.


对于其他的按键KeyEvent事件也是类似的,所以如果你的主容器由多层layout叠加,比如3层,那么希望触摸的时候,相应的是第二次或者第三层,那么根据上面的结论,开发人员应该知道如何调整事件传递路线,从而达到第二层或者第三层去相应Event事件.

















你可能感兴趣的:(Android View touch事件传递方式规律)