UC浏览器主界面滑动折叠效果 使用自定义behavior实现 难度五颗星*****

UC浏览器主界面滑动折叠效果 使用自定义behavior实现 难度五颗星*****_第1张图片

思路:!!!!!!!!!!!

RcycleView上的HeadScrollBehavior 思路:


1。让recycleview居于头部的下方
---方案:
重写layoutDependsOn  让当前recycleview去依赖头部视图
重写onDependentViewChanged 获取到依赖的头部视图的高度,给recycleview设置setTranslationY


2.处理头部向上平移

在onNestedPreScroll 中 向上滑动是dy>0
float newTranslationY = dependency.getTranslationY() - dy;
//计算出最小平移的y距离
float minTranslationY = -(dependency.getHeight() - finalHeight);
if (newTranslationY > minTranslationY) {
dependency.setTranslationY(newTranslationY);
//在图片折叠的情况下,
// 1,不允许RecyclerView自身处理滚动
consumed[1] = dy;
// 2,只能和图片一起向上平移
}


3.recycleview往上平移
onDependentViewChanged中
//让RecyclerView在y方向上平移一段距离
child.setTranslationY(dependency.getHeight() + dependency.getTranslationY());


4.向下平移的处理
onNestedScroll方法中:
if (dyUnconsumed >= 0) {
return;
}
float newTranslationY = dependency.getTranslationY() - dyUnconsumed;
if (newTranslationY < 0) {
dependency.setTranslationY(newTranslationY);
}


5.处理图片的缩放和渐变
onDependentViewChanged 中:


//计算图片平移的百分比
float percent = Math.abs(dependency.getTranslationY() / (dependency.getHeight() - finalHeight));
// Log.i("test", "percent:" + percent);
//图片的缩放和透明度处理
dependency.setScaleX(1 + percent);
dependency.setScaleY(1 + percent);
dependency.setAlpha(1 - percent);


6.手指快速滑动图片的缓慢打开和关闭
onNestedPreFling--快速滑翔
判断速度,比如速度大于800 我们才认为是快速滑动了。
核心代码:
private boolean startExpandOrClose(float velocityY){
//获取松开手瞬间,图片已经平移的距离
float translationY = dependency.getTranslationY();
//图片向上移动的最终Y坐标位置-注意是负数
float upFinalTranslationY=-(dependency.getHeight()-finalHeight);
float downFinalTranslationY=0;
//定义boolean值确定是否是向闭合的状态滚动
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 startY= (int) translationY;
int dy= (int) (targetTranslationY-translationY);
mScroller.startScroll(0,startY,0,dy);
handler.post(flingRunnable);
isScrolling=true;
return true;
}


private Handler handler=new Handler();


private Runnable flingRunnable=new Runnable() {
@Override
public void run() {
//Scroller滚动的原理:
//是一帧一帧向前滚动的,滚动的过程中,要不断的计算是否滚动到目标,如果未滚动到,则继续滚动
//判断Scroller是否已经滚动到目标位置
//这个方法还可以判断是否有下一个新的小目标点
if(mScroller.computeScrollOffset()){
//getCurrY:指获取下一个新的位置
dependency.setTranslationY(mScroller.getCurrY());
handler.post(this);
}else{
isScrolling=false;
}
}
};


7.文本框的移动和背景色变化-HeadTextBeahvior

public class HeadTextBehavior extends CoordinatorLayout.Behavior {


private final ArgbEvaluator argbEvaluator;


public HeadTextBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
argbEvaluator = new ArgbEvaluator();
initOffset = context.getResources().getDimension(R.dimen.initOffset);
collapsedOffset = context.getResources().getDimension(R.dimen.collapsedOffset);
finalHeight = (int) context.getResources().getDimension(R.dimen.finalHeight);
initMargin = (int) context.getResources().getDimension(R.dimen.initMargin);
finalMargin = (int) context.getResources().getDimension(R.dimen.finalMargin);
}


@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
if (dependency.getId() == R.id.iv_head) {
return true;
}
return super.layoutDependsOn(parent, child, dependency);
}


