您的位置:首页 > 其它

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

2017-07-06 13:11 483 查看


#复杂滑动案例

* 上方图片放大,
* 透明
* 输入框,不断增大

    * 变色
* 滑动的时候,条目不会改变.

    * 再滑的时候,条目滑动


* 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
* 让rv在y轴上平移一段距离:移动图片的高度
* <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          :十一恶搞数组:消耗的x和y的距离
*                          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);
}
}
};
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