先看效果

123.gif

package com.tospur.exmind.testrecycerviewwithtopandbottomrefresh.refresh;

import android.content.Context;

import android.graphics.Rect;

import android.support.design.widget.CoordinatorLayout;

import android.support.v4.view.ViewCompat;

import android.util.AttributeSet;

import android.util.Log;

import android.util.TypedValue;

import android.view.View;

/**

* Created by lehow on 2017/2/20.

* 内容摘要:

* 版权所有:极策科技

*/

public class PullRefreshBehavior extends CoordinatorLayout.Behavior {

private static final String TAG = "PullRefreshBehavior";

private static int HEADER_MIN_HEIGTH = 0;

private float default_pull_trans_y=0;

public PullRefreshBehavior(Context context, AttributeSet attrs) {

super(context, attrs);

HEADER_MIN_HEIGTH = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 72 * 2, context.getResources().getDisplayMetrics());

}

@Override

public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {

Log.i(TAG, "onLayoutChild: ");

int indexOfChild = parent.indexOfChild(child);

// super.onLayoutChild(parent, child, layoutDirection);

int childCount = parent.getChildCount();

int topOffset = parent.getTop();

for (int i = 0; i < childCount; i++) {

View childAt = parent.getChildAt(i);

if (childAt == child){

childAt.layout(0, 0, parent.getWidth(), 0 + Math.abs(childAt.getMeasuredHeight()));//需要这行,否则child不显示

}

childAt.setTranslationY(topOffset);

if (i == childCount - 1) {//最后一个,调整他的高度,防止向上滚动到底,scrollview的内容显示不全

int w = View.MeasureSpec.makeMeasureSpec(parent.getWidth(),View.MeasureSpec.EXACTLY);

int h = View.MeasureSpec.makeMeasureSpec(parent.getHeight()-HEADER_MIN_HEIGTH,View.MeasureSpec.EXACTLY);

childAt.measure(w,h);

default_pull_trans_y=childAt.getTranslationY();

// childAt.layout(0, 0, parent.getWidth(), parent.getHeight()-HEADER_MIN_HEIGTH);

}

if (i == indexOfChild) {//当前的pullview不显示,所以后面的偏移不应该累加他的高度

continue;

}

topOffset += childAt.getMeasuredHeight();

}

return true;

}

@Override

public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {

Log.i(TAG, "==onStartNestedScroll: ");

return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;

//coordinatorLayout 在此处判断 如果是垂直方向的滚,我就要先接收着看一看

}

@Override

public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {

super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);

Log.i(TAG, "onNestedPreScroll: dx="+dx+" dy="+dy);

//target 为滚动控件

//target.getTranslationY() > HEADER_MIN_HEIGTH; 滚动控件与

int targetHeaderOffest = (int) (target.getTranslationY() - HEADER_MIN_HEIGTH);

if (dy > 0 && targetHeaderOffest > 0) {//向上移动,并且与最小的Header距离大于0,先整体向上滚动

int childCount = coordinatorLayout.getChildCount();

int indexOfChild = coordinatorLayout.indexOfChild(child);

int scollY = Math.min(targetHeaderOffest, dy);

for (int i = 0; i < childCount; i++) {

View childAt = coordinatorLayout.getChildAt(i);

if (i <=indexOfChild) {//固定在顶部

} else {//移动pullview之后的控件

childAt.setTranslationY(childAt.getTranslationY() - scollY);

}

}

consumed[1] = scollY;//更新coordinatorLayout消耗的距离

}

}

@Override

public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {

super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);

Log.i(TAG, "onNestedScroll: dxConsumed="+dxConsumed+" dyConsumed="+dyConsumed+" dxUnconsumed="+dxUnconsumed+" dyUnconsumed="+dyUnconsumed);

if (dyConsumed<=0&&dyUnconsumed<0){//向下滚动,有剩余的,整体向下滚动

int childCount = coordinatorLayout.getChildCount();

int indexOfChild = coordinatorLayout.indexOfChild(child);

for (int i = 0; i < childCount; i++) {

View childAt = coordinatorLayout.getChildAt(i);

if (i <=indexOfChild) {//固定在顶部

} else {//pullview之下的控件之间移动就好

childAt.setTranslationY(childAt.getTranslationY() - dyUnconsumed);

}

}

}

}

@Override

public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {

super.onStopNestedScroll(coordinatorLayout, child, target);

float offsetToDefault = target.getTranslationY() - default_pull_trans_y;

if (offsetToDefault>0) {

int childCount = coordinatorLayout.getChildCount();

int indexOfChild = coordinatorLayout.indexOfChild(child);

for (int i = 0; i < childCount; i++) {

View childAt = coordinatorLayout.getChildAt(i);

if (i <=indexOfChild) {//固定在顶部

} else {//回弹

childAt.setTranslationY(childAt.getTranslationY() - (offsetToDefault));

}

}

}

}

