SmoothRefreshLayout
一款支持上下拉刷新、越界回弹、二级刷新、横向刷新、拉伸回弹、平滑滚动、嵌套滚动的多功能刷新控件
Install / Use
/learn @dkzwm/SmoothRefreshLayoutREADME
SmoothRefreshLayout
English | 中文
一个高效的Android刷新库,理论上支持所有的视图,比官方的SwipeRefreshLayout更强大且使用方便.
特性:
- 理论上支持所有的视图,且可根据具体需求高效适配.
- 支持多点触摸.
- 支持嵌套滑动,完整实现了NestedScrollingChild3,NestedScrollingParent3 接口,玩转CoordinatorLayout.
- 直接继承自ViewGroup,拥有卓越的性能,支持类FameLayout的特性(Gravity、Margin).
- 支持自动刷新、自动上拉加载、到底自动加载更多(不推荐,建议使用Adapter实现,可自定义到底判断逻辑回调实现预加载更多).
- 支持越界回弹,支持基于物理特性的越界回弹效果.
- 支持刷新视图自定样式:STYLE_DEFAULT(默认不改变大小)、STYLE_SCALE(动态改变大小,会在SRL内部测量并布局,所以性能会有损失)、STYLE_PIN(不会改变视图大小,固定在顶部或者底部)、STYLE_FOLLOW_SCALE(先纵向跟随移动并且不改变视图大小,大于视图高度后动态改变视图大小且性能会有损失)、STYLE_FOLLOW_PIN(不会改变视图大小,先纵向跟随移动,大于视图高度后固定)、STYLE_FOLLOW_CENTER(不会改变视图大小,先纵向跟随移动,大于视图高度后让视图保持在移动的距离中心点).
- 支持二级刷新事件(TwoLevelSmoothRefreshLayout),PS:淘宝二楼、京东活动.
- 支持横向刷新(HorizontalSmoothRefreshLayout).
- 支持ListView、GridView、RecyclerView加载更多的同步平滑滚动.
- 支持手势:同步Fling(刷新视图仍可见的情况下,会先回滚隐藏刷新视图,而后向下传递Fling手势).
- 支持作为可拉伸内部视图布局使用(类小米设置页效果).
- 丰富的回调接口和调试信息,可利用现有API实现丰富的效果.
引入
添加如下依赖到你的 build.gradle 文件:
dependencies {
implementation 'com.github.dkzwm:srl-core:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-classics:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-material:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-dynamic-rebound:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-horizontal:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-two-level:1.7.2.4'
implementation 'com.github.dkzwm:srl-ext-util:1.7.2.4'
}
演示程序
下载 Demo.apk
更新日志
老版本升级务必查看
快照

