安卓复杂滑动案例 自定义behavior源码分析 实现头布局图片的缩放透明度变化,RecycleView的滑动布局,坐标变化


#复杂滑动案例

上方图片放大,
透明
输入框,不断增大
    * 变色
滑动的时候,条目不会改变.
    * 再滑的时候,条目滑动


1,让rv居于头部的下方
    * 方案?:
    * 1,重写layoutDependsOn 让当前rv去以来头部视图
    * 2,获取都以来的头部视图的高度onDependentViewChanged 设置给rv 设置setTranslationY
2,让rv跟着头部 向上平移
处理头部的向上平移:在onNestedPreScroll中计算移动距离,还没有真正移动
    * float newTranslationY = dependency.getTranslationY() - dy;
            //计算出最小平移的y的距离

            float minTranslationY = -(dependency.getHeight() - finalHeight);
            if (newTranslationY > minTranslationY) {
                dependency.setTranslationY(newTranslationY);
                /**
                 * 在图片折叠的情况下
                 * 1不允许RecycleView自身滚动,不能和图片一起平移
                 * 2只能和图片一起向上移动
                 */
                //1,
                consumed[1] = dy;
                //2,
            }
3,rv向上平移  
    onDependentViewChanged
     child.setTranslationY(dependency.getHeight()+dependency.getTranslationY());
    后面是一个负数,所以用+号
4,向下平移的处理,
*  onNestedScroll方法中
*  float newTranslation = dependency.getTranslationY() - dyUnconsumed;
        //平移的最大距离,坐标0
        if (newTranslation <0) {
            dependency.setTranslationY(newTranslation);
        }
5处理图片的缩放和透明都,变化
    * onDependentViewChanged中拿到移动百分比,
    * 按照百分比,进行图片的缩放,和透明度变化
6,手指快读滑动图片的缓慢打开和关闭 

    * 快速滑动 


<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ImageView
        android:src="@drawable/header"
        android:scaleType="centerCrop"
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="300dp" />

    <android.support.v7.widget.RecyclerView
        android:background="#efffffff"
        app:layout_behavior="@string/HeaderScrollBehavior"
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>


</android.support.design.widget.CoordinatorLayout>

package com.example.yangg.commplexscrol;

import android.content.Context;
import android.os.Handler;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Scroller;

/**
 * Created by yangg on 2017/7/6.
 */

public class HeaderScrollBehavior extends CoordinatorLayout.Behavior<RecyclerView> {
    private View dependency;
    private final Scroller mSroller;

