【FastDev4Android框架开发】Android 列表下拉刷新组件PullToRefreshListView使用(三)

转载请标明出处:

//www.greatytc.com/p/1f94411af33d

本文出自:【江清清博客-代号独狼】

(一):写在前面的话

接着上一篇继续更新,上一篇文章已经把FastDev4Android项目新增图片自动无限轮播,包括项目结构已经需要进行完善的功能,那么今天我们继续完善这个项目;今天我们会再项目添加下拉刷新组件以及组件实现讲解和使用基本方法;

(二):基本实现

这边我们采用继承Listview控件来扩展下拉刷新的功能,主要在listview的头部添加一个下拉刷新的view,然后监听OnScrollListener滚动接口和实现onTouchEvent方法来处理。进行下拉listview滑动到指定的高度,然后接口回调加载刷新方法即可。

效果如下:

(三):详细实现:

这边主要看几个重点地方,详细的代码到项目中查看即可

onTouchEvent处理方法

code-lang

/

touch事件处理

@param event

@return

/

@Override

public boolean onTouchEvent(MotionEvent event) {

final int y = (int) event.getY();

switch (event.getAction()) {

case MotionEvent.ACTIONDOWN:

mLastMotionY = y;

break;

case MotionEvent.ACTIONMOVE:

int offsetY = (int) event.getY();

int deltY = Math.round(offsetY - mLastMotionY);

mLastMotionY = offsetY;

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

deltY = deltY / 2;

mRefreshOriginalTopPadding += deltY;

if (mRefreshOriginalTopPadding < -mRefreshViewHeight) {

mRefreshOriginalTopPadding = -mRefreshViewHeight;

}

resetHeaderPadding();

}

break;

case MotionEvent.ACTIONUP:

//当手指抬开得时候 进行判断下拉的距离 ,如果>=临界值,那么进行刷洗,否则回归原位

if (!isVerticalScrollBarEnabled()) {

setVerticalScrollBarEnabled(true);

}

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

if (mRefreshView.getBottom() >= mRefreshViewHeight

&& mRefreshState == RELEASETOREFRESH) {

//准备开始刷新

prepareForRefresh();

} else {

// Abort refresh

resetHeader();

}

}

break;

}

return super.onTouchEvent(event);

}

onScrooll和onScrollStateChanged处理listview滑动过程中,实时改变头部view(pull view)上面的数据效果显示:

code-lang

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

if (mCurrentScrollState == SCROLLSTATETOUCHSCROLL && mRefreshState != REFRESHING) {

if (firstVisibleItem == 0) {

if ((mRefreshView.getBottom() >= mRefreshViewHeight)

&& mRefreshState != RELEASETOREFRESH) {

mRefreshViewText.setText(R.string.pulltorefreshreleaselabelit);

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mFlipAnimation);

mRefreshState = RELEASETOREFRESH;

} else if (mRefreshView.getBottom() < mRefreshViewHeight

&& mRefreshState != PULLTOREFRESH) {

mRefreshViewText.setText(R.string.pulltorefreshpulllabelit);

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mReverseFlipAnimation);

mRefreshState = PULLTOREFRESH;

}

}

}

if (mOnScrollListener != null) {

mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);

}

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

mCurrentScrollState = scrollState;

if (mOnScrollListener != null) {

mOnScrollListener.onScrollStateChanged(view, scrollState);

}

}

使用方法如下:

code-lang

package com.chinaztt.fda.test;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.text.Layout;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.AbsListView;

import android.widget.AdapterView;

import android.widget.BaseAdapter;

import android.widget.LinearLayout;

import android.widget.ProgressBar;

import android.widget.TextView;

import com.chinaztt.fda.ui.R;

import com.chinaztt.fda.ui.base.BaseActivity;

import com.chinaztt.fda.utils.UIUtils;

import com.chinaztt.fda.widget.PullToRefreshListView;

import java.util.ArrayList;

import java.util.List;

/

当前类注释:下拉刷新,上拉加载更多组件实例

项目名:FastDev4Android

包名:com.chinaztt.fda.test

作者:江清清 on 15/10/23 11:25

邮箱:jiangqqlmj@163.com

QQ: 781931404

公司:江苏中天科技软件技术有限公司

/

