目录:
1.事件分发机制是怎么样的?
2.View与ViewGroup的事件分发有什么区别
3.onTouch和onTouchevent和onClick的执行顺序?
4.如何理解消费?
5.Button和ImageView有什么不一样?
6.可以达到父控件和子空间同时点击吗?
7.ListView上的button,点击button2个控件同时要有相应,应该怎么处理?
点击事件被拦截,但是相传到下面的view,如何操作?
8.请简述Android事件传递机制, ACTION_CANCEL事件何时触发?
滑动冲突源码分析
滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?
11. 滑动冲突实践,实例: recleview嵌套recleview
1.事件分发机制是怎么样的?
1.1 事件分发机制分为2种:View事件的分发和ViewGroup事件分发机制
总结ViewGroup发现:dispathcTouchEvent开始-----disallownotIntercepter---onInterceptTouchEvent-----1.子类dispath() 2.父类TouchEvent方法
然后我们来看一下View中dispatchTouchEvent方法的源码:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
1.2 view总结: 整个View的事件转发流程是:(原理是dispatchTouchEvent)
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
1.3 完整的总结:
1). 事件分发机制是一种责任链模式, Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
2). 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
3). 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。
4). .在ViewGroup中onInterceptTouchEvent方法若反回false,那么触屏事件会继续向下传递,
但如果没有子View去处理这个事件,即子view的onTouchEvent没有返回True
则最后还是由ViewGroup去处理这个事件,也就又执行了自己的onTouchEvent。
备注: ViewGroup 类中,实际是没有onTouchEvent 方法的,但是由于ViewGroup 继承自View,
1.4 深层次的总结: (从InputChannel)
在attach()方法的时候,通过上面的流程图我们知道,当我们的PhoneWindow创建完成之后,我们也在该Window上注册了InputChannel并与IMS通信,
IMS把事件写入InputChannel,WindowInputEventReceiver对事件进行处理并最终还是通过InputChannel反馈给IMS。
InputChannel最重要的!!!!!!!!
总结:兜兜转转一大圈我们神经都被绕弯了,我们在这里总结一下,当我们触摸(点击)屏幕时,
Android输入系统IMS通过对事件的加工处理再合适的Window接收者并通过InputChannel向Window派发加工后的事件,
并触发InputReceiver的onInputEvent的调用,由此产生后面一系列的调用,把事件派发给整个控件树的根DecorView
而DecorView又上演了一出偷梁换柱的把戏,先把事件交给Activity处理,在Activity中又把事件交还给了我们的DecorView。自此沿着控件树自上向下依次派发事件。
2.View与ViewGroup的事件分发有什么区别
ViewGruop的事件分发:
多了一个拦截事件的方法:onInterceptTouchEvent
ViewGroup的dispathcTouchEvent方法:里面有onInterceptTouchEvent方法
3.onTouch和onTouchevent和onClick的执行顺序?
View.dispatchEvent----ontouch-----ontouchEvent(方法down,up,判断onclick时间)---onclick
//子控件的ontouch方法影响子控件的函数
//onTouch====onTouchEvent====onClick;
/**
* 检验view的事件分发顺序,点击---dispatch- Ontouch返回值为ture 不执行---ontouchEvent---onclick
*/
button1.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "button1 on touch"+event.getAction());
return true;
}
});
/**
* 检验view的事件分发顺序, 点击---dispatch- Ontouch返回值为false执行---ontouchEvent---onclick
*/
button2.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "button1 on touch" + event.getAction());
return false;
}
});
ontouch先执行,如果返回true,ontouchEvent,onClick都不执行
ontouch先执行,如果返回false,ontouchEvent,然后再是onclick方法
如果不重写onTouchListerner方法。
onTouchEvent如果返回true,不会执行onclick方法
onTouchEvent如果返回false,会执行onclick方法
onclick默认调用的是onTouchEvent。因为ontouch事件默认返回是false。那么就会响应onTochEvent。(onTouchEvent
总结:onTouch优先于onTouchEvent
1).看判断条件。如果没有mOnTouchListener ,ontouch不执行,onTouchEvent执行
2).如果有mOnTouchListener,并且onTouch =true,onTouchEvent不执行
- .如果有mOnTouchListener,并且onTouch =false,onTouchEvent执行
4.如何理解消费?view事件分发机制的案例
4.1 总结:
如果onTouch为true,代表消费了。不会执行onTouchevent了
如果子类的onTouchevent为true,代表消费了,父类不会执行onTouchevent
基本上就是返回true,就是消费了
4.2 案例说明
当一个Touch事件(触摸事件为例)到达根节点,即Acitivty的ViewGroup时,它会依次下发,下发的过程是调用子View(ViewGroup)的dispatchTouchEvent方法实现的。
简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViwGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。
上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。
dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,顺序下发会中断。
在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件
5.Button和ImageView有什么不一样?
Button和ImageView效果不一样:一个是自带点击,一个是要自己控制点击
onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,
那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
<wiz_code_mirror><pre class=" CodeMirror-line " role="presentation">/*ImageView默认是不能点击事件的,要想点击的话必须手动设置/</pre>
/**ImageView默认是不能点击事件的,要想点击的话必须手动设置*/
imageView.setClickable(true);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("TAG","imageView setOnTouchListener");
}
});
6.可以达到父控件和子空间同时点击吗?
如下
7.ListView上的button,点击button2个控件同时要有相应,应该怎么处理?
7.1 具体方案:在listView的OnInterceptTouchEvent()方法里面。判断区域。是否拦截
在listView的空白区域:执行listview的onTouchEvent方法。拦截button
在button的点击区域: 不拦截,消费button的onTouchEvent事件。
当父控件是布局而子控件是控件时,如果要设置点击效果,可以在父布局里面加上android:clickable="true" ,在子控件里面设置android:clickable="false",并设置状态跟随父布局android:duplicateParentState="true",至于效果,则随自己写吧
7.2 案例分析4种情况:
1).如何让子类只有触摸事件,没有点击事件
2).如何让子类既有触摸事件又有点击事件
3).如何让父类只有触摸事件,没有点击事件
4).如何让父类既有触摸事件又有点击事件
分析总结:
- .onTouch为true,事件被消费了,ontouchevent不执行,点击也就不会执行
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("peng"," button.setOnTouchListener"+event.getAction());
return true;
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("peng"," button.setOnClickListener");
}
});
2). onTouch为false,ontouchevent会执行,这样,点击事件会执行
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("peng"," button.setOnTouchListener"+event.getAction());
return false;
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("peng"," button.setOnClickListener");
}
默认情况下,子view的onTouchEvent返回true,消费
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean pass=super.onTouchEvent(event);
Log.d("peng","onTouchEvent onTouchEvent"+pass);
return pass;
}
- .父类想要响应,子类不能消费,onTouch false ,onTouchEvent 也为false,onTouch 为false
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("peng"," button.setOnClickListener");
}
});
viewHead.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("peng"," viewHead.setOnTouchListener"+event.getAction());
return true;
}
});
viewHead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("peng"," viewHead.setOnClickListener");
}
});
public class Myview extends android.support.v7.widget.AppCompatButton {
public Myview(Context context) {
super(context);
}
public Myview(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public Myview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("peng","Myview onTouchEvent onTouchEvent"+false);
return false;
}
- .父类想要响应,子类不能消费,onTouch false ,onTouchEvent 也为false,onTouch 为false .父类的onTouchEvent也要重写true,代表消费了。
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("peng","MyParentView onTouchEvent");
return true;
}
子控件拿到事件之后,先判断是否设置了OnTouchListener, 如果设置了,则调用OnTouchListener的onTouch方法,如果返回true,事件已经处理到此结束,则跳过onTouchEvent方法,否则调用onTouchEvent方法
7.3 点击事件被拦截,但是想传到下面的view,如何操作?
反向制约:重写子类的requestDisallowInterceptTouchEvent()方法返回true,就不会执行父类的onInterceptTouchEvent(),即可将点击事件传到下面的View。
7.4 我想让webview在应用里面后台运行?看不到界面
2个viewGoup
1个webview和一个ViewGroup(包含4个btn)
点击btn的时候,会消费掉事件
问题:viewgroup点击空白也是会有事件的,如何给他添加监听
加入点击空白页面,Viewgroup的子View消费掉。(webview的子空间)
问题:不想让子控件消费怎么做
1).可以自己消费掉,ontouch==true。不再传递了,onclick事件就不会执行
- .可以让另外一个viewgourp自己消费掉。
ontouch==true,自己的onclick不会在执行,但是这个子view还是响应了
原因:因为没有拦截,走了子类的dispathevent方法。子类的dispathevent----ontouch---子类的onclick方法消费了。
所以消费是onclick和ontouch方法,但是onclick方法也是要先调用ontouch---ontouchevnet----onclick。
总结:最后的消费指的时onTouch事件
7.5 有一个布局,然后有一个textview,然后想点击整个布局有点击事件
结果发现:点击textview的区域没有响应,因为textview把焦点占用了。为了让整个区域都有效果的话,把textview设置成
android:clickable="false"
<TextView
android:id="@+id/tv_sport_data_second_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/dp_20"
android:textColor="@color/color_333333"
android:textStyle="bold"
android:clickable="false"
android:text="0"
android:layout_below="@id/ll_second_title"
android:layout_marginTop="@dimen/dp_6"
<RelativeLayout
android:id="@+id/rl_sport_data_second"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
>
<LinearLayout
android:id="@+id/ll_second_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/tv_sport_data_second_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/color_333333"
android:textSize="@dimen/dp_14"
android:text="@string/string_sport_rank_total_sport"
></TextView>
8.请简述Android事件传递机制, ACTION_CANCEL事件何时触发?
1). 关于ACTION_CANCEL何时被触发,系统文档有这么一种使用场景:在设计设置页面的滑动开关时,如果不监听ACTION_CANCEL,在滑动到中间时,如果你手指上下移动,就是移动到开关控件之外,则此时会触发ACTION_CANCEL,而不是ACTION_UP,造成开关的按钮停顿在中间位置。
意思是当滑动的时候就会触发,不知道大家搞没搞过微信的长按录音,有一种状态是“松开手指,取消发送”,这时候就会触发ACTION_CANCEL。
2). 简单来说不是一个完整的手势响应 例如:子控件只是响应了down 而父控件把子控件的up事件拦截了 这个时候就会触发cancel事件。
详细:当控件收到前驱事件(什么叫前驱事件?一个从DOWN一直到UP的所有事件组合称为完整的手势,中间的任意一次事件对于下一个事件而言就是它的前驱事件)之后,后面的事件如果被父控件拦截,那么当前控件就会
9. 滑动冲突源码分析
10. 滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?
10. 1 外部拦截法:(根据自己的业务拦截子view),重写一个方法
即父View根据需要对事件进行拦截。逻辑处理放在父View的onInterceptTouchEvent方法中。我们只需要重写父View的onInterceptTouchEvent方法,并根据逻辑需要做相应的拦截即可。
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if (满足父容器的拦截要求) {
intercepted = true;
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
注意点:
1). ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理!
2). ACTION_MOVE方法中进行判断,根据业务逻辑需要,如果需要父View处理则返回true,否则返回false,事件分发给子View去处理。
3). ACTION_UP也需要返回false,如果返回true,并且滑动事件交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。
- 而父View不一样,如果父View在ACTION_MOVE中开始拦截事件,那么后续ACTION_UP也将默认交给父View处理!
- 可以直接用super。默认都是不拦截
可以直接用super。默认都是不拦截
/***
* 如果不写整个方法的话:就会响应子类的touchEvent方法,而不响应自己viewGroup的方法
* @param
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://0
mXDown = ev.getRawX();
mXLastMove = mXDown;
break;
case MotionEvent.ACTION_MOVE://2
mXMove = ev.getRawX();//获取相对于屏幕的x值
float diff = Math.abs(mXMove - mXDown);
mXLastMove = mXMove;
// 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
if (diff > mTouchSlop) {
return true;
}
break;
case MotionEvent.ACTION_UP://1
break;
}
boolean superResult = super.onInterceptTouchEvent(ev);
Log.d("ScrollerLayout", "superResult" + superResult+"ev"+ev.getAction());
return superResult;
}
具体:
1.down 不拦截,否则up收不到,点击事件也会没有
2.move 更加业务判定。得到子view,滑动的距离和item的位置决定
3.up 不拦截
10.1.2 具体案例写法
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
nowY = y;
intercepted = super.onInterceptTouchEvent(event);
break;
}
case MotionEvent.ACTION_MOVE: {
if(mListView.getFirstVisiblePosition()==0
&& y>nowY){
intercepted = true;
break;
}
else if(mListView.getLastVisiblePosition()==mListView.getCount()-1
&& y<nowY){
intercepted = true;
break;
}
intercepted = false;
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
return intercepted;
}
10.2 内部拦截法:(拦截子view) (重写2个方法,都是事件分发的方法)
即父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。这需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。下面是子View的dispatchTouchEvent方法的伪代码:
1). 父View需要重写onInterceptTouchEvent方法:
为什么要重写父类的 onInterceptTouchEvent?因为默认不拦截,你需要的是拦截它
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {//down不拦截,给子类
return false;
} else {//拦截
return true;
}
}
2). 重写子类的dispatchTouchEvent()方法
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
parent.requestDisallowInterceptTouchEvent(true); // 父类不拦截, 子类处理
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (父容器需要此类点击事件) {
parent.requestDisallowInterceptTouchEvent(false);//请求父类拦截, 父类处理
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
10.2.1 内部拦截法总结:
1). 父View不能拦截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT标志位控制,一旦父容器拦截ACTION_DOWN那么所有的事件都不会传递给子View。
2). View的dispatchTouchEvent方法的ACTION_DOWN中, parent.requestDisallowInterceptTouchEvent(true)2). 滑动策略的逻辑放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要获取点击事件则调用 parent.requestDisallowInterceptTouchEvent(false)方法,让父容器去拦截事件。如果不需要,则相反
10.2.2 内部拦截法原理:
1). 内部拦截法也叫View分发反向制约的方法? 2). 拦截不拦截,由2个东西决定的。一个是requestDisllowIntercepter和onInterceptTouchEvent()2个决定的。
原因:但是子元素可以通过requestDisallowInterceptTouchEvent来干预父元素的分发过程,但是down事件除外(因为down事件方法里,会清除所有的标志位)。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
// If the event targets the accessibility focused view and this is it, start
// normal event dispatch. Maybe a descendant is what will handle the click.
if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
ev.setTargetAccessibilityFocus(false);
}
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
10.3 从内容逆向思维分析
1). 有时候,我们不想去修改引入的第三方控件,或者说是无法修改时。就必须考虑从当前从Touch传递事件中最后的那个View逆向考虑。
首先,由Android中View的Touch事件传递机制,我们知道Touch事件,首先必然由最外层View拦截,如果无法更改这个最外层View,那么是不是就没辙了呢?
其实不然,Android这么高大上的系统必然考虑到了这个问题,好了废话不说,先看代码
解决方案:onTouch方法中每次进入就设定父View不拦截此次事件,然后在MOTION_MOVE时候,根据滑动的距离判断再决定是父View是否有权利拦截Touch事件(即滑动行为)。
carouselView.setOnTouchListener( new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
carouselView.getParent().requestDisallowInterceptTouchEvent( true );
int x = ( int ) event.getRawX();
int y = ( int ) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break ;
case MotionEvent.ACTION_MOVE:
int deltaY = y - lastY;
int deltaX = x - lastX;
if (Math.abs(deltaX) < Math.abs(deltaY)) {
carouselView.getParent().requestDisallowInterceptTouchEvent( false );
} else {
carouselView.getParent().requestDisallowInterceptTouchEvent( true );
}
default :
break ;
}
return false ;
}
}
2). 一个viewpager2里面放了很多图片。但是图片又可以大于屏幕,导致滑动冲突。浏览图片 ViewPager2和HorizontalScrollView滑动冲突 结果:Viewpager2不能重新怎么办?它是final类。导致内部拦截和外部拦截不适用!
重写onTouchListener();
10.4 down,move ,Up,都是否需要拦截总结?
1). ACTION_DOWN,都不要拦截子类
在这里,首先down事件父容器必须返回false ,因为若是返回true,也就是拦截了down事件,
那么后续的move和up事件就都会传递给父容器,子元素就没有机会处理事件了。
其次是up事件也返回了false,一是因为up事件对父容器没什么意义,其次是因为若事件是子元素处理的,却没有收到up事件会让子元素的onClick事件无法
2). 要在
MotionEvent.ACTION_MOVE根据情况,是父类滑动还是子类滑动
10.5 滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?
主要用内部拦截,系统里面的,horscorrlview和,比如recyleview.
原因: 你只能重新你可以的, 能达到的view(主要看你哪个View是你自己的)
11. 滑动冲突实践,实例: recleview嵌套recleview
11. 1 一个ScrowView(父类)和一个RecycleView(子类)
他说重写子类的onIntecepter方法,让子类拦截,消费掉
11.2 ViewPager中嵌套ViewPager怎么处理滑动冲突?
1).重写canScroll()方法
2).自己手写
11.3 一个scorview和一个日期选择器
分析:scorllView是父类,datapinker是子类(viewGroup)
现在现象:在分辨率比较小的手机中,有时候滑动scorllView,有时候滑动dataPinker
需要实现的效果:拦截scorllView。超过1屏的时候,自己滑动
private void doMove(MotionEvent event)
{
mMoveLen += (event.getY() - mLastDownY);
if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2)
{
// 往下滑超过离开距离
moveTailToHead();
mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
} else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2)
{
// 往上滑超过离开距离
moveHeadToTail();
mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
}
mLastDownY = event.getY();
invalidate();
}