标签:
注:本文demo已经提交github,地址完整代码如下,demo工程已经上传至GitHub,
github地址https://github.com/wsclwps123/UpLoadSwipeRefreshLayout
感谢大家支持!
在Android开发中,我们经常会用到列表下拉刷新和上拉加载的功能。
Google在support.v4包中提供了一个组件可以用来进行下来刷新,这个组件是SwipeRefreshLayout。
下面我们来看一下这个组件的使用:
在布局文件中加上xml代码
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</android.support.v4.widget.SwipeRefreshLayout>
在MainActivity.java代码中添加代码:
/**
* 添加变量
* /
private SwipeRefreshLayout swipeRefreshLayout;
private ListView listView;
private ArrayList<String> list = new ArrayList<>();
private ArrayAdapter<String> adapter;
在Activity的onCreate方法中初始化实例
/**
* 实例化变量,此处省略initList()方法
* 此方法内容为添加了N个字符串"item"
*/
initList();
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
listView = (ListView) findViewById(R.id.list_view);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
listView.setAdapter(adapter);
接下来给SwipeRefreshLayout添加OnRefreshListener监听
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Toast.makeText(MainActivity.this, "is refreshing!", Toast.LENGTH_SHORT).show();
}
});
运行效果如图所示
但是在日常开发中,我们不仅需要下拉刷新的功能,还应该有上拉继续加载的功能,但是Google并没有给我们提供上拉加载的方法,那怎么办呢?我们可以自定义一个View,自己添加上拉加载方法。
我们模仿Swiperefreshlayout的使用下拉刷新的方法,去设计上拉加载的方法。添加了上拉加载的代码形式大约为
view.setOnLoadListener(new OnLoadListener() {
@Override
public void onLoad() {
//在此执行上拉加载的逻辑
view.setloading(false); //逻辑执行完毕后停止上拉加载
}
});
所以,我们在重写下拉刷新组件前先写一个接口OnLoadListener
public interface OnLoadListener {
public void onLoad(); //需要用户重写的方法
}
我们写一个UpLoadSwipeRefreshLayout类,继承SwipeRefershLayout类。我们应该在什么时候开始上拉加载呢?当然是在子ListView滑动到最底部的时候,所以,我们可以开始进行上拉加载的时候应该满足一下条件:
① 判断listview已经滑动到了最底部
② 判断手指是在向上滑动
③ 当前上拉加载不正在进行
编写类
代码如下:
public class UpLoadSwipeRefreshLayout extends SwipeRefreshLayout {
private ListView mListView; //子view
private boolean isCanLoading = false; //是否正可以加载,默认不可用
private OnLoadListener mOnLoadListener;
private View mFooterView; //上拉加载的视图
private int firstY;
private int lastY;
private int mTouchSlop; //最短的滑动距离
private int footerResource; //加载视图的资源ID
public UpLoadSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); //获取系统默认的最短滑动距离
}
}
因为ListView是此组件的子view,那么我们应该在开始的时候去检测,子view是否是listview。
重写onLayout()方法,获取子类
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mListView == null) {
getListView(); //获取子view
}
}
构造一个getListView方法
private void getListView() {
int childs = getChildCount();
if (childs > 0) {
View childView = getChildAt(0); //获取第一个子view
if (childView instanceof ListView) {
/**
* 如果子view的类型是ListView
*/
mListView = (ListView) childView;
//给子listview设置滑动监听
mListView.setOnScrollListener(this);
}
}
}
重写事件拦截事件,防止滑动事件发生冲突
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
/**
* 获得触摸事件刚刚开始的时候,手指触摸的坐标
*/
firstY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
/**
* 获得触摸事件结束的时候,手指离开时候的坐标
*/
lastY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_UP:
if (isCanLoad()) {
loadData();
}
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
为了获取子listview的滑动情况,使用我们应该让组件实现OnScrollListener接口。
即
class UpLoadSwipeRefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
/**
* 重写滑动时间
* /
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (isCanLoad()) {
/**
* 滑动过程中如果可以加载数据
* 就执行加载数据的函数
*/
loadData();
}
}
}
编写isCanLoad()方法,这里就用到了上方我们需要满足的三个条件
private boolean isCanLoad() {
return isBottom() && isPushUp() && !isCanLoading;
}
依次编写2个方法
/**
* 判断listview是否到了底部
*/
private boolean isBottom() {
if (mListView != null && mListView.getAdapter() != null) {
/**
* 当前可加的最后一项就是listview的末尾项
* 说明滑动到了最底部
*/
return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);
}
return false;
}
/**
* 判断是否正在上拉
*/
private boolean isPushUp() {
/**
* 往上滑动的距离大于系统默认的滑动距离
*/
return firstY - lastY >= mTouchSlop;
}
这时候我们还需要编写loadData()方法
/**
* 加载数据
*/
private void loadData() {
if (mOnLoadListener != null) {
setLoading(true);
/**
* 处理加载的逻辑
* 具体逻辑在回调中完成
*/
mOnLoadListener.onLoad();
}
}
编写设置可加载的方法setLoading()
public void setLoading(boolean isCanLoad) {
this.isCanLoading = isCanLoad;
if (isCanLoad == true) {
/**
* 加载,添加底部的正在加载视图
*/
mListView.addFooterView(mFooterView);
} else {
/**
* 不在加载中,将底部的加载中视图移除
*/
mListView.removeFooterView(mFooterView);
firstY = 0;
lastY = 0;
}
}
对了,还没添加设置上拉加载监听的方法!
编写setOnUpLoadListener()方法
public void setOnLoadListener(OnLoadListener onLoadListener) {
this.mOnLoadListener = onLoadListener;
}
这个类我对外提供了一个变量,代表listview的底视图的资源id
可以通过setFooterResource方法进行添加并实例化此底部view
编写此方法
public void setFooterResource(int footerResource) {
this.footerResource = footerResource;
/**
* 实例化布局view
*/
this.mFooterView = LayoutInflater.from(getContext()).inflate(footerResource, null, false);
}
这时候这个类我们就编写好了,完整的代码我会在博客的结尾放出。
我们先来看看这段代码的使用
将刚才的布局文件修改成如下:
<com.example.chenglei.myapplication.UpLoadSwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"</ListView>
</com.example.chenglei.myapplication.UpLoadSwipeRefreshLayout>
添加尾视图的资源id文件,layout_up_load_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/white">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="horizontal">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:indeterminateDuration="1500" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="5dp"
android:gravity="center"
android:text="正在加载中..." />
</LinearLayout>
</RelativeLayout>
修改MainActivity.java的代码
swipeRefreshLayout.setFooterResource(R.layout.layout_up_load_view); //添加正在加载中的视图
swipeRefreshLayout.setOnLoadListener(new OnLoadListener() {
@Override
public void onLoad() {
//上拉加载的操作
}
});
运行效果如图:
完整代码如下,demo工程已经上传至GitHub
github地址https://github.com/wsclwps123/UpLoadSwipeRefreshLayout
package com.example.chenglei.myapplication;
import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ListView;
/**
* Created by chenglei on 2016/4/20.
* 重写下拉刷新组件,添加上拉加载的功能
*/
public class UpLoadSwipeRefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener {
private ListView mListView; //子view
private boolean isCanLoading = false; //是否正可以加载,默认不可用
private OnLoadListener mOnLoadListener;
private View mFooterView; //上拉加载的视图
private int firstY;
private int lastY;
private int mTouchSlop; //最短的滑动距离
private int footerResource;
public UpLoadSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); //获取系统默认的最短滑动距离
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mListView == null) {
getListView();
}
}
/**
* 获取子view
*/
private void getListView() {
int childs = getChildCount();
if (childs > 0) {
View childView = getChildAt(0); //获取第一个子view
if (childView instanceof ListView) {
/**
* 如果子view的类型是ListView
*/
mListView = (ListView) childView;
//给子listview设置滑动监听
mListView.setOnScrollListener(this);
}
}
}
/**
* 触摸事件拦截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
/**
* 获得触摸事件刚刚开始的时候,手指触摸的坐标
*/
firstY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
/**
* 获得触摸事件结束的时候,手指离开时候的坐标
*/
lastY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_UP:
if (isCanLoad()) {
loadData();
}
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
/**
* 判断是否可以进行加载
*/
private boolean isCanLoad() {
return isBottom() && isPushUp() && !isCanLoading;
}
/**
* 判断listview是否到了底部
*/
private boolean isBottom() {
if (mListView != null && mListView.getAdapter() != null) {
/**
* 当前可加的最后一项就是listview的末尾项
* 说明滑动到了最底部
*/
return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);
}
return false;
}
/**
* 判断是否正在上拉
*/
private boolean isPushUp() {
/**
* 往上滑动的距离大于系统默认的滑动距离
*/
return firstY - lastY >= mTouchSlop;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (isCanLoad()) {
/**
* 滑动过程中如果可以加载数据
* 就执行加载数据的函数
*/
loadData();
}
}
/**
* 加载数据
*/
private void loadData() {
if (mOnLoadListener != null) {
setLoading(true);
/**
* 处理加载的逻辑
* 具体逻辑在回调中完成
*/
mOnLoadListener.onLoad();
}
}
/**
* 设置可加载
*/
public void setLoading(boolean isCanLoad) {
this.isCanLoading = isCanLoad;
if (isCanLoad == true) {
/**
* 加载,添加底部的正在加载视图
*/
mListView.addFooterView(mFooterView);
} else {
/**
* 不在加载中,将底部的加载中视图移除
*/
mListView.removeFooterView(mFooterView);
firstY = 0;
lastY = 0;
}
}
/**
* 设置上拉加载监听
*/
public void setOnLoadListener(OnLoadListener onLoadListener) {
this.mOnLoadListener = onLoadListener;
}
/**
* 设置上拉加载的布局
*/
public void setFooterResource(int footerResource) {
this.footerResource = footerResource;
/**
* 实例化布局view
*/
this.mFooterView = LayoutInflater.from(getContext()).inflate(footerResource, null, false);
}
}
标签:
原文地址:http://blog.csdn.net/u014044853/article/details/51208390