private float initOffset = 130;
private float collapsedOffset = 5;
private int finalHeight = 50;
private int initMargin=20;
private int finalMargin=5;


@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//处理随着图片向上移动,当前控件也向上移动
float percent = Math.abs(dependency.getTranslationY() / (dependency.getHeight() - finalHeight));
// Log.i("test","percent:"+percent);
float translationY = collapsedOffset + (initOffset - collapsedOffset) * (1-percent);
child.setTranslationY(translationY);
int color= (int) argbEvaluator.evaluate(percent, Color.RED,Color.GREEN);
child.setBackgroundColor(color);
int margin= (int) (finalMargin+(initMargin-finalMargin)*(1-percent));
CoordinatorLayout.LayoutParams params= (CoordinatorLayout.LayoutParams) child.getLayoutParams();
params.setMargins(margin,0,margin,0);
child.setLayoutParams(params);
return true;
}
}


UC案例思路:
findFirstDependency:决定了你的头部视图是谁!
默认的是:
    @Override
        View findFirstDependency(List views) {
            for (int i = 0, z = views.size(); i < z; i++) {
                View view = views.get(i);
                if (view instanceof AppBarLayout) {
                    return view;
                }
            }
            return null;
        }


getScrollRange(View v):决定你的头部视图滚动的范围 !


决定了我们必须要去继承 HeaderScrollingViewBehavior 但是由于这个类是包级的 所以需要去拷贝源代码

----------------------------------------------------------------------------------------

UC浏览器主界面滑动折叠效果 使用自定义behavior实现 难度五颗星*****_第2张图片

代码实现  布局文件  :-----

activity_main

xml version="1.0" encoding="utf-8"?>
    android:id="@+id/activity_main"
    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">

            app:layout_behavior="@string/NewsPagerBehavior"
        android:id="@+id/fl_head"
        android:background="@android:color/holo_blue_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
                    android:id="@+id/tv_head"
            android:gravity="center_vertical"
            android:text="NewsPaget"
            android:layout_width="wrap_content"
            android:layout_height="250dp"
            android:textColor="#333"
            android:padding="12dp"
            android:layout_gravity="center" />
    
            app:layout_behavior="@string/TitleBehavior"
        android:background="#486ef9"
        android:layout_width="match_parent"
        android:layout_height="45dp">
                    android:id="@+id/tv_title"
            android:text="uc 头条"
            android:paddingRight="12dp"
            android:paddingLeft="12dp"
            android:textColor="#fff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    

            app:layout_behavior="@string/tabBehavior"
        android:id="@+id/tab_layout"
        android:background="@color/colorPrimary"
        app:tabIndicatorColor="#a3a1ff"
        app:tabTextColor="#bbffffff"
        app:tabSelectedTextColor="#c9c9c9"
        app:tabGravity="fill"
        android:layout_width="match_parent"
        android:layout_height="45dp"/>

    
        app:layout_behavior="@string/ContentBehavior"
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f5ffffff"/>

----------------

2!!!!!!!!:fragment.xml

xml version="1.0" encoding="utf-8"?>
    android:id="@+id/activity_main"
    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">

            app:layout_behavior="@string/NewsPagerBehavior"
        android:id="@+id/fl_head"
        android:background="@android:color/holo_blue_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <TextView
            android:id="@+id/tv_head"
            android:gravity="center_vertical"
            android:text="NewsPaget"
            android:layout_width="wrap_content"
            android:layout_height="250dp"
            android:textColor="#333"
            android:padding="12dp"
            android:layout_gravity="center" />
    
            app:layout_behavior="@string/TitleBehavior"
        android:background="#486ef9"
        android:layout_width="match_parent"
        android:layout_height="45dp">
        <TextView
            android:id="@+id/tv_title"
            android:text="uc 头条"
            android:paddingRight="12dp"
            android:paddingLeft="12dp"
            android:textColor="#fff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    

            app:layout_behavior="@string/tabBehavior"
        android:id="@+id/tab_layout"
        android:background="@color/colorPrimary"
        app:tabIndicatorColor="#a3a1ff"
        app:tabTextColor="#bbffffff"
        app:tabSelectedTextColor="#c9c9c9"
        app:tabGravity="fill"
        android:layout_width="match_parent"
        android:layout_height="45dp"/>

    
        app:layout_behavior="@string/ContentBehavior"
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f5ffffff"/>