public class PullListviewActivity extends BaseActivity{

private PullToRefreshListView lvpullitem;

private PullAdapter mPullAdapter;

private LayoutInflater mInflater;

private List mTitles;

private View loadmore;

private TextView loadmoretv; // listview底部加载view 显示数据

private ProgressBar loadmoreprogress; // listview底部加载view 显示进度

private LinearLayout loadnextpagelayout;

private Handler newHandler=new Handler()

{

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

if(msg.what==1){

refreshTitles();

UIUtils.savePullToRefreshLastUpdateAt(lvpullitem,UIUtils.DEMOPULLTIMEKEY);

//刷新view

mPullAdapter.notifyDataSetChanged();

}else if(msg.what==2){

moreTitles();

//刷新view

mPullAdapter.notifyDataSetChanged();

showToastMsgShort("加载更多数据成功...");

loadmoretv.setText("数据加载完成");

}

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.pulllistviewlayout);

lvpullitem=(PullToRefreshListView)this.findViewById(R.id.lvpullitem);

mInflater=getLayouInflater();

//特别注意 里边的view的控件可以根据当前的状态 修改字符串信息

loadmore = mInflater.inflate(R.layout.loadmorefootviewlayout,

null);

loadmoretv = (TextView) loadmore

.findViewById(R.id.loadnextpagetext);

loadmoreprogress = (ProgressBar) loadmore

.findViewById(R.id.loadnextpageprogress);

loadnextpagelayout = (LinearLayout) loadmore

.findViewById(R.id.loadnextpagelayout);

//listview添加尾部 上拉加载更多view

lvpullitem.addFooterView(loadmore, null, false);

loadmoretv.setText("上拉加载更多数据...");

initTitles();

//初始化 上次下拉刷新的时间

UIUtils.setPullToRefreshLastUpdated(lvpullitem,UIUtils.DEMOPULLTIMEKEY);

mPullAdapter=new PullAdapter();

lvpullitem.setAdapter(mPullAdapter);

//listview item点击事件处理

lvpullitem.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view, int position, long id) {

int index = position++;

showToastMsgShort("点击了第:" + index + "个item");

}

});

//listview 开始下拉刷新回调函数

