gesture-refresh-layout
[] (https://jitpack.io/#Bvin/gesture-refresh-layout)
Android gesture refresh layout.
Swipe Gesture
- Both Translate, content and refresh view both translate, refresh view is next to content view transition.
- Content Translate, just translate content view.
- Refresher Translate, just translate refresh view.
- Both Fixed, content and refresh view both are fixed.
Usage
<GestureRefreshLayout>
<ContentView />
<RefreshView />
</GestureRefreshLayout>
java example code:
mGestureRefreshLayout = (GestureRefreshLayout) findViewById(R.id.gesture_refresh_layout);
mGestureRefreshLayout.setEnabled(false);//false disable gesture refrehsh,else enable
mGestureRefreshLayout.setTranslateContent(false);//false to pin refreshview,other side move contentview
mGestureRefreshLayout.setOnRefreshListener(new GestureRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// do something.
mGestureRefreshLayout.setRefreshing(false);
// after close refresh.
}
});
mGestureRefreshLayout.setOnGestureChangeListener(new GestureRefreshLayout.OnGestureStateChangeListener() {
@Override
public void onStartDrag(float startY) {
mRefreshText.setText("pull to refresh");
}
@Override
public void onDragging(float draggedDistance, float releaseDistance) {
//rotate angle: 360*draggedDistance/releaseDistance
mProgressBar.setProgress((int) (draggedDistance/releaseDistance*100));
Log.d(TAG, "onDragging: "+draggedDistance+","+releaseDistance);
if (draggedDistance>releaseDistance){
mRefreshText.setText("release to update");
}else {
mRefreshText.setText("refreshing...");
}
}
@Override
public void onFinishDrag(float endY) {
mRefreshText.setText("update...");
}
});
trigger refresh any where:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.refresh) {
mGestureRefreshLayout.setRefreshing(true);
}
return super.onOptionsItemSelected(item);
}
Installation
First, in your project's build.gradle add the jitpack.io repository like this:
allprojects {
repositories {
...
jcenter()
maven { url "https://jitpack.io" }
}
}
Note: do not add the jitpack.io repository under buildscript.
Then, add the following dependency to your module's build.gradle file:
dependencies {
...
compile 'com.github.bvin:gesture-refresh-layout:0.1.7'
}
If you want to get the latest feature, you can find that release the end with letter "d"(the code on dev branch), example "com.github.bvin:gesture-refresh-layout:0.1.4d".The stable version is no end w ith letter "d".
If in your module already has support-v4 dependency, you should exclude the inner support module, li ke this:
compile ('com.github.bvin:gesture-refresh-layout:0.1.4d') {
exclude group: 'com.android.support', module: 'support-compat'
}
中文版
Android 手势刷新布局
滑动手势
- 同步位移,即刷新视图跟随内容纵向位移,适合宽屏刷新视图。
- 悬浮位移,即内容视图固定,刷新视图跟着手势纵向位移,适合沉浸式刷新。
- 内容下潜位移,刷新视图固定,内容视图跟着手势纵向位移,这种情况一般是刷新视图会有吸引人的动画。
- 不位移,内容和刷新视图都不随手势位移,虽然纵向固定,但是可以通过其他形式来表现刷新行为。
安装
首先,在项目根目录的 build.gradle 中添加 JitPack 远程仓库如下:
allprojects {
repositories {
...
jcenter()
maven { url "https://jitpack.io" }
}
}
注意:不要把 JitPack 的仓库地址放在 buildscript 里面,否则会出现无法解析远程依赖的错误。
然后,再你需要使用的 Module 中的 build.gradle 添加以下依赖:
dependencies {
...
compile 'com.github.bvin:gesture-refresh-layout:0.1.7'
}
如果需要最新的功能,可以依赖以 d 结尾的在 dev 分支上发布的 Tag,如 "com.github.bvin:gesture-refresh-layout:0. 1.4d",稳定版是不以字母 d 结尾的。
如果你的 module 中已经有 support-v4 依赖,应该去除内部的 module,如下:
compile ('com.github.bvin:gesture-refresh-layout:0.1.7') {
exclude group: 'com.android.support', module: 'support-compat'
}
用法
通常可以在 GestureRefreshLayout 布局里面添加子视图来实现刷新功能,第一个应为内容视图,第二个应为刷新视图。
<GestureRefreshLayout>
<ContentView />
<RefreshView />
</GestureRefreshLayout>
可以设置 GestureRefreshLayout.OnRefreshListener 监听器来判断什么时候执行刷新操作(如异步请求),操作完 成后应通过 mGestureRefreshLayout.setRefreshing(false)方法来通知操作完毕以让视图回到初始位置。注意,一 定要在 UI 线程调用 mGestureRefreshLayout.setRefreshing(false)方法。
mGestureRefreshLayout.setOnRefreshListener(new GestureRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// do something.
mGestureRefreshLayout.setRefreshing(false);
// after close refresh.
}
});
GestureRefreshLayout 支持手势刷新,也支持主动触发刷新。例如可以在选项菜单添加刷新按钮或者在一进入页面 自动执行刷新操作。这一特性很多情况是非常受用的,比如点击顶部刷新呢,或者用于电视,电视一般是没有触屏 的,这是主动刷新却是很实用的功能。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.refresh) {
mGestureRefreshLayout.setRefreshing(true);
}
return super.onOptionsItemSelected(item);
}
同时如果你不想手势滑动触发刷新,只需要调用 setEnable(false)方法就可以禁用。
mGestureRefreshLayout.setEnabled(false);
GestureRefreshLayout 默认是以 RefreshView 的高度作为释放刷新的距离(即当下拉出屏幕一个 RefreshView 的高度 就会触发刷新动作),如果你的 RefreshView 的高度小于默认高度或者大于 3 倍默认高度,将会以默认下拉高度作为 释放刷新距离,当然也可以完全自定义释放刷新的距离。
mGestureRefreshLayout.setDistanceToTriggerSync(120);
高级用法
GestureRefreshLayout 的强大之处是可以非常个性化得定制刷新效果。通过 GestureChange 手势状态改变监听器可以 定制任何你想要的效果,OnGestureStateChangeListener 接口有下列 3 个状态回掉。
- onStartDrag(float startY) 开始滑动
- onDragging(float draggedDistance, float releaseDistance) 滑动中
onFinishDrag(float endY) 滑动结束 可以根据不同状态下的不同参数值制定不同效果,如简单的刷新文字可以根据状态改变修改,其他动画可以根据 onDragging 的两个参数比例值来完成旋转或者进度动画。
mGestureRefreshLayout.setOnGestureChangeListener(new GestureRefreshLayout.OnGestureStateChangeListener() { @Override public void onStartDrag(float startY) { mRefreshText.setText("下拉刷新"); } @Override public void onDragging(float draggedDistance, float releaseDistance) { //rotate angle: 360*draggedDistance/releaseDistance mProgressBar.setProgress((int) (draggedDistance/releaseDistance*100)); Log.d(TAG, "onDragging: "+draggedDistance+","+releaseDistance); if (draggedDistance>releaseDistance){ mRefreshText.setText("释放更新"); }else { mRefreshText.setText("下拉刷新..."); } // 超过定义的同步距离就意味着可以释放刷新了 } @Override public void onFinishDrag(float endY) { mRefreshText.setText("正在更新..."); } });
自定义动画效果演示:
为了保持结构简洁、用法简单,GestureRefreshLayout 只提供基础手势滑动动画,其他任何表现刷新的动画和提示 都需自己实现。
实现原理
原生 SwipeRefreshLayout 的 ChildView 的宽高会强制 match_parent,而我们的 GestureRefreshLayout 可以支持 Child View 为 wrap_content。宽度不足 match_parent 的 RefreshView 将会处于水平居中位置,未来可提供 gravity 和 margin 的支持。
至于为何 SRL(即 SwipeRefreshLayout,以下通称 SRL)会这样做,我猜测是因为 SRL 把触摸事件 从 ChildView 拦截到 SRL 自身去做事件处理,它原生是可以从 ChildView 的区域滑出到 SRL 自身的区域,Touche 事件可 以无缝衔接,虽然...但是 SRL 和 ChildView 是没有间隙的,是严丝合缝的。而 GRL(即 GestureRefreshLayout,以下通 称 GRL)的 ContentView 是可以支持 wrap_content 的,就算你的 ChildView 小到比 TouchSlop 还小,依然可以在 ChildView 外的 GRL 区域起作用。
+--------------------+ ------> OriginOffsetTop
| [Refresh View] |
|____________________|
| |
| |
| <----------------> | ------> TotalDragDistance/SpinnerOffsetEnd
| [Content View] |
| ------- == ------- | ------> CurrentOffsetTop
| |
| |
| |
| |
| |
| |
| |
| |
+--------------------+
- 用户可以定义下拉的 OffsetStart,OffsetEnd,其中 OffsetStart 是 RefreshView 初始位置,刷新完成或者取消下 拉刷新都会回到这个位置,便于隐藏;其中 OffsetEnd 是下拉的相对距离(CurrentOffsetTop)超过了释放刷新的距 离,需要回到一个位置等待执行事务,通常事务完成后需要回到初始位置。
- TotalDragDistance 是触发刷新的滑动距离边界值,超过这个值就开始刷新,否则当作取消。可以通过当前滑 动的距离与这个值的比例设定一个 progress,这个是非常有用的,比如说你要旋转角度、改变透明度或者给定一个 ProgressBar 的进度值。