--------------

Mainactivity.java文件

package com.example.yangg.uc;

import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

import com.example.yangg.uc.Behavior.NewsPagerBehavior;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ViewPager viewPager;
    private NewsPagerBehavior newsPagerBehavior;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        List fragments = new ArrayList<>();

        fragments.add(new MyFragment());
        fragments.add(new MyFragment());
        fragments.add(new MyFragment());
        viewPager = (ViewPager) findViewById(R.id.vp);

        MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
        myFragmentPagerAdapter.setDatas(fragments);
        viewPager.setAdapter(myFragmentPagerAdapter);


        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) findViewById(R.id.fl_head).getLayoutParams();

        newsPagerBehavior = (NewsPagerBehavior) layoutParams.getBehavior();

        initTab();


    }

    private void initTab() {
         TabLayout tableLayout = (TabLayout) findViewById(R.id.tab_layout);


        for (int i = 0; i < 3; i++) {
            tableLayout.addTab(tableLayout.newTab().setText("tab" + i));
        }
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tableLayout));
    }

    public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

        private List datas;

        public MyFragmentPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        public void setDatas(List datas) {
            this.datas = datas;
        }

        @Override
        public Fragment getItem(int position) {
            return datas.get(position);
        }

        @Override
        public int getCount() {
            return datas.size();
        }
    }

    @Override
    public void onBackPressed() {
        if (newsPagerBehavior.isClosed()) {
            newsPagerBehavior.open();
        } else {
            super.onBackPressed();
        }
    }
}
-----------------------MyFragment类

package com.example.yangg.uc;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

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

public class MyFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment, container, false);
        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

        super.onViewCreated(view, savedInstanceState);
        RecyclerView rv  = view.findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(getActivity()));

        rv.setAdapter(new RecyclerView.Adapter() {
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent,false);
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(v.getContext(), "点击了", Toast.LENGTH_SHORT).show();
                    }
                });
                MyViewHolder holder=new MyViewHolder(itemView);
                return holder;
            }

            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                MyViewHolder mVH= (MyViewHolder) holder;
                mVH.tv.setText("条目"+position);
            }

            @Override
            public int getItemCount() {
                return 30;
            }
        });
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{

        private final TextView tv;

        public MyViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(android.R.id.text1);
        }
    }
}

-----------------------------------

package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.example.yangg.uc.R;

import java.util.List;

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

public class ContentBehavior extends HeaderScrollingViewBehavior {

    private final Context context;

    public ContentBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency.getId() == R.id.fl_head;
    }

    /**
     * 找到要以来的头部视图,,找到时候 用方法layoutDependsOn 绑定依赖
     *
     * @param views
     * @return
     */
    @Override
    protected View findFirstDependency(List views) {
        //找到需要依赖的头部:  找到我们的头部视图
        for (int i = 0, z = views.size(); i < z; i++) {
            View view = views.get(i);
            if (view.getId() == R.id.fl_head) {
                return view;
            }
        }
        return null;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        offsetChild(child, dependency);

        return super.onDependentViewChanged(parent, child, dependency);
    }

    private void offsetChild(View child, View dependency) {

        //de child 移动的百分比是一样的
        /**
         * 当钱自试图滚东的距离wield:头部视图滚动的百分比滚动的范围
         */
        //能够移动的最大距离
        //int scrollRange = getScrollRange(dependency);
        child.setTranslationY(-dependency.getTranslationY() / getHeaderOffsetRange() * getScrollRange(dependency));
        Log.i("test", "translationY------------>" + child.getTranslationY());
    }


    private float getHeaderOffsetRange() {
        //让他返回-90dp,,,直接返回的话
        float height = context.getResources().getDimension(R.dimen.height);
        return -height;
    }

    /**
     * 滚动范围,,头部视图的高度就是他的滚动范围
     *
     * @param v
     * @return 指的是当前是如的滚动范围, 值得是高度变化范围
     */
    @Override
    protected int getScrollRange(View v) {
        if (v.getId() == R.id.fl_head) {
            //取最大值,
            int resule = Math.max(0, v.getMeasuredHeight() - getFinalHeight());
            return resule;
        }
        return super.getScrollRange(v);
    }

    public int getFinalHeight() {


        // context.getResources().getDimension(R.dimen.height);
        return (int) context.getResources().getDimension(R.dimen.height);//90
        //return 90;//90
    }
}

