Touch事件的冲突在Android开发中是非常常见的,有时为了实现较好的效果,必须解决Touch事件冲突的问题。
自定义一个ScrollBackLayout控件,该控件继承LinearLayout。要求该控件能随手指的下滑而下滑,松开手指时能自动弹回原处。这个功能实现起来是比较简单的。但是如果在该控件中添加一个ScrollView控件,这时就会出现Touch冲突的情况。具体解决如下:
自定义的ScrollBackLayout控件:
public class ScrollBackLayout extends LinearLayout
{
private int mMove;
private int yDown , yMove;
private int i = 0;
private boolean isIntercept;
private MyScrollView scrollView;
public ScrollBackLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
scrollView = (MyScrollView) getChildAt(0);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
int y = (int) event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
yDown = y;
break;
case MotionEvent.ACTION_MOVE:
yMove = y;
if ((yMove - yDown) > 0)
{
//计算每次滑动的距离和总距离,将每次滑动的距离作为layout()方法的参数并重新布局,达到滑动效果
mMove = yMove - yDown;
i += mMove;
layout(getLeft() , getTop() + mMove , getRight() , getBottom() + mMove);
}
break;
case MotionEvent.ACTION_UP:
//MotionEvent.Action_UP:将滑动的总距离作为layout()方法的参数,重新布局,达到布局回弹的效果
layout(getLeft() , getTop() - i , getRight() , getBottom() - i);
i = 0;
break;
}
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
int y = (int) ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
yDown = y;
isIntercept = false;
break;
case MotionEvent.ACTION_MOVE:
yMove = y;
if (yMove - yDown < 0)
{
isIntercept = false;
}
else if (yMove - yDown > 0)
{
isIntercept = true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return isIntercept;
}
}
关键是重写onInterceptTouchEvent方法。下面自定义一个ScrollView,重写onTouchEvent方法:
public class MyScrollView extends ScrollView
{
public MyScrollView(Context context)
{
this(context , null);
}
public MyScrollView(Context context, AttributeSet attrs)
{
this(context, attrs , 0);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent ev)
{
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
//禁止父View进行事件拦截
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int scrollY = getScrollY();
if (scrollY == 0)
{
//允许父View进行事件拦截
getParent().requestDisallowInterceptTouchEvent(false);
}
else
{
//禁止父View进行事件拦截
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.onTouchEvent(ev);
}
}
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/ic_main_left_bg">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_head"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
app:civ_border_color="#FFFFFF"
app:civ_border_width="1dp"
android:src="@mipmap/default_head"/>
</RelativeLayout>
<test.view.zhangtao.viewscrollbackdemo1.ScrollBackLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<test.view.zhangtao.viewscrollbackdemo1.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/content_layout"/>
</test.view.zhangtao.viewscrollbackdemo1.MyScrollView>
</test.view.zhangtao.viewscrollbackdemo1.ScrollBackLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#66cdaa">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider_color"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="70dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:src="@mipmap/ic_my_detail"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="60dp"
android:text="@string/person_center"
android:textSize="20sp"
android:textColor="@android:color/white"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:src="@mipmap/ic_main_next"/>
</RelativeLayout>
</LinearLayout>
自定义ScrollView在DOWN这个Action时,必须调用:getParent().requestDisallowInterceptTouchEvent(true);要不然事件还是会冲突,至于为什么这样实现,强烈建议看一下事件分发的相关源码。