lvpullitem.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {

@Override

public void onRefresh() {

//进行加载数据

new Thread(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(5000);

newHandler.sendEmptyMessage(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

});

//listview 滑动 进行上拉加载更多

lvpullitem.setOnScrollListener(new AbsListView.OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

if (scrollState == AbsListView.OnScrollListener.SCROLLSTATEIDLE) {

if (lvpullitem.getLastVisiblePosition() == (lvpullitem

.getCount() - 1)) {

loadmoretv.setText("正在加载最新数据....");

//进行获取最新数据

new Thread(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(5000);

newHandler.sendEmptyMessage(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

}

if (scrollState == AbsListView.OnScrollListener.SCROLLSTATEFLING) {

//正在滑动中,当前listview正在滑动 可以暂停图片加载器或者其他一些耗时操作

} else {

}

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

}

});

}

private void initTitles(){

mTitles=new ArrayList();

for(int i=0;i<20;i++){

int index=i+1;

mTitles.add("当前是:"+index+"");

}

}

private void refreshTitles(){

List newTitles=new ArrayList();

for(int i=0;i<5;i++){

int index=i+1;

newTitles.add("新数据是:"+index+"");

}

newTitles.addAll(mTitles);

mTitles.removeAll(mTitles);

mTitles.addAll(newTitles);

}

private void moreTitles(){

List newTitles=new ArrayList();

for(int i=0;i<8;i++){

int index=i+1;

newTitles.add("更多数据是:"+index+"");

}

mTitles.addAll(newTitles);

}

class PullAdapter extends BaseAdapter{

@Override

public int getCount() {

return mTitles.size();

}

@Override

public Object getItem(int position) {

return mTitles.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

HondlerHondler=null;

if(convertView==null){

Hondler=new Hondler();

convertView=mInflater.inflate(R.layout.lvmainitem,null);

Hondler.tvitem=(TextView)convertView.findViewById(R.id.tvitem);

convertView.setTag(Hondler);

}else

{

Hondler=(Hondler)convertView.getTag();

}

Hondler.tvitem.setText(mTitles.get(position));

return convertView;

}

}

static class Hondler{

TextView tvitem;

}

}

以上也是PullToRefreshListView的实现重点代码和基本使用效果,整个控件的功能实现代码如下:

code-lang

package com.chinaztt.fda.widget;

import android.content.Context;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.animation.LinearInterpolator;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

import com.chinaztt.fda.ui.R;

import com.chinaztt.fda.utils.Log;

/

当前类注释:下拉刷新,上拉加载更多组件

项目名:FastDev4Android

包名:com.chinaztt.fda.widget

作者:江清清 on 15/10/23 13:32

邮箱:jiangqqlmj@163.com

QQ: 781931404

公司:江苏中天科技软件技术有限公司

/

public class PullToRefreshListView extends ListView implements OnScrollListener, OnClickListener {

/

下拉状态

/

private static final int PULLTOREFRESH = 1; //下拉-默认为初始状态 准备下拉刷新

private static final int RELEASETOREFRESH = 2; //释放刷新

private static final int REFRESHING = 3; //正在刷新

private static final String TAG = "PullRefreshListView";

private OnRefreshListener mOnRefreshListener;

/

组件滑动监听器 scroll 当view在进行下拉滑动的时候,判断滑动的距离,

如果达到可以进行刷新的临界点时候,回调当前接口中的方法

Listener that will receive notifications every time the list scrolls.

/

private OnScrollListener mOnScrollListener;

//下拉刷新的的头部view

private LinearLayout mRefreshView;

private ImageView mRefreshViewImage;

private ProgressBar mRefreshViewProgress;

private TextView mRefreshViewText;

private TextView mRefreshViewLastUpdated;

private int mRefreshState;

private int mCurrentScrollState;

private RotateAnimation mFlipAnimation;

private RotateAnimation mReverseFlipAnimation;

private int mRefreshViewHeight;

private int mRefreshOriginalTopPadding;

private int mLastMotionY;

public PullToRefreshListView(Context context) {

super(context);

init(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

private void init(Context context) {

mFlipAnimation = new RotateAnimation(0, -180,

RotateAnimation.RELATIVETOSELF, 0.5f,

RotateAnimation.RELATIVETOSELF, 0.5f);

mFlipAnimation.setInterpolator(new LinearInterpolator());

mFlipAnimation.setDuration(250);

mFlipAnimation.setFillAfter(true);

mReverseFlipAnimation = new RotateAnimation(-180, 0,

RotateAnimation.RELATIVETOSELF, 0.5f,

RotateAnimation.RELATIVETOSELF, 0.5f);

mReverseFlipAnimation.setInterpolator(new LinearInterpolator());

mReverseFlipAnimation.setDuration(250);

mReverseFlipAnimation.setFillAfter(true);

mRefreshView = (LinearLayout) View.inflate(context, R.layout.pulltorefreshheader, null);

mRefreshViewText = (TextView) mRefreshView.findViewById(R.id.pulltorefreshtext);

mRefreshViewImage = (ImageView) mRefreshView.findViewById(R.id.pulltorefreshimage);

mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pulltorefreshprogress);

mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pulltorefreshupdatedat);

mRefreshState = PULLTOREFRESH;

mRefreshViewImage.setMinimumHeight(50); //设置下拉最小的高度为50

setFadingEdgeLength(0);

setHeaderDividersEnabled(false);

//把refreshview加入到listview的头部

addHeaderView(mRefreshView);

super.setOnScrollListener(this);

mRefreshView.setOnClickListener(this);

mRefreshView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);

mRefreshViewHeight = mRefreshView.getMeasuredHeight();

mRefreshOriginalTopPadding = -mRefreshViewHeight;

resetHeaderPadding();

}

/

Set the listener that will receive notifications every time the list scrolls.

@param l The scroll listener.

/

@Override

public void setOnScrollListener(OnScrollListener l) {

mOnScrollListener = l;

}

/

注册listview下拉刷新回到接口

Register a callback to be invoked when this list should be refreshed.

@param onRefreshListener The callback to run.

/

public void setOnRefreshListener(OnRefreshListener onRefreshListener) {

mOnRefreshListener = onRefreshListener;

}

/

进行设置设置上一次更新的时候

Set a text to represent when the list was last updated.

@param lastUpdated Last updated at.

/

public void setLastUpdated(CharSequence lastUpdated) {

if (lastUpdated != null) {

mRefreshViewLastUpdated.setVisibility(View.VISIBLE);

mRefreshViewLastUpdated.setText(lastUpdated);

} else {

mRefreshViewLastUpdated.setVisibility(View.GONE);

}

}

/

touch事件处理

@param event

@return

/

@Override

public boolean onTouchEvent(MotionEvent event) {

final int y = (int) event.getY();

switch (event.getAction()) {

case MotionEvent.ACTIONDOWN:

mLastMotionY = y;

break;

case MotionEvent.ACTIONMOVE:

int offsetY = (int) event.getY();

int deltY = Math.round(offsetY - mLastMotionY);

mLastMotionY = offsetY;

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

deltY = deltY / 2;

mRefreshOriginalTopPadding += deltY;

if (mRefreshOriginalTopPadding < -mRefreshViewHeight) {

mRefreshOriginalTopPadding = -mRefreshViewHeight;

}

resetHeaderPadding();

}

break;

case MotionEvent.ACTIONUP:

//当手指抬开得时候 进行判断下拉的距离 ,如果>=临界值,那么进行刷洗,否则回归原位

if (!isVerticalScrollBarEnabled()) {

setVerticalScrollBarEnabled(true);

}

if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {

if (mRefreshView.getBottom() >= mRefreshViewHeight

&& mRefreshState == RELEASETOREFRESH) {

//准备开始刷新

prepareForRefresh();

} else {

// Abort refresh

resetHeader();

}

}

break;

}

return super.onTouchEvent(event);

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

if (mCurrentScrollState == SCROLLSTATETOUCHSCROLL && mRefreshState != REFRESHING) {

if (firstVisibleItem == 0) {

if ((mRefreshView.getBottom() >= mRefreshViewHeight)

&& mRefreshState != RELEASETOREFRESH) {

mRefreshViewText.setText(R.string.pulltorefreshreleaselabelit);

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mFlipAnimation);

mRefreshState = RELEASETOREFRESH;

} else if (mRefreshView.getBottom() < mRefreshViewHeight

&& mRefreshState != PULLTOREFRESH) {

mRefreshViewText.setText(R.string.pulltorefreshpulllabelit);

mRefreshViewImage.clearAnimation();

mRefreshViewImage.startAnimation(mReverseFlipAnimation);

mRefreshState = PULLTOREFRESH;

}

}

}