--------------------

package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.graphics.Rect;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;

import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by sszz on 2017/2/21.
 */

public abstract class HeaderScrollingViewBehavior extends ViewOffsetBehavior{
   private final Rect mTempRect1 = new Rect();
   private final Rect mTempRect2 = new Rect();

   private int mVerticalLayoutGap = 0;
   private int mOverlayTop;

   public HeaderScrollingViewBehavior() {}

   public HeaderScrollingViewBehavior(Context context, AttributeSet attrs) {
      super(context, attrs);
   }

   @Override
   public boolean onMeasureChild(CoordinatorLayout parent, View child,
                          int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
                          int heightUsed) {
      final int childLpHeight = child.getLayoutParams().height;
      if (childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
            || childLpHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
         // If the menu's height is set to match_parent/wrap_content then measure it
         // with the maximum visible height

         final List dependencies = parent.getDependencies(child);
         final View header = findFirstDependency(dependencies);
         if (header != null) {
            if (ViewCompat.getFitsSystemWindows(header)
                  && !ViewCompat.getFitsSystemWindows(child)) {
               // If the header is fitting system windows then we need to also,
               // otherwise we'll get CoL's compatible measuring
               ViewCompat.setFitsSystemWindows(child, true);

               if (ViewCompat.getFitsSystemWindows(child)) {
                  // If the set succeeded, trigger a new layout and return true
                  child.requestLayout();
                  return true;
               }
            }

            if (ViewCompat.isLaidOut(header)) {
               int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
               if (availableHeight == 0) {
                  // If the measure spec doesn't specify a size, use the current height
                  availableHeight = parent.getHeight();
               }

               final int height = availableHeight - header.getMeasuredHeight()
                     + getScrollRange(header);
               final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height,
                     childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
                           ? View.MeasureSpec.EXACTLY
                           : View.MeasureSpec.AT_MOST);

               // Now measure the scrolling view with the correct height
               parent.onMeasureChild(child, parentWidthMeasureSpec,
                     widthUsed, heightMeasureSpec, heightUsed);

               return true;
            }
         }
      }
      return false;
   }

   @Override
   protected void layoutChild(final CoordinatorLayout parent, final View child,
                        final int layoutDirection) {
      final List dependencies = parent.getDependencies(child);
      final View header = findFirstDependency(dependencies);

      if (header != null) {
         final CoordinatorLayout.LayoutParams lp =
               (CoordinatorLayout.LayoutParams) child.getLayoutParams();
         final Rect available = mTempRect1;
         available.set(parent.getPaddingLeft() + lp.leftMargin,
               header.getBottom() + lp.topMargin,
               parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
               parent.getHeight() + header.getBottom()
                     - parent.getPaddingBottom() - lp.bottomMargin);

         final Rect out = mTempRect2;
         GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
               child.getMeasuredHeight(), available, out, layoutDirection);

         final int overlap = getOverlapPixelsForOffset(header);

         child.layout(out.left, out.top - overlap, out.right, out.bottom - overlap);
         mVerticalLayoutGap = out.top - header.getBottom();
      } else {
         // If we don't have a dependency, let super handle it
         super.layoutChild(parent, child, layoutDirection);
         mVerticalLayoutGap = 0;
      }
   }

   float getOverlapRatioForOffset(final View header) {
      return 1f;
   }

   final int getOverlapPixelsForOffset(final View header) {
      return mOverlayTop == 0
            ? 0
            : MathUtils.constrain(Math.round(getOverlapRatioForOffset(header) * mOverlayTop),
            0, mOverlayTop);

   }

   private static int resolveGravity(int gravity) {
      return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
   }

   protected abstract View findFirstDependency(List views);

   protected int getScrollRange(View v) {
      return v.getMeasuredHeight();
   }

   /**
    * The gap between the top of the scrolling view and the bottom of the header layout in pixels.
    */
   final int getVerticalLayoutGap() {
      return mVerticalLayoutGap;
   }

   /**
    * Set the distance that this view should overlap any {@link AppBarLayout}.
    *
    * @param overlayTop the distance in px
    */
   public final void setOverlayTop(int overlayTop) {
      mOverlayTop = overlayTop;
   }

   /**
    * Returns the distance that this view should overlap any {@link AppBarLayout}.
    */
   public final int getOverlayTop() {
      return mOverlayTop;
   }
}
---------------------

