金田

下拉刷新是一种比较常用的效果,Android 5.0之前官方并未提供类似的控件,App中主要是用的第三方库,例如PullToRefresh,ActionBar-PullToRefresh等。刚好现在项目中需要处理 Android 5.0 材质设计部分的东西,就顺带学习下这部分。

大体介绍一下;

  1. SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新控件 (android-support-v4.jar)
  2. 目前只支持下拉刷新,不支持上拉加载更多的操作(需要自行进行扩展)
  3. 作为官方自带的控件,相对能能够保证比较好的通用性及风格(这里不包括各种自家定制的系统 L)
  4. SwipeRefreshLayout继承于ViewGroup,ViewGroup中可以包含其他不同控件,so UI定制起来也相对比较容易
  5. 使用起来比较方便,可以很容易的实现Google Now的刷新效果

SwipeRefreshLayout布局中目前只能包含一个子布局,使用侦听机制来通知刷新事件。例如当用户使用下拉手势时,SwipeRefreshLayout会触发OnRefreshListener,然后刷新事件会在onRefresh()方法中进行处理。当需要结束刷新的时候,可以调用setRefreshing(false)。如果要禁用手势和进度动画,调用setEnabled(false)即可。

接下来介绍一下其大体使用方法:

1.布局文件(示例代码)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" > <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/id_explore_swipe_ly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffff" > <ListView
android:id="@+id/id_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>

2.java逻辑代码:

首先需要实现 SwipeRefreshLayout.OnRefreshListener  接口,然后重写方法 onRefresh():

@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() { @Override
public void run() {
// 设置SwipeRefreshLayout当前是否处于刷新状态,一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
mSwipeRefreshLayout.setRefreshing(false);
}
}, 3000);
}

现在我们初始化该控件:

public void initSwipeRefreshParameters() {
// 设置进度条的颜色变化,最多可以设置4种颜色
mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
android.R.color.holo_orange_light, android.R.color.holo_red_light);
// 设置下拉监听,当用户下拉的时候会去执行回调
mSwipeRefreshLayout.setOnRefreshListener(this);
// 调整进度条距离屏幕顶部的距离
mSwipeRefreshLayout.setProgressViewOffset(false, 0,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));
}

以上是基本用法,现在来大体介绍一下定制支持上拉加载的部分,演示图示:

图1 上拉加载效果示意图

首先实现SwipeRefreshLayout的重写:

public class mySwipeRefreshLayout extends SwipeRefreshLayout implements OnScrollListener {

    private int mTouchSlop;
private ListView mListView;
private OnLoadListener mOnLoadListener;
private View mListViewFooter;
private int mYDown;
private int mLastY;
private boolean isLoading = false; public mySwipeRefreshLayout(Context context) {
this(context, null);
} public mySwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, null, false);
} @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom); // 初始化ListView对象
if (mListView == null) {
getListView();
}
} private void getListView() {
int childs = getChildCount();
if (childs > 0) {
View childView = getChildAt(0);
if (childView instanceof ListView) {
mListView = (ListView) childView;
// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载
mListView.setOnScrollListener(this);
}
}
} public void setListView(ListView list) {
this.mListView = list;
setLoading(true);
this.mListView.setOnScrollListener(this);
} @Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction(); switch (action) {
case MotionEvent.ACTION_DOWN:
mYDown = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
mLastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
if (canLoad()) {
loadData();
}
break;
default:
break;
} return super.dispatchTouchEvent(event);
} /**
* @方法说明:是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.
*/
private boolean canLoad() {
return isBottom() && !isLoading && isPullUp();
} /**
* @方法说明:判断是否到了最底部
*/
private boolean isBottom() {
if (mListView != null && mListView.getAdapter() != null) {
return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);
}
return false;
} /**
* @方法说明:是否是上拉操作
*/
private boolean isPullUp() {
return (mYDown - mLastY) >= mTouchSlop;
} /**
* @方法说明: 如果到了最底部,而且是上拉操作.那么执行onLoad方法
*/
private void loadData() {
if (mOnLoadListener != null) {
mOnLoadListener.onLoad();
}
// 设置状态
setLoading(true);
} /**
* @方法说明:设置刷新
*/
public void setLoading(boolean loading) {
isLoading = loading;
if (mListView != null && mListView.getFooterViewsCount() > 0)
mListView.removeFooterView(mListViewFooter);
if (isLoading) {
if (mListView != null && mListView.getFooterViewsCount() <= 0)
mListView.addFooterView(mListViewFooter);
} else {
mYDown = 0;
mLastY = 0;
}
} public void setOnLoadListener(OnLoadListener loadListener) {
mOnLoadListener = loadListener;
} @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (isFastDoubleClick(100))
return; // 滚动时到了最底部也可以加载更多
isLoading = false;
if (canLoad()) {
loadData();
}
} public View getmListViewFooter() {
return mListViewFooter;
} /**
* @类描述:加载更多的监听器
*/
public static interface OnLoadListener {
public void onLoad();
} private static long lastClickTime; public static boolean isFastDoubleClick(long times) {
long time = System.currentTimeMillis();
long timeD = time - lastClickTime;
if (0 < timeD && timeD < times) {
return true;
}
lastClickTime = time;
return false;
}
}

