基本原理

上拉加载或者说滚动到底部时自动加载,都是通过判断是否滚动到了ListView或者其他View的底部,然后触发相应的操作,这里我们以 ListView来说明。因此我们需要在监听ListView的滚动事件,当ListView滚动到底部时自动触发加载操作;但是当用户支持手指滑动屏 幕,没有滚动时,我们也需要让它加载,因此这种情形就是上拉加载更多。所以我们需要在触摸事件里面进行判断,如果到了底部,且用户是上拉操作,那么执行加 载更多。

时间有限,直接上代码吧。

实现代码

/**
* 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.
*
* @author mrsimple
*/
public class RefreshLayout extends SwipeRefreshLayout implements OnScrollListener { /**
* 滑动到最下面时的上拉操作
*/ private int mTouchSlop;
/**
* listview实例
*/
private ListView mListView; /**
* 上拉监听器, 到了最底部的上拉加载操作
*/
private OnLoadListener mOnLoadListener; /**
* ListView的加载中footer
*/
private View mListViewFooter; /**
* 按下时的y坐标
*/
private int mYDown;
/**
* 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉
*/
private int mLastY;
/**
* 是否在加载中 ( 上拉加载更多 )
*/
private boolean isLoading = false; /**
* @param context
*/
public RefreshLayout(Context context) {
this(context, null);
} public RefreshLayout(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();
}
} /**
* 获取ListView对象
*/
private void getListView() {
int childs = getChildCount();
if (childs > 0) {
View childView = getChildAt(0);
if (childView instanceof ListView) {
mListView = (ListView) childView;
// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载
mListView.setOnScrollListener(this);
Log.d(VIEW_LOG_TAG, "### 找到listview");
}
}
} /*
* (non-Javadoc)
* @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)
*/
@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不在加载中, 且为上拉操作.
*
* @return
*/
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;
} /**
* 是否是上拉操作
*
* @return
*/
private boolean isPullUp() {
return (mYDown - mLastY) >= mTouchSlop;
} /**
* 如果到了最底部,而且是上拉操作.那么执行onLoad方法
*/
private void loadData() {
if (mOnLoadListener != null) {
// 设置状态
setLoading(true);
//
mOnLoadListener.onLoad();
}
} /**
* @param loading
*/
public void setLoading(boolean loading) {
isLoading = loading;
if (isLoading) {
mListView.addFooterView(mListViewFooter);
} else {
mListView.removeFooterView(mListViewFooter);
mYDown = 0;
mLastY = 0;
}
} /**
* @param loadListener
*/
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 (canLoad()) {
loadData();
}
} /**
* 加载更多的监听器
*
* @author mrsimple
*/
public static interface OnLoadListener {
public void onLoad();
}
}

listview_footer.xml:

<?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/umeng_comm_comments_bg"
android:gravity="center"
android:paddingBottom="8dip"
android:paddingTop="5dip" > <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_centerVertical="true"
android:layout_centerHorizontal="true"
android:paddingRight="100dp"
android:indeterminate="true" /> <TextView
android:id="@+id/pull_to_refresh_loadmore_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingTop="5dip"
android:text="@string/load"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@android:color/darker_gray"
android:textSize="14sp"
android:textStyle="bold" /> </RelativeLayout>

使用示例

refresh.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<myview.RefreshLayout 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> </myview.RefreshLayout>

activity中的使用 :

/**
* @author mrsimple
*/
public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.refresh); // 模拟一些数据
final List<String> datas = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
datas.add("item - " + i);
} // 构造适配器
final BaseAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
datas);
// 获取listview实例
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter); // 获取RefreshLayout实例
final RefreshLayout myRefreshListView = (RefreshLayout)
findViewById(R.id.swipe_layout); // 设置下拉刷新时的颜色值,颜色值需要定义在xml中
myRefreshListView
.setColorScheme(R.color.umeng_comm_text_topic_light_color,
R.color.umeng_comm_yellow, R.color.umeng_comm_green,
R.color.umeng_comm_linked_text);
// 设置下拉刷新监听器
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() {
// 更新数据
datas.add(new Date().toGMTString());
adapter.notifyDataSetChanged();
// 更新完后调用该方法结束刷新
myRefreshListView.setRefreshing(false);
}
}, 1000);
}
}); // 加载监听器
myRefreshListView.setOnLoadListener(new OnLoadListener() { @Override
public void onLoad() { Toast.makeText(MainActivity.this, "load", Toast.LENGTH_SHORT).show(); myRefreshListView.postDelayed(new Runnable() { @Override
public void run() {
datas.add(new Date().toGMTString());
adapter.notifyDataSetChanged();
// 加载完后调用该方法
myRefreshListView.setLoading(false);
}
}, 1500); }
});
} }

效果图