package com.example.yangg.uc.Behavior;

/**
 * Created by sszz on 2017/2/21.
 */

public class MathUtils {
   static int constrain(int amount, int low, int high) {
      return amount < low ? low : (amount > high ? high : amount);
   }

   static float constrain(float amount, float low, float high) {
      return amount < low ? low : (amount > high ? high : amount);
   }
}
--------------
package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

import com.example.yangg.uc.R;

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

public class NewsPagerBehavior extends CoordinatorLayout.Behavior {

    private MyRunable myRunable;
    private Scroller s;
    private View child;


    public NewsPagerBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
        currentOffsetRange = -(int) context.getResources().getDimension(R.dimen.height);
    }

    /**
     * 初始化
     */
    private void init(Context context) {

        s = new Scroller(context);
    }

    //用于判断滚动方向  顺序 1   滚动之前执行的
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        this.child = child;
        //垂直滚动
        return (nestedScrollAxes == ViewGroup.SCROLL_AXIS_VERTICAL) && !isToTop(child);
    }

    private boolean isToTop(View child) {
        /**
         * ???????????
         */
        if (child.getTranslationY() == currentOffsetRange) {
            return true;
        }
        return false;
    }

    /**
     * 滚动的时候  顺序 1
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dx
     * @param dy
     * @param consumed
     */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        float tempDy = (dy / 4f);//4,,滑动慢一点

        Log.i("test", "tempDy" + tempDy);//系统监控手指
        if (!canScroll(child, tempDy)) {
            //不能滚动,,一会二处理
            if (tempDy > 0) {
                //如果用户向上移动,并已经接近上部的最大高度,则直接将视图移动到做最上部
                child.setTranslationY(currentOffsetRange);
            } else {
                //向下移动
                child.setTranslationY(0);
            }
        } else {
            /**
             * 控制viewpager移动到-90
             */
            //能移动
            child.setTranslationY(child.getTranslationY() - tempDy);
            Log.i("test", "translationY:" + child.getTranslationY());
        }

        consumed[1] = dy;
    }

    /**
     * 该方法主要用于判读newspager是否能狗移动,移动的范围i额是-90  0
     *
     * @param child
     * @param tempDy
     * @return
     */
    private boolean canScroll(View child, float tempDy) {
        //将要移动的  (将要滑动到的坐标值)
        int pendingTranslationY = (int) (child.getTranslationY() - tempDy);
        if (pendingTranslationY <= 0 && pendingTranslationY >= currentOffsetRange) {
            return true;//可以滚动
        }

        return false;
    }

    //当前的偏移量的范围 移动范围i  newspager走了多少, != 列表向上移动的距离,下面滚动的快,上面滚动的慢
    private int currentOffsetRange = -90;//定义的是坐标

    /**
     * 按理说 抬起手的时候调用,但是newpaget没有触摸,,
     * @param parent
     * @param child
     * @param ev
     * @return
     */