使用
在Xml中配置
<?xml version="1.0" encoding="utf-8"?>
<me.dkzwm.widget.srl.SmoothRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</me.dkzwm.widget.srl.SmoothRefreshLayout>
Java代码配置
SmoothRefreshLayout refreshLayout = (SmoothRefreshLayout)findViewById(R.id.smoothRefreshLayout);
refreshLayout.setHeaderView(new ClassicHeader(this));
refreshLayout.setOnRefreshListener(new RefreshingListenerAdapter() {
@Override
public void onRefreshing() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
refreshLayout.refreshComplete();
}
}, 4000);
}
});
自定义刷新视图
接口定义
public interface IRefreshView <T extends IIndicator> {
byte TYPE_HEADER = 0;
byte TYPE_FOOTER = 1;
byte STYLE_DEFAULT = 0;
byte STYLE_SCALE = 1;
byte STYLE_PIN = 2;
byte STYLE_FOLLOW_SCALE = 3;
byte STYLE_FOLLOW_PIN = 4;
byte STYLE_FOLLOW_CENTER = 5;
/**
* 返回是头部视图还是尾部视图;
*/
int getType();
/**
* 一般情况都是View实现本接口,所以返回this;
*/
View getView();
/**
* 获取视图样式,自1.4.8版本后支持6种样式,STYLE_DEFAULT、STYLE_SCALE、STYLE_PIN、STYLE_FOLLOW_SCALE、STYLE_FOLLOW_PIN、STYLE_FOLLOW_CENTER;
*/
int getStyle();
/**
* 获取视图的自定义高度,当视图样式为STYLE_SCALE和STYLE_FOLLOW_SCALE时,必须返回一个确切且大于0的值,使用横向刷新库时,该属性实际应该返回的是视图的宽度;
* 自1.6.1版本开始,如果想要当前视图铺满布局即MATCH_PARENT,那么支持返回ViewGroup.LayoutParams.MATCH_PARENT对应的值即`-1`;
*/
int getCustomHeight();
/**
* 手指离开屏幕;
*/
void onFingerUp(SmoothRefreshLayout layout, T indicator);
/**
* 重置视图;
*/
void onReset(SmoothRefreshLayout layout);
/**
* 重新配置视图,准备刷新;
*/
void onRefreshPrepare(SmoothRefreshLayout layout);
/**
* 开始刷新;
*/
void onRefreshBegin(SmoothRefreshLayout layout, T indicator);
/**
* 刷新完成;
*/
void onRefreshComplete(SmoothRefreshLayout layout,boolean isSuccessful);
/**
* 当头部或者尾部视图发生位置变化;
*/
void onRefreshPositionChanged(SmoothRefreshLayout layout, byte status, T indicator);
/**
* 当头部或者尾部视图仍然处于处理事务中,这时候移动其他刷新视图则会调用该方法;
* 在1.4.6版本新加入;
*/
void onPureScrollPositionChanged(SmoothRefreshLayout layout, byte status, T indicator);
}
添加自定义刷新视图
- 全局静态代码构造
SmoothRefreshLayout.setDefaultCreator(new IRefreshViewCreator() {
@Override
public IRefreshView<IIndicator> createHeader(SmoothRefreshLayout layout) {
ClassicHeader header = new ClassicHeader(layout.getContext());
return header;
}
@Override
public IRefreshView<IIndicator> createFooter(SmoothRefreshLayout layout) {
ClassicFooter footer = new ClassicFooter(layout.getContext());
return footer;
}
});
- 动态代码添加
ClassicHeader header = new ClassicHeader(mRefreshLayout.getContext());
mRefreshLayout.setHeaderView(header);
ClassicFooter footer = new ClassicFooter(mRefreshLayout.getContext());
mRefreshLayout.setFooterView(footer);
- 请直接写入Xml文件,SmoothRefreshLayout会根据添加的View是否是实现了IRefreshView接口进行判断
实现类QQ下拉阻尼效果
mRefreshLayout.setIndicatorOffsetCalculator(new IIndicator.IOffsetCalculator() {
@Override
public float calculate(@IIndicator.MovingStatus int status, int currentPos, float offset) {
if (status == IIndicator.MOVING_HEADER) {
if (offset < 0) {
//如果希望拖动缩回时类似QQ一样没有阻尼效果,阻尼效果只存在于下拉则可以在此返回offset
//如果希望拖动缩回时类似QQ一样有阻尼效果,那么请注释掉这个判断语句
return offset;
}
return (float) Math.pow(Math.pow(currentPos / 2, 1.28d) + offset, 1 / 1.28d) * 2 - currentPos;
} else if (status == IIndicator.MOVING_FOOTER) {
if (offset > 0) {
//如果希望拖动缩回时类似QQ一样没有阻尼效果,阻尼效果只存在于上拉则可以在此返回offset
//如果希望拖动缩回时类似QQ一样有阻尼效果,那么请注释掉这个判断语句
return offset;
}
return -((float) Math.pow(Math.pow(currentPos / 2, 1.28d) - offset, 1 / 1.28d) * 2 - currentPos);
} else {
if (offset > 0) {
return (float) Math.pow(offset, 1 / 1.28d) * 2;
} else if (offset < 0) {
return -(float) Math.pow(-offset, 1 / 1.28d) * 2;
} else {
return offset;
}
}
}
});
Xml属性
SmoothRefreshLayout 自身配置
|名称|类型|描述|
|:---:|:---:|:---:|
|sr_content|reference|指定内容视图的资源ID|
|sr_resistance|float|移动刷新视图时候的移动阻尼(默认:1.65f)|
|sr_resistanceOfFooter|float|移动Footer视图时候的移动阻尼(默认:1.65f)|
|sr_resistanceOfHeader|float|移动Header视图时候的移动阻尼(默认:1.65f)|
|sr_ratioToRefresh|float|触发刷新时位置占刷新视图的高度比(默认:1f)|
|sr_ratioOfHeaderToRefresh|float|触发刷新时位置占Header视图的高度比(默认:1f)|
|sr_ratioOfFooterToRefresh|float|触发加载更多时位置占Footer视图的高度比(默认:1f)|
|sr_ratioToKeep|float|刷新中保持视图位置占刷新视图的高度比(默认:1f),该属性的值必须小于等于触发刷新高度比才会有效果|
|sr_ratioToKeepHeader|float|刷新中保持视图位置占Header视图的高度比(默认:1f),该属性的值必须小于等于触发刷新高度比才会有效果|
|sr_ratioToKeepFooter|float|刷新中保持视图位置占Footer视图的高度比(默认:1f),该属性的值必须小于等于触发刷新高度比才会有效果|
|sr_maxMoveRatio|float|最大移动距离占刷新视图的高度比(默认:0f,表示不会触发)|
|sr_maxMoveRatioOfHeader|float|最大移动距离占Header视图的高度比(默认:0f,表示不会触发)|
|sr_maxMoveRatioOfFooter|float|最大移动距离占Footer视图的高度比(默认:0f,表示不会触发)|
|sr_closeDuration|integer|指定收缩刷新视图到起始位置的时长(默认:350)|
|sr_closeHeaderDuration|integer|指定收缩Header视图到起始位置的时长(默认:350)|
|sr_closeFooterDuration|integer|指定收缩Footer视图到起始位置的时长(默认:350)|
|sr_backToKeepDuration|integer|设置回滚到保持刷新视图位置的时间(默认:200)|
|sr_backToKeepHeaderDuration|integer|设置回滚到保持Header视图位置的时间(默认:200)|
|sr_backToKeepFooterDuration|integer|设置回滚到保持Footer视图位置的时间(默认:200)|
|sr_enablePinContent|boolean|固定内容视图(默认:false)|
|sr_enableKeep|boolean|刷新中保持视图停留在所设置的应该停留的位置(默认:true)|
|sr_enablePullToRefresh|boolean|拉动刷新,下拉或者上拉到触发刷新位置即立即触发刷新(默认:false)|
|sr_enableOverScroll|boolean|越界回弹(默认:true)|
|sr_enableRefresh|boolean|设置是否启用下拉刷新(默认:ture)|
|sr_enableLoadMore|boolean|设置是否启用加载更多(默认:false)|
|sr_mode|enum|模式设置(默认:MODE_DEFAULT为刷新控件模式)|
|sr_stickyHeader|reference|指定黏贴头部的资源ID|
|sr_stickyFooter|reference|指定黏贴尾部的资源ID|
TwoLevelSmoothRefreshLayout 自身配置
|名称|类型|描述|
|:---:|:---:|:---:|
|sr_enableTwoLevelRefresh|boolean|设置是否启用二级刷新(默认:true)|
|sr_backToKeep2Duration|boolean|设置回滚到保持二级刷新头部处于二级刷新过程中的时长(默认:500)|
|sr_closeHeader2Duration|boolean|设置关闭二级刷新头部的时长(默认:500)|
SmoothRefreshLayout包裹内部其他View支持配置
|名称|类型|描述| |:---:|:---:|:---:| |layout_gravity|flag|指定其它被包裹视图的对齐属性(非 targetView、非refreshView)|
SmoothRefreshLayout java属性设置方法
|名称|参数|描述|
|:---:|:---:|:---:|
|setHeaderView|IRefreshView|配置头部视图|
|setFooterView|IRefreshView|配置尾部视图|
|setContentView|View|配置内容视图|
|setMode|int|配置当前模式|
|setLayoutManager|LayoutManager|配置自定义布局管理器|
|setDisableWhenAnotherDirectionMove|boolean|内部视图含有其他方向滑动视图时需设置该属性为ture(默认:false)|
|setMaxOverScrollDuration|int|设置越界回弹动画最长时间(默认:350)|
|setMinOverScrollDuration|int|设置越界回弹动画最短时间(默认:100)|
|setResistance|float|移动刷新视图时候的移动阻尼(默认:1.65f)|
|setResistanceOfFooter|float|移动Footer视图时候的移动阻尼(默认:1.65f)|
|setResistanceOfHeader|float|移动Header视图时候的移动阻尼(默认:1.65f)|
|setRatioToRefresh|float|触发刷新时位置占刷新视图的高度比(默认:1.1f)|
|setRatioOfHeaderToRefresh|float|触发刷新时位置占Header视图的高度比(默认:1.1f)|
|setRatioOfFooterToRefresh|float|触发加载更多时位置


