首页 > 代码库 > 【安卓笔记】下拉刷新组件的使用及实现
【安卓笔记】下拉刷新组件的使用及实现
项目中如果需要实现下拉刷新一般有以下几个选择:
1.使用开源库Android-pullToRefresh。
2.使用support.v4包提供的SwipeRefreshLayout。
3.自己实现一个。
下面分别简单介绍:
注:以listView下拉刷新为例.
方案1:使用开源库Android-pullToRefresh
1.下载Android-PullToRefresh开源库(https://github.com/chrisbanes/Android-PullToRefresh)
2.将library工程导入到eclipse中
3.创建一个新工程,并在properties->android选项中引用library库
4.编写代码
该库提供了PullToRefreshListView,我们用它替换ListView,它在使用上跟ListView一致。
但是其提供了一个监听下拉更新的接口,我们通过setOnRefreshListener注册该监听器,然后在onRefresh回调方法中异步更新数据即可,更新完成后需调用onRefreshComplete方法完成更新。
示例:
页面布局:
listView的item布局:
<RelativeLayout 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" tools:context="com.example.flushlistview.MainActivity" > <com.handmark.pulltorefresh.library.PullToRefreshListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="#19000000" android:dividerHeight="4dp" > </com.handmark.pulltorefresh.library.PullToRefreshListView> </RelativeLayout>
listView的item布局:
<?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/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000" android:textSize="20sp" /> </LinearLayout>界面逻辑:
package com.example.flushlistview; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; import com.handmark.pulltorefresh.library.PullToRefreshBase; import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener; import com.handmark.pulltorefresh.library.PullToRefreshListView; /** * @author Rowandjj * *使用pull-to-refresh库实现下拉刷新操作 */ public class MainActivity extends Activity { private PullToRefreshListView lv; private ArrayAdapter<String> adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (PullToRefreshListView) findViewById(R.id.lv); List<String> list = new ArrayList<String>(); list.add("张三"); list.add("李四"); list.add("王五"); list.add("赵六"); list.add("啊啊"); list.add("呵呵"); list.add("嘻嘻"); list.add("嘿嘿"); adapter = new ArrayAdapter<String>(this, R.layout.item, R.id.tv, list); lv.setAdapter(adapter); //实现刷新接口 lv.setOnRefreshListener(new OnRefreshListener<ListView>() { @Override public void onRefresh(PullToRefreshBase<ListView> refreshView) { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日hh时mm分ss秒",Locale.CHINA); String updateTime = format.format(date); refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(updateTime); //异步刷新 new UpdateTask().execute(); } }); } private class UpdateTask extends AsyncTask<Void, Void,List<String>> { @Override protected List<String> doInBackground(Void... params) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } List<String> newData = http://www.mamicode.com/new ArrayList();>效果:
方案2:使用support.v4包提供的SwipeRefreshLayout
SwipeRefreshLayout是support.v4包提供的一个类,可以实现具有Material Design效果的下拉刷新。
使用方式上也很简单,只要将ListView/RecyclerView或者其他View放置在此layout之中,然后调用setOnRefreshListener注册数据更新接口,并在onRefresh方法中处理数据更新事件即可。当数据更新完毕,调用setRefreshing并将参数置为false即可。
注:
1. SwipeRefreshLayout只能包裹一个子View。
2.如果你的support.v4包中没有这个类,那么需要更新之。
示例:
页面布局:
<RelativeLayout 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" tools:context="com.example.swiperefreshlayoutdemo.MainActivity" > <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/activity_main_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="wrap_content" > <ListView android:id="@+id/activity_main_listview" android:layout_width="match_parent" android:layout_height="match_parent" > </ListView> </android.support.v4.widget.SwipeRefreshLayout> </RelativeLayout>item布局:
<?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="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="40dip" android:textColor="#000" android:gravity="center_vertical" android:textSize="18sp" /> </LinearLayout>页面逻辑:
package com.example.swiperefreshlayoutdemo; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends Activity { private ListView mListView; private SwipeRefreshLayout mRefreshLayout; private ArrayAdapter<String> mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.activity_main_listview); mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.activity_main_swipe_refresh_layout); List<String> data = http://www.mamicode.com/new ArrayList();>效果:
方案3:自己实现一个
要想实现一个下拉刷新效果需要对android的事件分发、事件回调机制有清晰的认识。
这里我直接继承自ListView,然后通过实现OnScrollListener监听屏幕滚动事件,因为只有ListView滑动到首部才能下滑刷新,另外,需要重写onTouchEvent方法,根据手指位置动态更新布局。
我们通过分析传统的下拉刷新,发现有四种状态,1.正常态、2.下拉刷新态、3.释放刷新态、4.刷新态
当手指按下时,首先判断当前listView的第一个item是否可见,如果不可见那么不做任何处理,否则记下当前位置。
手指移动时,计算竖直方向的偏移量,然后根据偏移量改变当前状态,并根据当前状态更新布局。这里的布局指的是listView的headerView,当然,默认情况下,这个view是隐藏的,我们可以设置其padding为负的headerview的高度。
手指松开时,判断当前状态,如果是刷新态,那么调用回调接口处理更新逻辑。
先贴出代码:
package com.example.mypulltorefreshlistview.ui; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.example.mypulltorefreshlistview.R; public class PullToRefreshListView extends ListView implements OnScrollListener { private static final String TAG = "PullToRefreshListView"; /** *顶部布局 */ private View mHeaderView; /** * header的高度 */ private int mHeaderHeight; /** * 当前页面已经滑到顶部 */ private boolean flag; /** * 初始滑动时的y坐标 */ private int mStartY; /** * 正常状态 */ public static final int STATE_NORMAL = 0; /** * 下拉刷新状态 */ public static final int STATE_PULL_TO_REFRESH = 1; /** * 释放刷新状态 */ public static final int STATE_RELEASE_TO_REFRESH = 2; /** * 正在刷新状态 */ public static final int STATE_REFRESH = 3; /** * 当前状态 */ private int mCurrentState; private static final int DEFAULT_LENGTH = 70; private OnRefreshListener mRefreshListener; public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public PullToRefreshListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public PullToRefreshListView(Context context) { super(context); init(context); } public void setOnRefreshListener(OnRefreshListener listener) { this.mRefreshListener = listener; } /** * 初始化操作 * @param context */ private void init(Context context) { //添加headerview mHeaderView = LayoutInflater.from(context).inflate(R.layout.header_layout,null); this.addHeaderView(mHeaderView); //设置滚动监听器 this.setOnScrollListener(this); //通过设置padding将hider隐藏 //注:因为此时无法获得header的高度,所以放入MessageQueue中 post(new HideHeaderAction()); } /** * 设置header的padding * @param topPadding */ private void setHeaderTopPadding(int topPadding) { if(mHeaderView != null) { mHeaderView.setPadding(mHeaderView.getPaddingLeft(),topPadding,mHeaderView.getPaddingRight(),mHeaderView.getPaddingBottom()); } } @Override public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { if(firstVisibleItem == 0) flag = true; else flag = false; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if(flag) { mStartY = (int) ev.getY(); } break; case MotionEvent.ACTION_MOVE: performMove(ev); break; case MotionEvent.ACTION_UP: if(mCurrentState == STATE_RELEASE_TO_REFRESH) { mCurrentState = STATE_REFRESH; updateUIByState(); //TODO 加载新数据 if(mRefreshListener == null) { throw new RuntimeException("you must call setOnRefreshListener before..."); }else { mRefreshListener.onRefresh(this); } }else if(mCurrentState == STATE_PULL_TO_REFRESH) { mCurrentState = STATE_NORMAL; flag = false; updateUIByState(); } break; } return super.onTouchEvent(ev); } private void updateUIByState() { TextView tip = (TextView) findViewById(R.id.tip); ImageView arrow = (ImageView) findViewById(R.id.arrow); ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress); Animation anim1 = AnimationUtils.loadAnimation(getContext(),R.anim.rotate_1); Animation anim2 = AnimationUtils.loadAnimation(getContext(),R.anim.rotate_2); switch (mCurrentState) { case STATE_NORMAL: setHeaderTopPadding(-mHeaderHeight); break; case STATE_PULL_TO_REFRESH: arrow.clearAnimation(); arrow.setAnimation(anim1); arrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tip.setText("下拉可以刷新..."); break; case STATE_RELEASE_TO_REFRESH: arrow.clearAnimation(); arrow.setAnimation(anim2); arrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tip.setText("松开可以刷新..."); break; case STATE_REFRESH: arrow.clearAnimation(); setHeaderTopPadding(mHeaderHeight); arrow.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); tip.setText("正在刷新..."); break; default: break; } } private void performMove(MotionEvent ev) { if(!flag) { return; } int currY = (int) ev.getY(); int deltaY = currY-mStartY; if(deltaY > mHeaderHeight+DEFAULT_LENGTH) deltaY = mHeaderHeight+DEFAULT_LENGTH; switch (mCurrentState) { case STATE_NORMAL: if(deltaY > 0) { mCurrentState = STATE_PULL_TO_REFRESH; } break; case STATE_PULL_TO_REFRESH: setHeaderTopPadding(deltaY-mHeaderHeight); updateUIByState(); if(deltaY >= mHeaderHeight+DEFAULT_LENGTH) { mCurrentState = STATE_RELEASE_TO_REFRESH; }else if(deltaY <= 0) { mCurrentState = STATE_NORMAL; } break; case STATE_RELEASE_TO_REFRESH: // setHeaderTopPadding(deltaY-mHeaderHeight); updateUIByState(); if(deltaY < mHeaderHeight+DEFAULT_LENGTH) { mCurrentState = STATE_PULL_TO_REFRESH; }else if(deltaY <= 0) { mCurrentState = STATE_NORMAL; } break; } } /** * 更新完毕时调用 */ public void refreshComplete() { TextView lastUpdateTime = (TextView) findViewById(R.id.last_update_time); SimpleDateFormat format = new SimpleDateFormat("MM-dd hh:mm",Locale.CHINA); String updateTime = format.format(new Date(System.currentTimeMillis())); lastUpdateTime.setText("更新于 "+updateTime); mCurrentState = STATE_NORMAL; updateUIByState(); } public interface OnRefreshListener { public void onRefresh(PullToRefreshListView listView); } private class HideHeaderAction implements Runnable { @Override public void run() { //获取header的高度 mHeaderHeight = mHeaderView.getMeasuredHeight();//view在被渲染前无法获得其宽高 Log.d(TAG,"Headerheight:"+mHeaderHeight); //通过设置header的padding来隐藏header setHeaderTopPadding(-mHeaderHeight); } } }
使用上跟上面差不多,也是需要添加监听器,然后处理回调方法,数据更新完调用refreshComplete。
当然,这个只是一个简单的demo,效果可能不是很好,仅供参考~
【安卓笔记】下拉刷新组件的使用及实现
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。