首先说明,这个例子是来自这篇博客的(一个Demo带你彻底掌握View的滑动冲突),感谢博主的分享。看了该博主的文章,于是自己试了一下,也看了评论,从中得到些解决方法,有些零散,于是自己集合起来做了些修改,可以实现平滑上下移动、ViewGroup不会出现一直往上移动的bug、松手时动画回弹、还有回弹过程中手指马上进行滑动所出现的问题。本来想在博主评论区回复的,发现回复有字数限制,所以只好写在这里了
效果图如下:
下面直接贴出代码吧,关键部分有解析的了
主要的两个类:
/**
* Created by Gerka on 2016/12/11.
*/
public class MyParentView extends LinearLayout {
private ScrollView scrollView;
private ValueAnimator animator;
private int mMove;
private int yDown, yMove;
private int i = 0;
private boolean isIntercept = false;
private int actionTop;
private int actionBottom;
public MyParentView(Context context) {
super(context);
}
public MyParentView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyParentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyParentView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
scrollView = (ScrollView) getChildAt(0);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// Log.v("kaka", "------------------isIntercept = "+isIntercept+"----event = "+ev.getAction());
onInterceptTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int y = (int) ev.getY();
int mScrollY = scrollView.getScrollY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("kaka", "------------action down");
yDown = y;
if(animator != null){
animator.end(); //一定要加这个,让布局立刻回位,不然的话,回弹动画没结束就马上进行下一次的下拉,布局会飞走噢
}
break;
case MotionEvent.ACTION_MOVE:
yMove = y;
// Log.i("kaka", "--------------yDown = "+yDown+"-----yMove = "+yMove+"---isIntercept = "+isIntercept+"---mScrollY = "+mScrollY);
if (yMove - yDown > 0 && mScrollY == 0) {
Log.i("kaka", "--------------isIntercept = "+isIntercept);
if (!isIntercept) {
yDown = (int) ev.getY();
isIntercept = true;
}
}
break;
case MotionEvent.ACTION_UP:
// layout(getLeft(), getTop() - i, getRight(), getBottom() - i);
actionTop = getTop();
actionBottom = getBottom();
animator = ValueAnimator.ofInt(0, i);
animator.setDuration(500);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int) animation.getAnimatedValue();
layout(getLeft(), actionTop - curValue, getRight(), actionBottom - curValue);
}
});
animator.start();
i = 0;
isIntercept = false;
break;
}
if (isIntercept) {
mMove = yMove - yDown;
i += mMove;
if(i < 0){ //判断少于0时,要把isIntercept至为false了,不然布局会一直往上移动,会移出去
isIntercept = false;
//这里做了 move - i 的处理,是为了要把布局刚好回位到y = 0的位置
layout(getLeft(), getTop() + mMove - i, getRight(), getBottom() + mMove - i);
i = 0;
}else {
layout(getLeft(), getTop() + mMove, getRight(), getBottom() + mMove);
}
}
return isIntercept;
}
}
/**
* Created by Gerka on 2016/12/11.
*/
public class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//这里很关键,如果不加这句,当ScrollView在顶端时,手指开始下滑操作,然后再往上滑时,你会发现ScrollView里面的view不会滑动
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return super.onTouchEvent(ev);
}
}
布局文件,很简单
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_bright"
tools:context="com.readboy.gerka.myapplication.MainActivity">
<com.gerka.widget.MyParentView
android:layout_width="match_parent"
android:layout_marginTop="100dp"
android:layout_height="match_parent"
>
<com.gerka.widget.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0000">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
<include layout="@layout/item_text_layout"/>
</LinearLayout>
</com.gerka.widget.MyScrollView>
</com.gerka.widget.MyParentView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:contentDescription="@android:string/ok"
android:id="@+id/ooo"
android:layout_marginTop="38dp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginStart="29dp" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="利物浦"
android:gravity="center"
android:textSize="20sp"
/>
</LinearLayout>