@Override

public boolean onRequestChildRectangleOnScreen(CoordinatorLayout coordinatorLayout, View child, Rect rectangle, boolean immediate) {

return super.onRequestChildRectangleOnScreen(coordinatorLayout, child, rectangle, immediate);

}

}

onLayoutChild

主要处理了pillview之下控件的偏移问题,因为CoordinatorLayout默认是层叠的方式布局,所以利用setTranslationY把布局错开。同时调整了scrollview的高度为折叠后的最大高度,防止内容少的时候,没有沾满整个空间,和内容过多,向上滚动到头的时候,内容显示不完整。

onNestedPreScroll

主要处理向上滚动时,先整体向上滚动到折叠的最小状态,然后才是scrollview自己的内容滚动

onNestedScroll

先让scrollview自己的内容滚动,然后再整体滚动,实现下拉效果

onStopNestedScroll

处理滚动回弹问题

MyCoordinatorLayout 处理了toolbar置顶的问题和,下面控件向上滚动会覆盖toolbar的问题

package com.tospur.exmind.testrecycerviewwithtopandbottomrefresh.refresh;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.support.design.widget.CoordinatorLayout;

import android.util.AttributeSet;

import android.util.Log;

import android.util.TypedValue;

import android.view.View;

import com.tospur.exmind.testrecycerviewwithtopandbottomrefresh.R;

/**

* Created by lehow on 2017/2/23.

* 内容摘要:

* 版权所有:极策科技

*/

public class MyCoordinatorLayout extends CoordinatorLayout{

//处理顶部toolbar区域置顶的效果

private int fixed_num = 0;

private int HEADER_FIXED_HEIGTH = 0;

public MyCoordinatorLayout(Context context) {

this(context, null);

}

public MyCoordinatorLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public MyCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

TypedArray a = context.obtainStyledAttributes(attrs,

R.styleable.MyCoordinatorLayout);

fixed_num = a.getInteger(

R.styleable.MyCoordinatorLayout_fix_num, 0);

a.recycle();

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

HEADER_FIXED_HEIGTH = 0;

for (int i=0;i

HEADER_FIXED_HEIGTH += getChildAt(i).getMeasuredHeight();

}

}

@Override

protected boolean drawChild(Canvas canvas, View child, long drawingTime) {

Log.i("MyCoordinatorLayout", "drawChild: "+child);

if (indexOfChild(child)>= fixed_num) {//非置顶项,裁剪置顶的高度

canvas.clipRect(0, HEADER_FIXED_HEIGTH - child.getTop(), canvas.getWidth(), canvas.getHeight());

}

return super.drawChild(canvas, child, drawingTime);

}

}

布局结构

xmlns:tools="http://schemas.android.com/tools"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:id="@+id/activity_refresh"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:fix_num="1"

tools:context="com.tospur.exmind.testrecycerviewwithtopandbottomrefresh.refresh.RefreshActivity">

android:layout_width="match_parent"

android:layout_height="72dp"

android:background="#ff0"

android:id="@+id/toolbar"

>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#f00"

android:orientation="vertical"

app:layout_behavior="com.tospur.exmind.testrecycerviewwithtopandbottomrefresh.refresh.PullRefreshBehavior"

>

android:id="@+id/pull_text_view"

android:layout_gravity="bottom|center_horizontal"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="下拉刷新"

android:textSize="24sp"

android:textColor="#fff"

/>

android:layout_width="match_parent"

android:layout_height="220dp"

android:src="@mipmap/test"

android:adjustViewBounds="true"

android:scaleType="fitCenter"

/>

android:layout_width="match_parent"

android:layout_height="72dp"

android:background="#00f"

android:orientation="vertical"

>

android:gravity="center"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:text="过滤条件"

android:textColor="#fff"

android:textSize="24sp"

/>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#0f0"

>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/my_txt"

/>

当然,只实现到了下拉回弹,下拉刷新的逻辑还有很多,初步已经写放弃了,有时间我再接着写,因为我突然想到另一种方式去实现。

在这里我只给下拉刷新所在的LinearLayout 指定了Behavior,而这个LinearLayout 本身不接收事件也不支持嵌套滚动,而他的Behavior确是可以接收到NestedScrollView触发的滚动事件的。也就是说Behavior可以绑定在任何CoordinatorLayout的直接子view上,而其他view触发的嵌套滚动事件,该Behavior都有机会接收到。

这就是为啥AppBarLayout的default Behavior能接收到 其他NestedView的嵌套滚动事件,而不用自己触发,自己会拦截在其上的touch事件作消耗处理,发生在其他控件上的nested事件则通过Behavior来监听。

