轉載請標明出處:
http://www.lxweimin.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整個開源快速開發框架項目如果有什么意見和反饋,歡迎留言,必定第一時間回復。也歡迎有同樣興趣的童鞋加入到該項目中來,一起維護該項目。