if (mOnScrollListener != null) {

mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);

}

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

mCurrentScrollState = scrollState;

if (mOnScrollListener != null) {

mOnScrollListener.onScrollStateChanged(view, scrollState);

}

}

/

Sets the header padding back to original size.

/

private void resetHeaderPadding() {

mRefreshView.setPadding(

mRefreshView.getPaddingLeft(),

mRefreshOriginalTopPadding,

mRefreshView.getPaddingRight(),

mRefreshView.getPaddingBottom());

}

public void prepareForRefresh() {

if (mRefreshState != REFRESHING) {

mRefreshState = REFRESHING;

mRefreshOriginalTopPadding = 0;

resetHeaderPadding();

mRefreshViewImage.clearAnimation();

mRefreshViewImage.setVisibility(View.GONE);

mRefreshViewProgress.setVisibility(View.VISIBLE);

mRefreshViewText.setText(R.string.pulltorefreshrefreshinglabelit);

onRefresh();

}

}

private void resetHeader() {

mRefreshState = PULLTOREFRESH;

mRefreshOriginalTopPadding = -mRefreshViewHeight;

resetHeaderPadding();

mRefreshViewImage.clearAnimation();

mRefreshViewImage.setVisibility(View.VISIBLE);

mRefreshViewProgress.setVisibility(View.GONE);

mRefreshViewText.setText(R.string.pulltorefreshpulllabelit);

}

/

开始回调刷新

/

public void onRefresh() {

Log.d(TAG, "onRefresh");

if (mOnRefreshListener != null) {

mOnRefreshListener.onRefresh();

}

}

/

Resets the list to a normal state after a refresh.

/

public void onRefreshComplete() {

Log.d(TAG, "onRefreshComplete");

resetHeader();

}

@Override

public void onClick(View v) {

Log.d(TAG, "onClick");

}

/

Interface definition for a callback to be invoked when list should be

refreshed.

/

public interface OnRefreshListener {

/

Called when the list should be refreshed.

A call to {@link PullToRefreshListView #onRefreshComplete()} is

expected to indicate that the refresh has completed.

/

public void onRefresh();

}

}

核心实现类的代码就这些,其实整个文件读下来,实现起来也不难的吧大家可以根据上面的代码可以修改定制成自己的控件都没问题的希望可以帮助到大家,如果需要整个demo源代码可以去Github中下载整个项目:https://github.com/jiangqqlmj/FastDev4Android

同时欢迎大家star和fork整个开源快速开发框架项目如果有什么意见和反馈,欢迎留言,必定第一时间回复。也欢迎有同样兴趣的童鞋加入到该项目中来,一起维护该项目。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容