//    @Override
//    public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
//
//        return super.onTouchEvent(parent, child, ev);
//    }

    /**
     * 截断事件
     *
     * @param parent
     * @param child
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            handleActionUp(child);
        }
        return super.onInterceptTouchEvent(parent, child, ev);
    }
    //在头部没有完全不和的时候,要组织底部列表进入Fling状态
    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {
        return !isClosed();//返回true  类似:对事件的拦截
    }

    private void handleActionUp(View child) {
        myRunable = new MyRunable(child);
        if (child.getTranslationY() < currentOffsetRange / 2f) {

            myRunable.scrollToClose();
        } else {
            myRunable.scrollToOpen();

        }
    }



    public void open() {
        myRunable = new MyRunable(child);
        myRunable.scrollToOpen();

    }

    public boolean isClosed() {
        return child.getTranslationY() == currentOffsetRange;
    }

    private class MyRunable implements Runnable {
        private View child;

        public MyRunable(View child) {
            this.child = child;
        }

        public void scrollToClose() {
            int startY = (int) child.getTranslationY();
            int dY = currentOffsetRange - startY;
            s.startScroll(0, startY, 0, dY);
            start();
        }

        public void scrollToOpen() {
            int startY = (int) child.getTranslationY();
            s.startScroll(0, startY, 0, -startY);
            start();
        }

        private void start() {
            if (s.computeScrollOffset()) {
                //判断滚动有没有结束,用于获取新的坐标点
                child.postDelayed(this, 30);
            }

        }

        @Override
        public void run() {
            //computeScrollOffset
            if (s.computeScrollOffset()) {
                child.setTranslationY(s.getCurrY());
                child.postDelayed(this, 30);
            }
        }
    }
---------------------------------下一个类::tabBehavior
 
  
package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;

import com.example.yangg.uc.R;

import java.util.List;

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

public class tabBehavior extends HeaderScrollingViewBehavior {
    private  Context context;

    public tabBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {

        return dependency.getId() == R.id.fl_head;
    }

    @Override
    protected View findFirstDependency(List views) {
        for (int i= 0;i;i++){

            View view = views.get(i);
            if (view.getId() == R.id.fl_head){
                return view;
            }
        }
        return null;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        offsetChild(child,dependency);

        return super.onDependentViewChanged(parent, child, dependency);
    }


    private void offsetChild(View child, View dependency) {
    //随着滑动,tab便宜点额百分比和newpaget偏移的百分比相同
        float offsetRange = getFinalHeigt()-child.getTop();
        child.setTranslationY(dependency.getTranslationY() / getHeadetOffsetRange() * offsetRange) ;

    }

    private int getFinalHeigt(){
        return (int) (context.getResources().getDimension(R.dimen.height)/2);
    }

    private int getHeadetOffsetRange(){
        return -(int) (context.getResources().getDimension(R.dimen.height));
    }
}
----------------------------
--------------------------
 
  
package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;

import com.example.yangg.uc.R;

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

public class TitleBehavior extends CoordinatorLayout.Behavior {
    private  Context context;

    public TitleBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }


    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {

        return dependency.getId() == R.id.fl_head;
    }

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
//        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) (child.getLayoutParams());
//        params.topMargin = -45;
        ((CoordinatorLayout.LayoutParams)child.getLayoutParams()).topMargin = (int) - (context.getResources().getDimension(R.dimen.height)/2);
        //当修改完子试图的布局参数后,要让付布局

        parent.onLayoutChild(child,layoutDirection);
        return super.onLayoutChild(parent, child, layoutDirection);
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        offsetChikd(child,dependency);
        return super.onDependentViewChanged(parent, child, dependency);
    }

    private void offsetChikd(View child, View dependency) {

        int titleOffsetRange = (int) (context.getResources().getDimension(R.dimen.height)/2);

        child.setTranslationY(dependency.getTranslationY()/getHeaderOffsetRange()*titleOffsetRange);

    }
    private int getHeaderOffsetRange(){
        return -(int) (context.getResources().getDimension(R.dimen.height));
    }
}

-------------------------
 
  
package com.example.yangg.uc.Behavior;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by sszz on 2017/2/21.
 */

