Behavior的demo——粗仿天猫详情页效果

来源:互联网 发布:淘宝怎么秒杀 编辑:程序博客网 时间:2024/05/22 06:33

效果

        整个内容区域分为上下两部分,当将上部分内容拉到底部时,再拉动会将下面一部分内容拉出来,并且在松手时根据拉动的距离判断是回弹还是拉出来。在下部分时同样,拉动到顶部后继续下拉会将上部分拉出来。

思路

思路一

        可以将上部分写成带有上拉功能的控件,根据拉动的距离将下部分在垂直方向上进行移动,从而达到模拟上拉的效果。 
        同样,将下部分写成具有下拉功能的控件,也根据拉动的距离将上部分在垂直方向上移动。 
        这种思路需要处理上下拉控件,并且在拉动过程中得设置回调,在回弹过程中一样得设置回调,这样才能达到两者同时滚动的效果。同时,上下部分在垂直方向上的移动需要一个单独的类进行协调。并且根据下部分控件的变化,需要不断地自定义带有下拉功能的控件。

思路二

        利用CoordinatorLayout与Behavior,只需要自定义上拉加载下部分的Behavior与下拉加载上部分的Behavior即可。

示例

        上拉加载的Behavior。注:上部分使用的是NestedScrollView,support v4中的。它类似于ScrollView,但可以与CoordinatorLayout一起使用。如下: 
public class FooterBehavior extends CoordinatorLayout.Behavior {    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();    public FooterBehavior() {    }    public FooterBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {        return target.getId() == R.id.anchor && isBottom((NestedScrollView) target) && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0 ;        //判断正在垂直滑动的控件是不是自己想要的,并且正处于底部    }    private boolean isUploaded = false;    @Override    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {        if (dy > 0) {//上滑        } else {//下滑            if (sum > 0) {//已经上滑了一部分,此时又进行下滑。因此,需要将此时的下滑给屏蔽掉                isUploaded = true;                consumed[1] = dy;//禁止target的自身滑动。此时不会回调onNestedScroll方法,因此需要自己处理垂直位移                sum += dy;                ViewCompat.setTranslationY(child, -sum);                ViewCompat.setTranslationY(target, -sum);            }        }    }    private int sum;    @Override    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {        if (sum < child.getHeight()) {            sum = dyUnconsumed + sum;            if (sum > child.getHeight())                sum = child.getHeight();            ViewCompat.setTranslationY(child, -sum);            ViewCompat.setTranslationY(target, -sum);        }    }    @Override    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {        if (sum < child.getHeight() / 2) {//手指离开时,根据滑动距离判断是回弹还是继续上拉            hide(child);            hide(target);        } else {            show(child, -target.getHeight());            show(target, -target.getHeight());        }        if (isUploaded) {//滑动过程中下拉过,因此屏蔽掉下拉时对NestedScrollView造成的fling效果            ((NestedScrollView) target).fling(0);        }        isUploaded = false;        sum = 0;    }    //判断NestedScrollView是否滑动到底部    private boolean isBottom(NestedScrollView scrollView) {        int height = scrollView.getHeight();        int height1 = scrollView.getChildAt(0).getHeight();        return scrollView.getScrollY() >= height1 - height;    }    //通过属性动画隐藏和显示指定的内容    private void hide(final View view) {        ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(200);        animator.start();    }    private void show(final View view, int target) {        ViewPropertyAnimator animator = view.animate().translationY(target).setInterpolator(INTERPOLATOR).setDuration(200);        animator.start();    }}

        以下是下拉时的Behavior,大部分思路与上面的Behavior类似。它的child是RecyclerView。如下:

public class HeaderBehavior extends CoordinatorLayout.Behavior<View> {    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();    public HeaderBehavior() {    }    public HeaderBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    private int mInitY;    @Override    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {        mInitY = (int) ViewCompat.getTranslationY(child);        sum = (int) ViewCompat.getTranslationY(child);        return target.getId() == R.id.tv && isTop(child, target) && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;    }    private boolean isUploaded = false;    @Override    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {        if (dy > 0) {//上滑            if (sum > mInitY) {//已经下拉出一部分,所以此时上滑不应该再没去target                isUploaded = true;                consumed[1] = dy;//禁止target的自身滑动。此时不会回调onNestedScroll方法,因此需要自己处理垂直位移                sum -= dy;                ViewCompat.setTranslationY(child, sum);                ViewCompat.setTranslationY(target, sum);            }        } else {//下滑        }    }    private int sum;    @Override    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {        if (Math.abs(sum) <= child.getHeight()) {//sum < 0            sum -= dyUnconsumed;            if (sum >= 0)                sum = 0;            ViewCompat.setTranslationY(child, sum);            ViewCompat.setTranslationY(target, sum);        }    }    @Override    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {        if (Math.abs(sum) > target.getHeight() / 2) {            show(child, -child.getHeight());            show(target, -child.getHeight());        } else {            hide(child);            hide(target);        }        if (isUploaded) {            ((RecyclerView) target).stopScroll();        }        isUploaded = false;        sum = 0;    }    private boolean isTop(View child, View target) {        RecyclerView view = (RecyclerView) target;        LinearLayoutManager lm = (LinearLayoutManager) view.getLayoutManager();        return ViewCompat.getTranslationY(target) == -child.getHeight() && lm.findFirstCompletelyVisibleItemPosition() == 0;    }    private void hide(final View view) {        ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(200);        animator.start();    }    private void show(final View view, int target) {        ViewPropertyAnimator animator = view.animate().translationY(target).setInterpolator(INTERPOLATOR).setDuration(200);        animator.start();    }}
使用如下:
<com.example.demo.DemoView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/co"    android:layout_width="match_parent"    android:layout_height="match_parent">    <android.support.v4.widget.NestedScrollView        android:id="@+id/anchor"        app:layout_behavior="com.example.hufeng.demo.HeaderBehavior"        android:layout_width="match_parent"        android:layout_height="wrap_content">        <!--保存高度超过屏幕高-->        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical">            <View                android:layout_width="match_parent"                android:layout_height="500dp"                android:background="@android:color/holo_red_dark" />            <View                android:layout_width="match_parent"                android:layout_height="500dp"                android:background="@android:color/holo_green_light" />        </LinearLayout>    </android.support.v4.widget.NestedScrollView>    <android.support.v7.widget.RecyclerView        android:id="@+id/tv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_gravity="bottom"        android:background="@android:color/holo_red_light"        android:textColor="@android:color/white"        app:layout_behavior="com.example.hufeng.demo.FooterBehavior" /></com.example.demo.DemoView>

        其根结果的DemoView继承于CoordinatoryLayout,只是将其子View按垂直排列,并且可以排到屏幕之外。代码如下:

public class DemoView extends CoordinatorLayout {    public DemoView(Context context) {        super(context);    }    public DemoView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec,heightMeasureSpec);        int sum = 0;        for(int x = 0;x<getChildCount();x++){            sum += getChildAt(x).getMeasuredHeight();        }        setMeasuredDimension(getMeasuredWidth(),MeasureSpec.makeMeasureSpec(sum,MeasureSpec.EXACTLY));    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        int top = 0;        for (int x = 0; x < getChildCount(); x++) {            View view = getChildAt(x);            view.layout(l, top, r, top + view.getMeasuredHeight());            top += view.getMeasuredHeight();        }    }}





0 0