Android实现下拉刷新上拉加载(PullToRefreshLayout)
Posted <菜鸟@号>
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android实现下拉刷新上拉加载(PullToRefreshLayout)相关的知识,希望对你有一定的参考价值。
各个组件位置: 导xutils包gson包配置网络权限
values包下面
strings修改
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Pull</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> <string name="head">这里是HeadView</string> <string name="pull_to_refresh">下拉刷新</string> <string name="release_to_refresh">释放立即刷新</string> <string name="refreshing">正在刷新...</string> <string name="refresh_succeed">刷新成功</string> <string name="refresh_fail">刷新失败</string> <string name="pullup_to_load">上拉加载更多</string> <string name="release_to_load">释放立即加载</string> <string name="loading">正在加载...</string> <string name="load_succeed">加载成功</string> <string name="load_fail">加载失败</string> </resources>
添一个color.xml 在这可以修改颜色
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="white">#FFFFFF</color> <color name="black">#000000</color> <color name="gray">#f00</color> <color name="light_blue">#f00</color> </resources>
在res文件夹下创个anim文件夹添加动画(两个)
/MainActivity/res/anim/reverse_anim.xml
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="100" android:fillAfter="true" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:repeatCount="0" android:toDegrees="180" > </rotate>
/MainActivity/res/anim/rotating.xml
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1500" android:fillAfter="true" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:repeatCount="-1" android:toDegrees="360" > </rotate>
在res下layout下添加两部局
/MainActivity/res/layout/load_more.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/loadmore_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/gray" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:paddingBottom="20dp" android:paddingTop="20dp" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" > <ImageView android:id="@+id/pullup_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:background="@drawable/pullup_icon_big" /> <ImageView android:id="@+id/loading_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:background="@drawable/loading" android:visibility="gone" /> <TextView android:id="@+id/loadstate_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="@string/pullup_to_load" android:textColor="@color/black" android:textSize="16sp" /> <ImageView android:id="@+id/loadstate_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/loadstate_tv" android:visibility="gone" /> </RelativeLayout> </RelativeLayout> </RelativeLayout>
/MainActivity/res/layout/refresh_head.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/head_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/light_blue" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:paddingBottom="20dp" android:paddingTop="20dp" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" > <ImageView android:id="@+id/pull_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:background="@drawable/pull_icon_big" /> <ImageView android:id="@+id/refreshing_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:background="@drawable/refreshing" android:visibility="gone" /> <TextView android:id="@+id/state_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="@string/pull_to_refresh" android:textColor="@color/white" android:textSize="16sp" /> <ImageView android:id="@+id/state_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/state_tv" android:visibility="gone" /> </RelativeLayout> </RelativeLayout> </RelativeLayout>
修改/MainActivity/res/layout/activity_main.xml布局(注意红色包名)
<com.exaple.tong.PullToRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <include layout="@layout/refresh_head" /> <com.exaple.tong.PullableListView android:id="@+id/listview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world" /> <include layout="@layout/load_more" /> </com.exaple.tong.PullToRefreshLayout>
/MainActivity/res/layout/base.xml 子布局
<?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="horizontal" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hhh" /> </LinearLayout>
下面在src文件夹下
先创个com.exaple.tong包里面有三个类(固定的直接粘)
/MainActivity/src/com/exaple/tong/Pullable.java (1)
package com.exaple.tong; public interface Pullable { /** * 判断是否可以下拉,如果不需要下拉功能可以直接return false * * @return true如果可以下拉否则返回false */ boolean canPullDown(); /** * 判断是否可以上拉,如果不需要上拉功能可以直接return false * * @return true如果可以上拉否则返回false */ boolean canPullUp(); }
/MainActivity/src/com/exaple/tong/PullableListView.java (2)
package com.exaple.tong; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.widget.ListView; public class PullableListView extends ListView implements Pullable { public PullableListView(Context context) { super(context); } public PullableListView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getCount() == 0) { // 娌℃湁item鐨勬椂鍊欎篃鍙互涓嬫媺鍒锋柿 return true; } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) { // 婊戝埌ListView鐨勯《閮ㄤ簡 return true; } else return false; } @Override public boolean canPullUp() { if (getCount() == 0) { // 娌℃湁item鐨勬椂鍊欎篃鍙互涓婃媺鍔犺浿 return true; } else if (getLastVisiblePosition() == (getCount() - 1)) { // 婊戝埌搴曢儴浜? if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null && getChildAt( getLastVisiblePosition() - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) return true; } return false; } }
/MainActivity/src/com/exaple/tong/PullToRefreshLayout.java (3)
package com.exaple.tong; import java.util.Timer; import java.util.TimerTask; import com.exmple.pull.R; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.RelativeLayout; import android.widget.TextView; /** * 閼奉亜鐣炬稊澶屾畱鐢啫鐪敍宀?暏閺夈儳顓搁悶鍡曠瑏娑擃亜鐡欓幒褌娆㈤敍灞藉従娑擃厺绔存稉顏呮Ц娑撳濯烘径杈剧礉娑擄拷閲滈弰顖氬瘶閸氼偄鍞寸?鍦 * 畱pullableView閿涘牆褰叉禒銉︽Ц鐎圭偟骞嘝ullable閹恒儱褰涢惃鍕畱娴犺缍峍iew閿涘绱? * 鏉╂ɑ婀佹稉锟介嚋娑撳﹥濯烘径杈剧礉閺囨潙顦跨拠锕佇掔憴浣稿触鐎诡晭ttp * ://blog.csdn.net/zhongkejingwang/article/details/38868463 * * @author 闂勫牓娼? */ public class PullToRefreshLayout extends RelativeLayout { public static final String TAG = "PullToRefreshLayout"; // 閸掓繂顫愰悩鑸碉拷 public static final int INIT = 0; // 闁插﹥鏂侀崚閿嬫煀 public static final int RELEASE_TO_REFRESH = 1; // 濮濓絽婀崚閿嬫煀 public static final int REFRESHING = 2; // 闁插﹥鏂侀崝鐘烘祰 public static final int RELEASE_TO_LOAD = 3; // 濮濓絽婀崝鐘烘祰 public static final int LOADING = 4; // 閹垮秳缍旂?灞剧槸 public static final int DONE = 5; // 瑜版挸澧犻悩鑸碉拷 private int state = INIT; // 閸掗攱鏌婇崶鐐剁殶閹恒儱褰? private OnRefreshListener mListener; // 閸掗攱鏌婇幋鎰 public static final int SUCCEED = 0; // 閸掗攱鏌婃径杈Е public static final int FAIL = 1; // 閹稿绗匶閸ф劖鐖i敍灞肩瑐娑擄拷閲滄禍瀣╂閻愮瓬閸ф劖鐖? private float downY, lastY; // 娑撳濯洪惃鍕獩缁傛眹锟藉▔銊﹀壈閿涙ullDownY閸滃ullUpY娑撳秴褰查懗钘夋倱閺冩湹绗夋稉锟? public float pullDownY = 0; // 娑撳﹥濯洪惃鍕獩缁傦拷 private float pullUpY = 0; // 闁插﹥鏂侀崚閿嬫煀閻ㄥ嫯绐涚粋锟? private float refreshDist = 200; // 闁插﹥鏂侀崝鐘烘祰閻ㄥ嫯绐涚粋锟? private float loadmoreDist = 200; private MyTimer timer; // 閸ョ偞绮撮柅鐔峰 public float MOVE_SPEED = 8; // 缁楊兛绔村▎鈩冨⒔鐞涘苯绔风仦锟? private boolean isLayout = false; // 閸︺劌鍩涢弬鎷岀箖缁嬪鑵戝鎴濆З閹垮秳缍? private boolean isTouch = false; // 閹靛瀵氬鎴濆З鐠烘繄顬囨稉搴濈瑓閹峰銇旈惃鍕拨閸斻劏绐涚粋缁樼槷閿涘奔鑵戦梻缈犵窗闂呭繑顒滈崚鍥у毐閺佹澘褰夐崠锟? private float radio = 2; // 娑撳濯虹粻顓炪仈閻ㄥ嫯娴?80鎺抽崝銊ф暰 private RotateAnimation rotateAnimation; // 閸у洤瀵戦弮瀣祮閸斻劎鏁? private RotateAnimation refreshingAnimation; // 娑撳濯烘径锟? private View refreshView; // 娑撳濯洪惃鍕唲婢讹拷 private View pullView; // 濮濓絽婀崚閿嬫煀閻ㄥ嫬娴橀弽锟? private View refreshingView; // 閸掗攱鏌婄紒鎾寸亯閸ョ偓鐖? private View refreshStateImageView; // 閸掗攱鏌婄紒鎾寸亯閿涙碍鍨氶崝鐔稿灗婢惰精瑙? private TextView refreshStateTextView; // 娑撳﹥濯烘径锟? private View loadmoreView; // 娑撳﹥濯洪惃鍕唲婢讹拷 private View pullUpView; // 濮濓絽婀崝鐘烘祰閻ㄥ嫬娴橀弽锟? private View loadingView; // 閸旂姾娴囩紒鎾寸亯閸ョ偓鐖? private View loadStateImageView; // 閸旂姾娴囩紒鎾寸亯閿涙碍鍨氶崝鐔稿灗婢惰精瑙? private TextView loadStateTextView; // 鐎圭偟骞囨禍鍝杣llable閹恒儱褰涢惃鍒卛ew private View pullableView; // 鏉╁洦鎶ゆ径姘卞仯鐟欙妇顫? private int mEvents; // 鏉╂瑤琚辨稉顏勫綁闁插繒鏁ら弶銉﹀付閸掔ull閻ㄥ嫭鏌熼崥鎴礉婵″倹鐏夋稉宥呭閹貉冨煑閿涘苯缍嬮幆鍛枌濠娐ゅ喕閸欘垯绗傞幏澶婂嫉閸欘垯绗呴幏澶嬫濞屸剝纭舵稉瀣 private boolean canPullDown = true; private boolean canPullUp = true; private Context mContext; /** * 閹笛嗩攽閼奉亜濮╅崶鐐寸泊閻ㄥ埅andler */ Handler updateHandler = new Handler() { @Override public void handleMessage(Message msg) { // 閸ョ偛鑴婇柅鐔峰闂呭繋绗呴幏澶庣獩缁傜北oveDeltaY婢х偛銇囬懓灞筋杻婢讹拷 MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2 / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); if (!isTouch) { // 濮濓絽婀崚閿嬫煀閿涘奔绗栧▽鈩冩箒瀵帮拷绗傞幒銊ф畱鐠囨繂鍨幃顒?粻閿涘本妯夌粈锟藉锝呮躬閸掗攱鏌?.." if (state == REFRESHING && pullDownY <= refreshDist) { pullDownY = refreshDist; timer.cancel(); } else if (state == LOADING && -pullUpY <= loadmoreDist) { pullUpY = -loadmoreDist; timer.cancel(); } } if (pullDownY > 0) pullDownY -= MOVE_SPEED; else if (pullUpY < 0) pullUpY += MOVE_SPEED; if (pullDownY < 0) { // 瀹告彃鐣幋鎰礀瀵拷 pullDownY = 0; pullView.clearAnimation(); // 闂呮劘妫屾稉瀣婢跺瓨妞傞張澶婂讲閼冲?绻曢崷銊ュ煕閺傚府绱濋崣顏呮箒瑜版挸澧犻悩鑸碉拷娑撳秵妲稿锝呮躬閸掗攱鏌婇弮鑸靛閺?懓褰夐悩鑸碉拷 if (state != REFRESHING && state != LOADING) changeState(INIT); timer.cancel(); requestLayout(); } if (pullUpY > 0) { // 瀹告彃鐣幋鎰礀瀵拷 pullUpY = 0; pullUpView.clearAnimation(); // 闂呮劘妫屾稉濠冨婢跺瓨妞傞張澶婂讲閼冲?绻曢崷銊ュ煕閺傚府绱濋崣顏呮箒瑜版挸澧犻悩鑸碉拷娑撳秵妲稿锝呮躬閸掗攱鏌婇弮鑸靛閺?懓褰夐悩鑸碉拷 if (state != REFRESHING && state != LOADING) changeState(INIT); timer.cancel(); requestLayout(); } Log.d("handle", "handle"); // 閸掗攱鏌婄敮鍐ㄧ湰,娴兼俺鍤滈崝銊ㄧ殶閻⑩暙nLayout requestLayout(); // 濞屸剝婀侀幏鏍ㄥ閹存牞锟介崶鐐茶剨鐎瑰本鍨? if (pullDownY + Math.abs(pullUpY) == 0) timer.cancel(); } }; public void setOnRefreshListener(OnRefreshListener listener) { mListener = listener; } public PullToRefreshLayout(Context context) { super(context); initView(context); } public PullToRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } private void initView(Context context) { mContext = context; timer = new MyTimer(updateHandler); rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation( context, R.anim.reverse_anim); refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation( context, R.anim.rotating); // 濞h濮為崠锟斤拷鏉烆剙濮╅崝銊ф暰 LinearInterpolator lir = new LinearInterpolator(); rotateAnimation.setInterpolator(lir); refreshingAnimation.setInterpolator(lir); } private void hide() { timer.schedule(5); } /** * 鐎瑰本鍨氶崚閿嬫煀閹垮秳缍旈敍灞炬▔缁?搫鍩涢弬鎵波閺嬫嚎锟藉▔銊﹀壈閿涙艾鍩涢弬鏉跨暚閹存劕鎮楁稉锟界暰鐟曚浇鐨熼悽銊ㄧ箹娑擃亝鏌熷▔锟? */ /** * @param refreshResult * PullToRefreshLayout.SUCCEED娴狅綀銆冮幋鎰閿涘ullToRefreshLayout. * FAIL娴狅綀銆冩径杈Е */ public void refreshFinish(int refreshResult) { refreshingView.clearAnimation(); refreshingView.setVisibility(View.GONE); switch (refreshResult) { case SUCCEED: // 閸掗攱鏌婇幋鎰 refreshStateImageView.setVisibility(View.VISIBLE); refreshStateTextView.setText(R.string.refresh_succeed); refreshStateImageView .setBackgroundResource(R.drawable.refresh_succeed); break; case FAIL: default: // 閸掗攱鏌婃径杈Е refreshStateImageView.setVisibility(View.VISIBLE); refreshStateTextView.setText(R.string.refresh_fail); refreshStateImageView .setBackgroundResource(R.drawable.refresh_failed); break; } if (pullDownY > 0) { // 閸掗攱鏌婄紒鎾寸亯閸嬫粎鏆?缁夛拷 new Handler() { @Override public void handleMessage(Message msg) { changeState(DONE); hide(); } }.sendEmptyMessageDelayed(0, 1000); } else { changeState(DONE); hide(); } } /** * 閸旂姾娴囩?灞剧槸閿涘本妯夌粈鍝勫鏉炵晫绮ㄩ弸婧匡拷濞夈劍鍓伴敍姘鏉炶棄鐣幋鎰倵娑擄拷鐣剧憰浣界殶閻€劏绻栨稉顏呮煙濞夛拷 * * @param refreshResult * PullToRefreshLayout.SUCCEED娴狅綀銆冮幋鎰閿涘ullToRefreshLayout. * FAIL娴狅綀銆冩径杈Е */ public void loadmoreFinish(int refreshResult) { loadingView.clearAnimation(); loadingView.setVisibility(View.GONE); switch (refreshResult) { case SUCCEED: // 閸旂姾娴囬幋鎰 loadStateImageView.setVisibility(View.VISIBLE); loadStateTextView.setText(R.string.load_succeed); loadStateImageView.setBackgroundResource(R.drawable.load_succeed); break; case FAIL: default: // 閸旂姾娴囨径杈Е loadStateImageView.setVisibility(View.VISIBLE); loadStateTextView.setText(R.string.load_fail); loadStateImageView.setBackgroundResource(R.drawable.load_failed); break; } if (pullUpY < 0) { // 閸掗攱鏌婄紒鎾寸亯閸嬫粎鏆?缁夛拷 new Handler() { @Override public void handleMessage(Message msg) { changeState(DONE); hide(); } }.sendEmptyMessageDelayed(0, 1000); } else { changeState(DONE); hide(); } } private void changeState(int to) { state = to; switch (state) { case INIT: // 娑撳濯虹敮鍐ㄧ湰閸掓繂顫愰悩鑸碉拷 refreshStateImageView.setVisibility(View.GONE); refreshStateTextView.setText(R.string.pull_to_refresh); pullView.clearAnimation(); pullView.setVisibility(View.VISIBLE); // 娑撳﹥濯虹敮鍐ㄧ湰閸掓繂顫愰悩鑸碉拷 loadStateImageView.setVisibility(View.GONE); loadStateTextView.setText(R.string.pullup_to_load); pullUpView.clearAnimation(); pullUpView.setVisibility(View.VISIBLE); break; case RELEASE_TO_REFRESH: // 闁插﹥鏂侀崚閿嬫煀閻樿埖锟? refreshStateTextView.setText(R.string.release_to_refresh); pullView.startAnimation(rotateAnimation); break; case REFRESHING: // 濮濓絽婀崚閿嬫煀閻樿埖锟? pullView.clearAnimation(); refreshingView.setVisibility(View.VISIBLE); pullView.setVisibility(View.INVISIBLE); refreshingView.startAnimation(refreshingAnimation); refreshStateTextView.setText(R.string.refreshing); break; case RELEASE_TO_LOAD: // 闁插﹥鏂侀崝鐘烘祰閻樿埖锟? loadStateTextView.setText(R.string.release_to_load); pullUpView.startAnimation(rotateAnimation); break; case LOADING: // 濮濓絽婀崝鐘烘祰閻樿埖锟? pullUpView.clearAnimation(); loadingView.setVisibility(View.VISIBLE); pullUpView.setVisibility(View.INVISIBLE); loadingView.startAnimation(refreshingAnimation); loadStateTextView.setText(R.string.loading); break; case DONE: // 閸掗攱鏌婇幋鏍у鏉炶棄鐣В鏇礉閸熴儵鍏樻稉宥呬粵 break; } } /** * 娑撳秹妾洪崚鏈电瑐閹峰鍨ㄦ稉瀣 */ private void releasePull() { canPullDown = true; canPullUp = tru
以上是关于Android实现下拉刷新上拉加载(PullToRefreshLayout)的主要内容,如果未能解决你的问题,请参考以下文章
Android 使用SwipeRefreshLayout实现RecyclerVeiw的下拉刷新和上拉加载
Android实战----RecyclerView下拉刷新和上拉加载的简单实现