MainActivity.java

public class MainActivity extends Activity {
private mydapter adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.main);
adapter = new mydapter(); // 获取RefreshLayout实例
final mySwipeRefreshLayout myRefreshListView = (mySwipeRefreshLayout) findViewById(R.id.swipe_layout); // 获取listview实例
ListView listView = (ListView) findViewById(R.id.listview);
myRefreshListView.setListView(listView);
listView.setAdapter(adapter); // 设置进度条的颜色变化,最多可以设置4种颜色
myRefreshListView.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
android.R.color.holo_orange_light, android.R.color.holo_red_light);
// 设置下拉刷新监听器
myRefreshListView.setOnRefreshListener(new OnRefreshListener() { @Override
public void onRefresh() {
Toast.makeText(MainActivity.this, "refresh", Toast.LENGTH_SHORT).show();
myRefreshListView.postDelayed(new Runnable() { @Override
public void run() {
// 更新完后调用该方法结束刷新
myRefreshListView.setRefreshing(false); adapter.getData().clear();
// 模拟一些数据
for (int i = 0; i < 20; i++) {
adapter.addData("liu hhh " + i);
}
}
}, 1000);
}
}); // 加载监听器
myRefreshListView.setOnLoadListener(new OnLoadListener() { @Override
public void onLoad() {
myRefreshListView.postDelayed(new Runnable() {
@Override
public void run() {
// 加载完后调用该方法
adapter.addData(new Date().toGMTString());
adapter.notifyDataSetChanged();
myRefreshListView.setLoading(false);
}
}, 1500);
}
});
} class mydapter extends BaseAdapter {
List<String> datas = new ArrayList<String>(); public mydapter() {
// 模拟一些数据
for (int i = 0; i < 20; i++) {
datas.add("item - " + i);
}
} public void setData(List<String> data) {
this.datas = data;
notifyDataSetChanged();
} public void addData(String str) {
this.datas.add(str);
notifyDataSetChanged();
} public List<String> getData() {
return datas;
} @Override
public int getCount() {
return datas.size();
} @Override
public Object getItem(int position) {
return datas.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = MainActivity.this.getLayoutInflater().inflate(R.layout.item, null);
} TextView tv = (TextView) convertView.findViewById(R.id.text);
tv.setText(datas.get(position)); return convertView;
}
}
}

listView_footer:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/very_light_gray"
android:gravity="center"
android:layout_gravity="center_horizontal"
android:paddingBottom="10dip"
android:paddingTop="10dip" > <ProgressBar
android:id="@+id/pull_to_refresh_load_progress"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:indeterminate="true"
android:paddingRight="10dp" /> <TextView
android:id="@+id/pull_to_refresh_loadmore_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_toRightOf="@+id/pull_to_refresh_load_progress"
android:paddingTop="5dip"
android:text="@string/loading"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@android:color/darker_gray"
android:textSize="14sp"
android:textStyle="bold" /> </RelativeLayout>

main.xml

<?xml version="1.0" encoding="utf-8"?>
<com.example.demo.mySwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swipe_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" > <ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView> </com.example.demo.mySwipeRefreshLayout>

item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:padding="10dp"
android:text="wo lai le"
android:background="@color/very_light_gray"/> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/white"/> </LinearLayout>

参考链接

http://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