    public HeaderScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        mSroller = new Scroller(context);
    }

    /**
     * 去定当前空间rv 以来的是哪个子试图
     */
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, RecyclerView child, View dependency) {
        if (dependency.getId() == R.id.iv) {
            this.dependency = dependency;
            return true;
        }
        return false;
    }

    /**
     * 依赖的视图变化
     *
     * @param parent
     * @param child
     * @param dependency
     * @return rv 就是child
     * rvy轴上平移一段距离:移动图片的高度
     * <p>
     * 1,图片向上折叠
     */
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, RecyclerView child, View dependency) {

        //把图片移动的高度给rv 图片走多少,rv就走多少
        child.setTranslationY(dependency.getHeight() + dependency.getTranslationY());
        /**
         * 在这个方法中控制图片的变化
         * 计算出移动的百分比,,图片就缩放百分之多少
         *
         */
        float persent = Math.abs(dependency.getTranslationY() / (dependency.getHeight() - finalHeight));
        dependency.setScaleX(1 + persent);
        dependency.setScaleY(1 + persent);
        dependency.setAlpha(1 - persent);
        return true;
    }

    /**
     * 判断 在嵌套滚动将要开始的时候,一般用于判断滚动方向  顺序1!!!
     *
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param nestedScrollAxes
     * @return
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View directTargetChild, View target, int nestedScrollAxes) {
        //判断垂直滚动,,滚动之前 告诉系统,垂直滚动
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    private float finalHeight = 150;

    /**
     * 在滚动之前,告诉系统,  要滚动的距离,dy
     * onStartNestedScroll 之后  顺序2!!!
     * 在嵌套滚动之前执行,这个方法在在onStartNestedScroll 执行
     * dy:y方向上移动的距离,值得是单位时间内手指移动的距离
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dx
     * @param dy
     * @param consumed          :十一恶搞数组:消耗的xy的距离
     *                          0元素:表示x方向系统小号的距离
     *                          1元素:表示y方向系统消耗 的距离
     */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        //判断手指向下移动dy<=0  向上移动dy>0
        if (dy <= 0) {
            return;
        }

        //计算他移动了多少
        float newTranslationY = dependency.getTranslationY() - dy;
        //计算出最小平移的y的距离

        float minTranslationY = -(dependency.getHeight() - finalHeight);
        if (newTranslationY > minTranslationY) {
            dependency.setTranslationY(newTranslationY);
            /**
             * 在图片折叠的情况下
             * 1不允许RecycleView自身滚动,不能和图片一起平移
             * 2只能和图片一起向上移动
             */
            //1,
            consumed[1] = dy;
            //2,
        }

    }

    /**
     * 开始滚动                 顺序3!!!
     * rv 消耗掉,y方向上的距离,dyUnconsumed不等于0
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dxConsumed
     * @param dyConsumed
     * @param dxUnconsumed
     * @param dyUnconsumed
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        //Log.i("test", "dy--->" + dyConsumed);
        Log.i("test", "dyUnconsumed" + dyUnconsumed);
        /**
         * 向下移动dyUnconsumed <0的时候
         */
        if (dyUnconsumed > 0) {
            return;
        }
        float newTranslation = dependency.getTranslationY() - dyUnconsumed;
        //平移的最大距离,坐标0
        if (newTranslation <= 0) {
            dependency.setTranslationY(newTranslation);
        }
    }

    /**
     * Fling 快速滑动,执行, 猛动
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param velocityX
     * @param velocityY  表示快速滑动松开收瞬间y方向的的速度,向上为+ ,向下喂-
     * @return
     */
    //定义 boolean,判断是否自动滚动中,,
    private boolean isScrolling = false;

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, float velocityX, float velocityY) {

        Log.i("test", "velocityY" + velocityY);

        if (!isScrolling) {
            return startExpandOrClose(velocityY);
        }
        Log.i("test", "onNestedPreFling");
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }

    /**
     * 慢慢滚动的时候走这里
     *  父布局布局停止滚动的时候,执行一次,
     *  手指停了之后,又执行一次
     * @param coordinatorLayout
     * @param child
     * @param target
     */
    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
       //800以下都可以,表示速度很慢
        startExpandOrClose(0);
        Log.i("test","onStopNestedScroll");
    }

    //在滚动被子视图接受的时候执行
    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, RecyclerView child, View directTargetChild, View target, int nestedScrollAxes) {
        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        //如果我滑动的过程中的时候停止了,但是没有松开收调用onNestedScrollAccepted
        //继续滑动-->停止-->onNestedScrollAccepted
        //再执行,-->松开-->onNestedScrollAccepted  最后一次执行这个方法onNestedScrollAccepted
        //手指松开的一瞬间,我才真正停止,滚动了,
        //让动画禁止执行  ,,第二次不会被调用,第二次,的时候不影响上个方法,执行
        mSroller.abortAnimation();
    }

    private boolean startExpandOrClose(float velocityY) {
        //获取松开收瞬间,图片已经平移的距离
        float translationY = dependency.getTranslationY();
        float upFinalTranslationY = -(dependency.getHeight() - finalHeight);
        float downFinalTranslationY = 0;
        //dingyi boolean值却动是否闭合的状态fun        boolean isClose = false;
        if (Math.abs(velocityY) <= 800) {
            /**
             * 滑动过成中慢慢的抬起手,
             * 判断松开收时已经平移的位置 和 最向上品故意位置的差值的据对只进行比较
             */
            if (Math.abs(translationY) < Math.abs(translationY - upFinalTranslationY)) {
                isClose = false;
            } else {
                isClose = true;
            }

        } else {
            /**
             * 快速滑动
             */
            if (velocityY > 0) {//向上滑动
                //东松开收的钝剑位置自动滚动到完全闭合的位置
                isClose = true;
            } else {//向下滑动
                //完全展开
                isClose = false;
            }
        }

        //确定滚动的目标点
        float targetTranslationY = isClose ? upFinalTranslationY : downFinalTranslationY;
        int starY = (int) translationY;
        //变化的
        int dy = (int) (targetTranslationY - translationY);
        mSroller.startScroll(0, starY, 0, dy);
        handler.post(flingRunable);

        isScrolling = true;
        /**
         * ?????????????????????
         */
        return true;
    }

    private Handler handler = new Handler();

    private Runnable flingRunable = new Runnable() {
        @Override
        public void run() {

            //Scroller滚滚的用户那里
//            是一阵一帧的向前滚动的,眼不断的计算是否滚动到目标,如果未滚动到,则据需滚动
            //判断scroller是否滚动到莫表
            //这个方法还可以判断是否有一个新的小目标点
            if (mSroller.computeScrollOffset()) {
                //mSroller.getCurrY() 指获取下一个新的位置
                dependency.setTranslationY(mSroller.getCurrY());
                handler.post(this);
            }
        }
    };
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值