android 5 .0下拉回弹,自定义CoordinatorLayout.Behavior 实现下拉回弹
先看效果
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 实现下拉回弹相关推荐
- Android:自定义CoordinatorLayout.behavior 简单的仿UC首页
CoordinatorLayout顾名思义协调布局,是用来协调该布局下的子控件,最简单地使用就是头部伸缩和折叠了,配合着TabLayout,只需要设置一下AppBarLayout子控件的layout_ ...
- 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 ...
- Android 4.0的图形硬件加速及绘制技巧
[51CTO独家特稿]从Android 3.0开始,Android 2D的绘制流程就设计为能够更好地支持硬件加速.使用GPU的View在Canvas上进行画的操作时都会使用硬件加速.在最新的Andro ...
- android sdk版本8.0,把targetSdkVersion设置为26(Android 8.0)需要注意的地方
前言 由于项目要上应用宝,必须设置targetSdk>=26,所以把以前项目的targetSdk=22的改成了26,要开始处理Android 6.0的动态权限,7.0的FileProvider, ...
- Android 8.0学习(5)---模块化内核
模块化内核要求 在 Android 8.0 中,设备内核分为系统芯片 (SoC).设备和板专属组件.基于这种分层结构的内核和 Android 使得原始设计制造商 (ODM) 和原始设备制造商 (OEM ...
- Android 7.0 ----- Direct Boot模式(AppClock)
本文针对闹钟应用对于此次Android 7.0增加DB模式所需要的应对方式. Direct Boot模式:设备已开机但用户尚未解锁设备时,Android 7.0 将在安全的"直接启动&quo ...
- Android 8.0正式发布 奥利奥新功能惊人
尽管 Android 刷版本号的步伐年年加快,但每年带给用户的惊喜从未减少.经历了四个开发者预览版的洗礼后,Android 8.0 终于在今天凌晨迎来了正式版发布. 如果你还不清楚 Android O ...
- 诺基亚 android 7.0,在中国首发! 诺基亚两款Android 7.0新机曝光:一大一小
对于老粉丝来说,等来诺基亚安卓手机应该不会是太遥远的事情了,不过只是贴牌生产的它,真的还有入手的必要吗?现在,最新的消息称,诺基亚准备的两款安卓手机预计最快年底前发布,其完全由富士康设计和生产,定位高 ...
- Android自定义下拉刷新动画--仿百度外卖下拉刷新
好久没写博客了,小编之前一段时间一直在找工作,从天津来到了我们的大帝都,感觉还不错.好了废话不多说了,开始我们今天的主题吧.现如今的APP各式各样,同样也带来了各种需求,一个下拉刷新都能玩出花样了,前 ...
最新文章
- 常用的Linux服务器各项性能指标查看方法!
- 公共基础选择题—关系代数和范式
- 嵌入式Linux学习问题解决记录
- 第1章 Qt概述和下载安装及创建工程
- Java数据结构和算法(六)——前缀、中缀、后缀表达式
- oracle学习笔记5:pl/sql流程控制语句
- java正则表达式性能_译:Java 中的正则表达式性能概述
- java.exe闪退_Tomcat7.0 exe闪退问题
- android studio创建构造方法,使用Android studio创建你的第一个项目
- 移动互联网时代,学iOS开发好吗
- java画一只小猫程序代码_android 汤姆猫动画源码(主要就是模仿汤姆猫点击小猫给反应)...
- 最新浅析java源代码转换为机器码的编译执行过程
- mysql驱动5.1_mysql jdbc 驱动 5.1.26 官方最新版
- VMware激活密钥
- 【Web 开发】第1章 概论
- 分享 27 个面向开发人员的最佳 Vue.js 开发工具
- 王道数据结构代码---第五章:二叉树(重要)
- 浅谈对于机器学习的理解
- 微信公众号内,实现下载 PDF 文件。
- Response.setContentType类型按文件扩展名首字母分类大全
热门文章
- JAVA中获取字段信息的方法
- 48所大学!20考研计算机/软件专业课变化的大学名单!
- Hostapd Configuration Guide
- Java程序设计(Java9版):第0章 绪论(Introduction)
- java uml建模_Java开源UML建模
- 懒逼 神经所 蒲慕明_中科院神经所所长蒲慕明:在祖国的工作是最大的贡献
- OpenCV(C++)---调整图像亮度和对比度
- 在OFFICE2007中如何编辑PPT模板!
- 模拟电影胶片、梦幻系列、喜怒无常的电影胶片、Lightroom预设合集【61】
- SpringCloud从入门到精通(超详细文档二)