android 5 .0下拉回弹,自定义CoordinatorLayout.Behavior 实现下拉回弹相关推荐

  1. Android:自定义CoordinatorLayout.behavior 简单的仿UC首页

    CoordinatorLayout顾名思义协调布局,是用来协调该布局下的子控件,最简单地使用就是头部伸缩和折叠了,配合着TabLayout,只需要设置一下AppBarLayout子控件的layout_ ...

  2. android 5.1 flash,Flash Player for Android 4.0 and 5.1 以上版本(提供下載)

    城哥說: Flash Player for Android 4.0 and 4.3 arc... 恕刪 Android 2.3版 進入手機"設置"->"應用程式&q ...

  3. Android 4.0的图形硬件加速及绘制技巧

    [51CTO独家特稿]从Android 3.0开始,Android 2D的绘制流程就设计为能够更好地支持硬件加速.使用GPU的View在Canvas上进行画的操作时都会使用硬件加速.在最新的Andro ...

  4. android sdk版本8.0,把targetSdkVersion设置为26(Android 8.0)需要注意的地方

    前言 由于项目要上应用宝,必须设置targetSdk>=26,所以把以前项目的targetSdk=22的改成了26,要开始处理Android 6.0的动态权限,7.0的FileProvider, ...

  5. Android 8.0学习(5)---模块化内核

    模块化内核要求 在 Android 8.0 中,设备内核分为系统芯片 (SoC).设备和板专属组件.基于这种分层结构的内核和 Android 使得原始设计制造商 (ODM) 和原始设备制造商 (OEM ...

  6. Android 7.0 ----- Direct Boot模式(AppClock)

    本文针对闹钟应用对于此次Android 7.0增加DB模式所需要的应对方式. Direct Boot模式:设备已开机但用户尚未解锁设备时,Android 7.0 将在安全的"直接启动&quo ...

  7. Android 8.0正式发布 奥利奥新功能惊人

    尽管 Android 刷版本号的步伐年年加快,但每年带给用户的惊喜从未减少.经历了四个开发者预览版的洗礼后,Android 8.0 终于在今天凌晨迎来了正式版发布. 如果你还不清楚 Android O ...

  8. 诺基亚 android 7.0,在中国首发! 诺基亚两款Android 7.0新机曝光:一大一小

    对于老粉丝来说,等来诺基亚安卓手机应该不会是太遥远的事情了,不过只是贴牌生产的它,真的还有入手的必要吗?现在,最新的消息称,诺基亚准备的两款安卓手机预计最快年底前发布,其完全由富士康设计和生产,定位高 ...

  9. Android自定义下拉刷新动画--仿百度外卖下拉刷新

    好久没写博客了,小编之前一段时间一直在找工作,从天津来到了我们的大帝都,感觉还不错.好了废话不多说了,开始我们今天的主题吧.现如今的APP各式各样,同样也带来了各种需求,一个下拉刷新都能玩出花样了,前 ...

最新文章

  1. 常用的Linux服务器各项性能指标查看方法!
  2. 公共基础选择题—关系代数和范式
  3. 嵌入式Linux学习问题解决记录
  4. 第1章 Qt概述和下载安装及创建工程
  5. Java数据结构和算法(六)——前缀、中缀、后缀表达式
  6. oracle学习笔记5:pl/sql流程控制语句
  7. java正则表达式性能_译:Java 中的正则表达式性能概述
  8. java.exe闪退_Tomcat7.0 exe闪退问题
  9. android studio创建构造方法,使用Android studio创建你的第一个项目
  10. 移动互联网时代,学iOS开发好吗
  11. java画一只小猫程序代码_android 汤姆猫动画源码(主要就是模仿汤姆猫点击小猫给反应)...
  12. 最新浅析java源代码转换为机器码的编译执行过程
  13. mysql驱动5.1_mysql jdbc 驱动 5.1.26 官方最新版
  14. VMware激活密钥
  15. 【Web 开发】第1章 概论
  16. 分享 27 个面向开发人员的最佳 Vue.js 开发工具
  17. 王道数据结构代码---第五章:二叉树(重要)
  18. 浅谈对于机器学习的理解
  19. 微信公众号内,实现下载 PDF 文件。
  20. Response.setContentType类型按文件扩展名首字母分类大全

热门文章

  1. JAVA中获取字段信息的方法
  2. 48所大学!20考研计算机/软件专业课变化的大学名单!
  3. Hostapd Configuration Guide
  4. Java程序设计(Java9版):第0章 绪论(Introduction)
  5. java uml建模_Java开源UML建模
  6. 懒逼 神经所 蒲慕明_中科院神经所所长蒲慕明:在祖国的工作是最大的贡献
  7. OpenCV(C++)---调整图像亮度和对比度
  8. 在OFFICE2007中如何编辑PPT模板!
  9. 模拟电影胶片、梦幻系列、喜怒无常的电影胶片、Lightroom预设合集【61】
  10. SpringCloud从入门到精通(超详细文档二)