在上一章中我们实现了抽屉+滚动功能,但是遗留了一个问题就是滚动事件与组件的Touch事件冲突,接下来我们看一下他们冲突的原因
public boolean onInterceptTouchEvent (MotionEvent ev)
使用此方法可以拦截所有触摸屏动作引发的事件。这意味着你可以监视分派给子项的事件,并且可以拿到任何当前手势的所有权。
使用此方法需谨慎。因为它与View.onTouchEvent(MotionEvent)有相当复杂的交互影响。这两者都必须同时正确地实现。事件将按以下顺序来被方法接收:
1. 接收到down事件
2. 事件将被视图组的一个子视图处理,或者被传递给自己的onTouchEvent()方法处理;这意味着你必须实现onTouchEvent(),并且返回true,这样才可以接着接受到其他的手势(而不是寻求一个父视图来处理它)。onTouchEvent()返回true后,你将不再接受到onInterceptTouchEvent()的任何事件,同时所有对触摸动作的处理必须像往常一样在onTouchEvent()中进行。
3. 如果返回false,则接下来的每个事件(所有的up事件,包含最后一个up)将会首先被传递到这里,然后到目标对象view的onTouchEvent()。
4. 如果返回ture,你将不会接收到以下任何事件:目标view将会接收到相同的事件,但是带着ACTION_CANCEL的动作。所有在此之后的事件将会被传递到你的onTouchEvent()方法中,并且不再在这里出现。
参数
ev 沿着树型结构往下分派的动作事件
返回值
若将动作事件从子视图中截获并通过onTouchEvent()将他们分派给当前ViewGroup,则返回true。当前目标将收到一个ACTION_CANCEL事件,并且不再会有其他消息被传递到这里。
onInterceptTouchEvent 这个功能只有在布局中才会有的,如上面所述,所以我们解决这个问题,就要实现当我们实现组件的Touch事件的时候,需要onInterceptTouchEvent 返回false,否则组件无法捕获Touch事件,知道原理以后,我们就可以编写代码,我们使用一个标志位来标准HorizontalScrollView的子View是否正在实现Touch事件,如果有则设置flag = 0;当Touch_up的时候,设置flag = -1,而在HorizontalScrollView的onInterceptTouchEvent 函数中判断flag是否等于-1,如果flag == -1,则onInterceptTouchEvent 返回return super.onInterceptTouchEvent(ev);,否则返回false。下面我们使用代码来实现:
布局文件需要重新编写:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<SlidingDrawer
android:id="@+id/slidingDrawer1"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
android:content="@+id/content"
android:handle="@+id/handle" >
<Button
android:id="@+id/handle"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="Handle" />
<com.example.test.Horizon
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/black"
android:scrollbars="none" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:id="@+id/content_linear"
android:orientation="horizontal" >
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:id="@+id/btn1"
android:text="btn1" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn2" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn3" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn4" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn5" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn5" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn5" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn5" >
</Button>
<Button
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:text="btn5" >
</Button>
</LinearLayout>
</com.example.test.Horizon>
</SlidingDrawer>
</RelativeLayout>
与上面上一章中的布局文件不同的地方就是用com.example.test.Horizon替换HorizontalScrollView,下面就是Horizon类的内容:
Horizon.java
package com.example.test;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
public class Horizon extends HorizontalScrollView{
public Horizon(Context context) {
super(context);
}
public Horizon(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (MainActivity.flag == -1) {
return super.onInterceptTouchEvent(ev);
}else{
return false;
}
}
}
主类的内容如下:
package com.example.test;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
flag = 0;
Log.e("test", "down");
break;
case MotionEvent.ACTION_MOVE:
Log.e("test", "move");
break;
case MotionEvent.ACTION_UP:
flag = -1;
Log.e("test", "up");
break;
}
return false;
}
});
}
public Button btn1;
public static int flag = -1;
}
测试结果如下:
07-06 21:49:04.639: E/test(409): down
07-06 21:49:04.659: E/test(409): move
07-06 21:49:04.669: E/test(409): move
07-06 21:49:04.679: E/test(409): move
07-06 21:49:04.699: E/test(409): move
07-06 21:49:04.709: E/test(409): move
07-06 21:49:04.719: E/test(409): move
07-06 21:49:04.739: E/test(409): move
07-06 21:49:04.749: E/test(409): move
07-06 21:49:04.769: E/test(409): move
07-06 21:49:04.769: E/test(409): up
上面组件btn1实现了Touch事件同时移动,但是能够测试到up事件,不过你移动组件的时候,是不能移动滚动条