2015/9/8-5

Android事件传递机制(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)

Android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。

View即普通的控件,没有子布局的,如Button、TextView.

ViewGroup继承自View,表示可以有子控件,如Linearlayout、Listview这些。

事件即MotionEvent,最重要的有3个:

  • (1)MotionEvent.ACTION_DOWN 按下View,是所有事件的开始
  • (2)MotionEvent.ACTION_MOVE 滑动事件
  • (3)MotionEvent.ACTION_UP 与down对应,表示抬起

明确事件传递机制的最终目的都是为了触发执行View的点击监听和触摸监听:

******.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        Log.i(tag, "testLinelayout---onClick...");
    }
});

*******.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub

        return false;
    }
});

我们简称为onClick监听和onTouch监听,一般程序会注册这两个监听。从上面可以看到,onTouch监听里默认return false。不要小看了这个return false,后面可以看到它有大用。

对于View来说,事件传递机制有两个函数:dispatchTouchEvent负责分发事件,在dispatch*里又会调用onTouchEvent表示执行事件,或者说消费事件,

总结

1、事件入口是dispatchTouchEvent(),它会先执行注册的onTouch监听,如果一切顺利的话,接着执行onTouchEvent,在onTouchEvent里会执行onClick监听。

2、无论是dispatchTouchEvent还是onTouchEvent,如果返回true表示这个事件已经被消费、处理了,不再往下传了。在dispathTouchEvent的源码里可以看到,如果onTouchEvent返回了true,那么它也返回true。如果dispatch*在执行onTouch监听的时候,onTouch返回了true,那么它也返回true,这个事件提前被onTouch消费掉了。就不再执行onTouchEvent了,更别说onClick监听了。

3、我们通常在onTouch监听了设置图片一旦被触摸就改变它的背景、透明度之类的,这个onTouch表示事件的时机。而在onClick监听了去具体干某些事。

在自定义的View里面添加再设置一个外加View

再mianActivity中添加进来:

sideBar.setTextView(dialog);

在sideBar中再对他进行设置。

/**

 * 在mainActivity中吧TextView设置进来。
 * @param mTextDialog
 */
public void setTextView(TextView mTextDialog) {
    this.mTextDialog = mTextDialog;
}

在dispatchTouchEvent中对他进行监听和控制。

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    final int action = event.getAction();
    final float y = event.getY();// 点击y坐标
    final int oldChoose = choose;
    final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
    final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

    switch (action) {
    case MotionEvent.ACTION_UP:
        setBackgroundDrawable(new ColorDrawable(0x00000000));
        choose = -1;//
        invalidate();
        if (mTextDialog != null) {
            mTextDialog.setVisibility(View.INVISIBLE);
        }
        break;

    default:
        setBackgroundResource(R.drawable.sidebar_background);
        if (oldChoose != c) {
            if (c >= 0 && c < b.length) {
                if (listener != null) {
                    listener.onTouchingLetterChanged(b[c]);
                }
                if (mTextDialog != null) {
                    mTextDialog.setText(b[c]);
                    mTextDialog.setVisibility(View.VISIBLE);
                }

                choose = c;
                invalidate();
            }
        }

        break;
    }
    return true;
}

View.VISIBLE、INVISIBLE、GONE的区别

android中UI应用的开发中经常会使用view.setVisibility()来设置控件的可见性,其中该函数有3个可选值,他们有着不同的含义:

View.VISIBLE—->可见

View.INVISIBLE—->不可见,但这个View仍然会占用在xml文件中所分配的布局空间,不重新layout

View.GONE——>不可见,但这个View在ViewGroup中不保留位置,会重新layout,不再占用空间,那后面的view就会取代他的位置,

invalidate()函数

invalidate()函数的主要作用是请求View树进行重绘,该函数可以由应用程序调用,或者由系统函数间接调用,例如setEnable(), setSelected(), setVisiblity()都会间接调用到invalidate()来请求View树重绘,更新View树的显示。