版权所有,转载须注明作者(金田)及出处(原文

Android 5.0 之SwipeRefreshLayout的更多相关文章

  1. Android下拉刷新-SwipeRefreshLayout,RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout)

    SwipeRefrshLayout是Google官方更新的一个Widget,可以实现下拉刷新的效果.该控件集成自ViewGroup在support-v4兼容包下,不过我们需要升级supportlibr ...

  2. 【Android - V】之SwipeRefreshLayout的使用

    SwipeRefreshLayout是Android V4.V7包中的一个控件,是Google给我们提供的一个下拉刷新的布局控件,可以轻松完成下拉刷新. SwipeRefreshLayout的特点是其 ...

  3. Android下拉刷新-SwipeRefreshLayout

    现在市面上新闻类的App基本上都有下拉刷新,算是一个标配吧,网上关于下拉刷新的博客也有很多,实现方式可以使用开源的PullToRefresh,自定义ListView,或者可以直接使用LineLayOu ...

  4. android 5.0新特性学习总结之下拉刷新(一)

    android 5.0 后google最终在 support v4 包下 添加了下拉刷新的控件 项目地址: https://github.com/stormzhang/SwipeRefreshLayo ...

  5. Android下拉刷新SwipeRefreshLayout简单用法

    之前一直都想用下拉刷新,感觉上是庞大的工程,所以搁置了.现在学习了一下其实真的超级简单. 看了<第一行代码>以及 https://www.jianshu.com/p/3c402a9e4b7 ...

  6. Android数据存储之Android 6.0运行时权限下文件存储的思考

    前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...

  7. Android权限管理之RxPermission解决Android 6.0 适配问题

    前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...

  8. Android权限管理之Android 6.0运行时权限及解决办法

    前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...

  9. Android 5.0 到 Android 6.0 + 的深坑之一 之 .so 动态库的适配

    (原创:http://www.cnblogs.com/linguanh) 目录: 前序 一,问题描述 二,为何会如此"无情"? 三,目前存在该问题的知名SDK 四,解决方案,1 对 ...

随机推荐

  1. 【深入了解cocos2d-x 3.x】定时器(scheduler)的使用和原理探究(3)

    上篇文章分析到了定时器的定义.这篇的重点就是定时器是怎样执行起来的. 1.从main中寻找定时器的回调 讲定时器的执行,就不得不触及到cocos2dx的main函数了,由于定时器是主线程上执行的.并非 ...

  2. 27个Jupyter快捷键、技巧(原英文版)

    本文是转发自:https://www.dataquest.io/blog/jupyter-notebook-tips-tricks-shortcuts/ 的一篇文章,先记录在此,等有空时我会翻译成中文 ...

  3. LA 6448 Credit Card Payment

      [题目] 你的信用卡目前欠M元,每月的汇率是R,每月的利息要四舍五入为小数点后两位,你每月还B元,问多少月能还清. 输入 先是T代表测试数据组数 接下来T行,每行有三个实数,R,M,B每个实数小数 ...

  4. Python迭代--笔记

    <python3 程序开发指南> 迭代子.迭代操作 迭代子是一个对象,该对象可提供_next_()方法,该方法依次返回每个相继的数据项,并在没有数据项时产生StopIteration()异 ...

  5. 跨域信息传递postMessage

    var sendToParent = function(event, data, listener) { var message = { event: event, data: data, liste ...

  6. Wcf序列化的循环引用问题1

    1.Wcf数据契约序列化,使用的类DataContractSerializer 默认如果类不指定[DataContract],则序列化类的所有字段,并且在出现循环引用的时候回抛出异常,服务终止 msd ...

  7. (转)精通 JS正则表达式

    精通 JS正则表达式 (精通?标题党 ) 正则表达式可以: •测试字符串的某个模式.例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式.这称为数据有效性验证  ...

  8. PL/SQL客户端安装配置说明

    一.电脑安装了多个Oracle客户端时,需要设定pl/sql 中的home 二.配置环境变量: (打开环境变量配置界面操作:我的电脑---属性---高级---环境变量,在系统变量部分新建或编辑即可.w ...

  9. 安装VS2010后,如何设置老版本的项目文件不是默认用VS2010打开

    1.系统先后安装了VS2008和VS2010,在打开用VS2008创建的项目文件时总是会默认用VS2010打开,选择打开方式都不行,很不方便,差点要把VS2010卸载了.     其实只需要简单设置V ...

  10. 关于char与varchar,varchar2的区别

    http://zhidao.baidu.com/question/220360696.html?qbl=relate_question_0&word=char%BA%CDvarchar2%B5 ...