public class ViewOffsetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {

   private ViewOffsetHelper mViewOffsetHelper;

   private int mTempTopBottomOffset = 0;
   private int mTempLeftRightOffset = 0;

   public ViewOffsetBehavior() {}

   public ViewOffsetBehavior(Context context, AttributeSet attrs) {
      super(context, attrs);
   }

   @Override
   public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
      // First let lay the child out
      layoutChild(parent, child, layoutDirection);

      if (mViewOffsetHelper == null) {
         mViewOffsetHelper = new ViewOffsetHelper(child);
      }
      mViewOffsetHelper.onViewLayout();

      if (mTempTopBottomOffset != 0) {
         mViewOffsetHelper.setTopAndBottomOffset(mTempTopBottomOffset);
         mTempTopBottomOffset = 0;
      }
      if (mTempLeftRightOffset != 0) {
         mViewOffsetHelper.setLeftAndRightOffset(mTempLeftRightOffset);
         mTempLeftRightOffset = 0;
      }

      return true;
   }

   protected void layoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
      // Let the parent lay it out by default
      parent.onLayoutChild(child, layoutDirection);
   }

   public boolean setTopAndBottomOffset(int offset) {
      if (mViewOffsetHelper != null) {
         return mViewOffsetHelper.setTopAndBottomOffset(offset);
      } else {
         mTempTopBottomOffset = offset;
      }
      return false;
   }

   public boolean setLeftAndRightOffset(int offset) {
      if (mViewOffsetHelper != null) {
         return mViewOffsetHelper.setLeftAndRightOffset(offset);
      } else {
         mTempLeftRightOffset = offset;
      }
      return false;
   }

   public int getTopAndBottomOffset() {
      return mViewOffsetHelper != null ? mViewOffsetHelper.getTopAndBottomOffset() : 0;
   }

   public int getLeftAndRightOffset() {
      return mViewOffsetHelper != null ? mViewOffsetHelper.getLeftAndRightOffset() : 0;
   }
}

-----------------------
package com.example.yangg.uc.Behavior;

import android.support.v4.view.ViewCompat;
import android.view.View;

/**
 * Created by sszz on 2017/2/21.
 */

public class ViewOffsetHelper {
   private final View mView;

   private int mLayoutTop;
   private int mLayoutLeft;
   private int mOffsetTop;
   private int mOffsetLeft;

   public ViewOffsetHelper(View view) {
      mView = view;
   }

   public void onViewLayout() {
      // Now grab the intended top
      mLayoutTop = mView.getTop();
      mLayoutLeft = mView.getLeft();

      // And offset it as needed
      updateOffsets();
   }

   private void updateOffsets() {
      ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
      ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
   }

   /**
    * Set the top and bottom offset for this {@link android.support.design.widget.ViewOffsetHelper}'s view.
    *
    * @param offset the offset in px.
    * @return true if the offset has changed
    */
   public boolean setTopAndBottomOffset(int offset) {
      if (mOffsetTop != offset) {
         mOffsetTop = offset;
         updateOffsets();
         return true;
      }
      return false;
   }

   /**
    * Set the left and right offset for this {@link android.support.design.widget.ViewOffsetHelper}'s view.
    *
    * @param offset the offset in px.
    * @return true if the offset has changed
    */
   public boolean setLeftAndRightOffset(int offset) {
      if (mOffsetLeft != offset) {
         mOffsetLeft = offset;
         updateOffsets();
         return true;
      }
      return false;
   }

   public int getTopAndBottomOffset() {
      return mOffsetTop;
   }

   public int getLeftAndRightOffset() {
      return mOffsetLeft;
   }
}
 
  

你可能感兴趣的:(UC浏览器主界面滑动折叠效果 使用自定义behavior实现 难度五颗星*****)