Android利用V4包中的SwipeRefreshLayout实现上拉加载的更多相关文章

  1. Android中自定义ListView实现上拉加载更多和下拉刷新

    ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能.这里我就简单记录一下实现过程. 实现这个功能的方法不止一个,Gi ...

  2. SwipeRefreshLayout实现上拉加载

    原来的Android SDK中并没有下拉刷新组件,但是这个组件确实绝大多数APP必备的一个部件.好在google在v4包中出了一个SwipeRefreshLayout,但是这个组件只支持下拉刷新,不支 ...

  3. SwipeRefreshLayout实现上拉加载下拉刷新

    package com.example.swiperefreshlayoutdemo; import java.util.ArrayList;import java.util.HashMap; imp ...

  4. 在vue中运用mt-loadmore 实现上拉加载,下拉刷新(完整源码)

    <template> <div class="serverList"> <ul class="scrollModeBox" :st ...

  5. 在vue中运用mt-loadmore 实现上拉加载,下拉刷新

    元旦了,给手残党直接复制的机会,代码如下: 1. :style="{'-webkit-overflow-scrolling': scrollMode}" 最外层div设置,以便兼容 ...

  6. SwipeRefreshLayout详解和自定义上拉加载更多

    个人主页 演示Demo下载 本文重点介绍了SwipeRefreshLayout的使用和自定View继承SwipeRefreshLayout添加上拉加载更多的功能. 介绍之前,先来看一下SwipeRef ...

  7. Android简易实战教程--第四十三话《上拉加载与下拉刷新》

    ListView的下拉刷新很常见,很多开源的框架都能做到这个效果,当然也可以自己去实现.本篇案例是基于xlistview的. 布局: <RelativeLayout xmlns:android= ...

  8. dropload.js(上拉加载插件使用过程中遇到的坑)

    dropload.js相关介绍和使用以及demo下载详见:https://github.com/ximan/dropload (原文出处) 之前因为项目需要一个上拉加载的效果,然后无意中看到了此插件, ...

  9. android 支持上拉加载,下拉刷新的列表控件SwipeRefreshLayout的二次封装

    上拉加载,下拉刷新的列表控件,大家一定都封装过,或者使用过 源代码,我会在最后贴出来 这篇代码主要是为了解决两个问题 1.滑动冲突得问题 2.listview无数据时,无数据布局的展示问题 下方列出的 ...

随机推荐

  1. Underscore 整体架构浅析

    前言 终于,楼主的「Underscore 源码解读系列」underscore-analysis 即将进入尾声,关注下 timeline 会发现楼主最近加快了解读速度.十一月,多事之秋,最近好多事情搞的 ...

  2. C#常用异常类记录

    从MSDN抄下来的 ArgumentException 传递到方法的非空参数是无效的. ArgumentNullException  传递给方法的参数为空. ArgumentOutOfRangeExc ...

  3. [故障处理]联想笔记本故障0x0000007B

    同事笔记本故障,莫名其妙的快捷方式就找不到了.开始程序中的内容也无法正常查看. 解决步骤: 1.怀疑用户配置的问题,新建一个用户,没有解决. 2.使用自带的一键恢复ThinkVantage,恢复后,重 ...

  4. AngularJS 全局scope与Isolate scope通信

    在项目开发时,全局scope 和 directive本地scope使用范围不够清晰,全局scope与directive本地scope通信掌握的不够透彻,这里对全局scope 和 directive本地 ...

  5. Objective C 基础

    1,字符串加@: 不加@的是C语言字符串. 加@的代表的是OC的NSString http://www.jikexueyuan.com/course/71_2.html 2,setValuesForK ...

  6. mysql之触发器before和after的区别(2)

    我们先做个测试: 接上篇日志建的商品表g和订单表o和触发器 假设:假设商品表有商品1,数量是10: 我们往订单表插入一条记录: insert into o(gid,much) values(1,20) ...

  7. [转载]Android开发常用调试技术记录

    ANDROID 调试技术: 1)Ps 指令 ls –l /proc/27/ cat /proc/27/cmdline       #cmdline文件表示了这个进程所在的命令行. cat /proc/ ...

  8. CentOS下安装两个或多个Tomcat7

    链接地址:http://lcbk.net/tomcat/1407.html 首先安装JDK 安装之前检查下是否已经安装了openJDK,如果已安装,建议用yum remove 卸载掉. [root@b ...

  9. 重定向如何携带cookie

    起因 最近在做微信开放平台,需要给第三方入住,而且入住方都有自己的二级域名.做过微信开发的人都知道,坑爹的是微信并不支持这种二级域名的方式,所以用一个域名专门来处理. 问题 然后由于采用了一个专门的域 ...

  10. golang build 的简单用法.(菜鸟初学)

    1. golang 里面的 go build 可以编译代码. go build helloworld.go 2. 这里面有一个注意事项事项. 如果引用非go语言的 内置package的话 需要在环境变 ...