自定義RecyclerView實現下拉重新整理和上拉載入(第一種實現方式)
說明:該自定義RecyclerView只適用於layoutManager為LinearLayoutManager的情況,使用的還是RecyclerView.Adapter。
效果圖
使用
1、編寫layout檔案
<?xml version="1.0" encoding="utf-8"?> <com.shbj.refreashrvdemo.ui.RefreashRecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent"> </com.shbj.refreashrvdemo.ui.RefreashRecyclerView>
2、定義HeaderView
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:visibility="visible" android:id="@+id/tv_refresh" android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center" android:text="下拉重新整理" android:textAllCaps="false" android:textSize="18sp" android:textStyle="bold"/> <LinearLayout android:id="@+id/ll_refreshing" android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center" android:orientation="horizontal" android:visibility="invisible"> <ProgressBar android:layout_width="30dp" android:layout_height="30dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="20dp" android:text="重新整理中..." android:textSize="15sp"/> </LinearLayout> </FrameLayout>
3、定義FooterView
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_load" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:text="載入更多" android:textSize="15sp"/> <LinearLayout android:id="@+id/ll_loading" android:visibility="invisible" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:orientation="horizontal"> <ProgressBar android:layout_width="30dp" android:layout_height="30dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="20dp" android:text="載入中..." android:textSize="15sp"/> </LinearLayout> </FrameLayout>
4、Java程式碼實現
package com.shbj.refreashrvdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.shbj.refreashrvdemo.ui.RefreashRecyclerView;
import java.util.ArrayList;
public class Demo1Fragment extends Fragment {
private final String TAG = "Demo1Fragment";
private ArrayList<String> mStrings;
private final int TYPE_REFRESH = 1;
private final int TYPE_LOAD = 2;
private final int TYPE_NO_LOAD_MORE = 3;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TYPE_REFRESH:
mRv.refreshEnd();//重新整理完成後需呼叫refreshEnd,更新HeaderView顯示狀態
mDemo1Adapter.setDatas(mStrings);
//由於自定義RecycleView中使用了自定義的adapter所以資料改變時需呼叫自定義adapter的notifyDataSetChanged
mRv.getAdapter().notifyDataSetChanged();
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
LinearLayout llRefreshing = mHeaderView.findViewById(R.id.ll_refreshing);
tvHeader.setVisibility(View.VISIBLE);
llRefreshing.setVisibility(View.INVISIBLE);
break;
case TYPE_LOAD:
mDemo1Adapter.setDatas(mStrings);
mRv.getAdapter().notifyDataSetChanged();
TextView tvLoad = mFooterView.findViewById(R.id.tv_load);
LinearLayout llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.VISIBLE);
llLoading.setVisibility(View.INVISIBLE);
break;
case TYPE_NO_LOAD_MORE:
mRv.removeOnLoadMoreListener();//當沒有更多資料時可移除載入更多監聽
tvLoad = mFooterView.findViewById(R.id.tv_load);
llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.VISIBLE);
llLoading.setVisibility(View.INVISIBLE);
tvLoad.setText("沒有更多資料了");
break;
}
}
};
private RefreashRecyclerView mRv;
private Demo1Adapter mDemo1Adapter;
private View mHeaderView;
private View mFooterView;
private int mLoadCount;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = View.inflate(getContext(), R.layout.fragment_demo1, null);
mStrings = new ArrayList<>();
for (int i = 0; i < 50; i++) {//初始資料
mStrings.add("條目 " + i);
}
mRv = view.findViewById(R.id.rv);
mRv.setLayoutManager(new LinearLayoutManager(getContext()));
mRv.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
mHeaderView = LayoutInflater.from(this.getContext()).inflate(R.layout.item_header, mRv, false);
mRv.setHeaderView(mHeaderView);//設定HeaderView,需在setLayoutManager後設置否則會報錯
mFooterView = LayoutInflater.from(this.getContext()).inflate(R.layout.item_footer, mRv, false);
mRv.setFooterView(mFooterView);//設定FooterView
mDemo1Adapter = new Demo1Adapter(getContext(), mStrings);
mRv.setAdapter(mDemo1Adapter);//設定adapter,照樣繼承的是RecycleView中自帶的adapter
mRv.setOnRefreshListener(new RefreashRecyclerView.OnRefreshListener() {//設定下拉重新整理監聽
@Override
public void onStartRefresh() {
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
LinearLayout llRefreshing = mHeaderView.findViewById(R.id.ll_refreshing);
tvHeader.setVisibility(View.INVISIBLE);
llRefreshing.setVisibility(View.VISIBLE);
refresh();//監聽到開始重新整理時呼叫重新整理函式
}
});
mRv.setOnPullDownListener(new RefreashRecyclerView.OnPullDownListener() {//設定下拉過程的監聽
@Override
public void onPullDownProgress(float progress) {//獲取下拉的佔比,一些特殊要求可能會用到,比如下面實現了下拉過程中字型逐漸變大
if (progress > 1) {
progress = 1;
}
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
tvHeader.setTextSize(15 + 20 * progress);
}
});
mRv.setOnLoadMoreListener(new RefreashRecyclerView.OnLoadMoreListener() {//設定上拉載入更多的監聽
@Override
public void onLoadMoreStart() {
TextView tvLoad = mFooterView.findViewById(R.id.tv_load);
LinearLayout llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.INVISIBLE);
llLoading.setVisibility(View.VISIBLE);
loadMore();//監聽到開始載入時呼叫載入更多函式
}
});
return view;
}
private void refresh() {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
mStrings.clear();
for (int i = 0; i < 50; i++) {
mStrings.add("欄目 " + i);
}
mHandler.sendEmptyMessage(TYPE_REFRESH);
}
}).start();
}
private void loadMore() {
mLoadCount++;
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
if (mLoadCount == 3) {//模擬沒有更多資料
mHandler.sendEmptyMessage(TYPE_NO_LOAD_MORE);
} else {
for (int i = 0; i < 20; i++) {
mStrings.add("新欄目 " + i);
}
Log.d(TAG, "run: loadMore");
mHandler.sendEmptyMessage(TYPE_LOAD);
}
}
}).start();
}
}
5、定義adapter,使用的還是RecyclerView.Adapter
package com.shbj.refreashrvdemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class Demo1Adapter extends RecyclerView.Adapter {
private Context mContext;
private List<String> mDatas;
public Demo1Adapter(Context context, List<String> datas){
mContext = context;
mDatas = datas;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_normal, parent, false);
RecyclerView.ViewHolder holder = new NormalHolder(view);
return holder;
}
public void setDatas(List<String> datas){
mDatas=datas;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((NormalHolder)holder).setData(position);
}
@Override
public int getItemCount() {
if (mDatas != null) {
return mDatas.size();
}
return 0;
}
class NormalHolder extends RecyclerView.ViewHolder {
private View mItemView;
public NormalHolder(View itemView) {
super(itemView);
mItemView = itemView;
}
public void setData(int postion) {
((TextView) mItemView).setText(mDatas.get(postion));
}
}
}
自定義RecyclerView實現過程
1、在onlayout時獲取HeaderView的高度,並修改HeaderView的TopMargin值使其隱藏
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
Log.d(TAG, "onLayout: " + sHeaderViewMeasuredHeight);
if (isFristLayout) {
//將sHeaderViewMeasuredHeight設定為static,只要是為了防止頁面間切換出現bug
if (sHeaderViewMeasuredHeight == 0) {//只有當第一次layout時才會為sHeaderViewMeasuredHeight賦值
sHeaderViewMeasuredHeight = mHeaderView.getMeasuredHeight();//獲取HeaderView的高度
}
updateMargin(-sHeaderViewMeasuredHeight);//修改HeaderView的TopMargin值使其隱藏
}
}
2、重寫onTouchEvent,實現下拉重新整理和上拉載入的效果
@Override
public boolean onTouchEvent(MotionEvent e) {
//下拉重新整理處理
if (mHeaderView == getChildAt(0)) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = e.getX();
mDownY = e.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = e.getX();
float moveY = e.getY();
mDx = moveX - mDownX;
mDy = moveY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy > 0) {
if (mDy < 2 * sHeaderViewMeasuredHeight) {//小於兩倍height時,逐漸修改TopMargin,使HeaderView逐漸顯現出來
updateMargin(-sHeaderViewMeasuredHeight + (int) mDy);
if (mOnPullDownListener != null) {
mOnPullDownListener.onPullDownProgress(mDy / sHeaderViewMeasuredHeight);//將佔比返回給監聽者
}
}
}
break;
case MotionEvent.ACTION_UP:
float upX = e.getX();
float upY = e.getY();
mDx = upX - mDownX;
mDy = upY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy > 0 && mHeaderView.getTop() > -sHeaderViewMeasuredHeight) {
if (mDy < sHeaderViewMeasuredHeight * 2 / 3) {//小於兩倍height時,TopMargin置為-sHeaderViewMeasuredHeight,使其隱藏
updateMargin(-sHeaderViewMeasuredHeight);
} else {//否則使其完全顯現
updateMargin(0);
if (mOnRefreshListener != null) {
//下拉釋放後開始重新整理
mOnRefreshListener.onStartRefresh();//通知監聽者開始重新整理
}
}
}
break;
}
}
//上拉載入處理
if (mFooterView == getChildAt(getChildCount() - 1)) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = e.getX();
mDownY = e.getY();
break;
case MotionEvent.ACTION_UP:
float upX = e.getX();
float upY = e.getY();
mDx = upX - mDownX;
mDy = upY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy < -80) {//上拉載入時,mDy < -80可以通過此處調節載入的靈敏度,值越小上拉所需的距離約大
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMoreStart();//通知監聽者開始載入
}
}
break;
}
}
return super.onTouchEvent(e);
}
3、重新整理完成後,處理邏輯
//重新整理結束後呼叫該方法隱藏HeaderView
public void refreshEnd() {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
updateMargin(-sHeaderViewMeasuredHeight);
} else {
mHeaderView.post(new Runnable() {
@Override
public void run() {
updateMargin(-sHeaderViewMeasuredHeight);
}
});
}
}
4、定義各類監聽介面
//下拉重新整理的程序監聽,可以獲取到下拉過程中下拉的佔比
private OnPullDownListener mOnPullDownListener;
public void setOnPullDownListener(OnPullDownListener onPullDownListener) {
mOnPullDownListener = onPullDownListener;
}
public interface OnPullDownListener {
void onPullDownProgress(float progress);
}
//下拉重新整理的監聽
private OnRefreshListener mOnRefreshListener;
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
public interface OnRefreshListener {
void onStartRefresh();
}
//載入更多監聽
private OnLoadMoreListener mOnLoadMoreListener;
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
mOnLoadMoreListener = onLoadMoreListener;
}
//如果沒有更多的載入專案可以移除OnLoadMoreListener
public void removeOnLoadMoreListener() {
mOnLoadMoreListener = null;
}
public interface OnLoadMoreListener {
void onLoadMoreStart();
}
5、設定HeaderView和FooterView
public void setHeaderView(View headerView) {
mHeaderView = headerView;
}
public void setFooterView(View footerView) {
mFooterView = footerView;
}
6、自定義Adapter
//自定義adapter加入header和footer
private class RefreashAdapter extends RecyclerView.Adapter {
private final int HEADER_TYPE = 0;
private final int NORMAL_TYPE = 1;
private final int FOOTER_TYPE = 2;
private Adapter mAdapter;
public RefreashAdapter(Adapter adapter) {
mAdapter = adapter;
}
@Override
public int getItemViewType(int position) {
int type = 0;
if (position == 0) {
type = HEADER_TYPE;
} else if (position == getItemCount() - 1) {
type = FOOTER_TYPE;
} else {
type = NORMAL_TYPE;
}
return type;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder;
switch (viewType) {
case HEADER_TYPE:
holder = new HeaderHolder(mHeaderView);
break;
case FOOTER_TYPE:
holder = new FooterHolder(mFooterView);
break;
default:
holder = mAdapter.onCreateViewHolder(parent, viewType);
break;
}
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == NORMAL_TYPE) {
mAdapter.onBindViewHolder(holder, position - 1);
}
}
@Override
public int getItemCount() {
return mAdapter.getItemCount() + 2;
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View itemView) {
super(itemView);
}
}
class FooterHolder extends RecyclerView.ViewHolder {
public FooterHolder(View itemView) {
super(itemView);
}
}
}
原始碼地址
相關推薦
自定義RecyclerView實現下拉重新整理和上拉載入
2)尾部佈局(上拉載入部分):refresh_recyclerview_footer.xml<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro
自定義RecyclerView實現下拉重新整理和上拉載入(第一種實現方式)
說明:該自定義RecyclerView只適用於layoutManager為LinearLayoutManager的情況,使用的還是RecyclerView.Adapter。效果圖使用1、編寫layout檔案<?xml version="1.0" encoding="ut
自定義ListView實現下拉重新整理和上拉載入
實現ListView的下拉重新整理和上拉載入,需要先新增headerView和footerView,通過在拖動的過程中,控制頭尾佈局的paddingTop實現。先把paddingTop設為負值,來隱藏header,在下拉的過程中,不斷改變headerView的p
史上最全的使用RecyclerView實現下拉重新整理和上拉載入更多
前言: 縱觀多數App,下拉重新整理和上拉載入更多是很常見的功能,但是谷歌官方只有一個SwipeRefreshLayout用來下拉重新整理,上拉載入更多還要自己做。 本篇文章基於RecyclerView簡單封裝了這兩個操作,下拉重
android自定義下拉重新整理和上拉載入控制元件
import android.content.Context; import android.graphics.Point; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.NestedScro
當scrollview巢狀多個recyclerview時如何實現整個頁面的下拉重新整理和上拉載入
最近做的一個專案中有個佈局比較複雜一點,整個頁面是個srollview裡面又嵌套了幾個recycview,剛開始是有的滑動衝突卡頓的問題,通過如下方法解決了 mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(),
手把手教你實現RecyclerView的下拉重新整理和上拉載入更多
個人原創,轉載請註明出處http://blog.csdn.net/u012402124/article/details/78210639 2018年10月25日更新 讓大家花費時間看文章卻沒有解決需求,隨著bug的增多內心的愧疚感逐漸增強,但幾個月前的程式
使用SwipeRefreshLayout和RecyclerView實現仿“簡書”下拉重新整理和上拉載入
package com.leohan.refresh;import android.os.Bundle;import android.os.Handler;import android.support.v4.widget.SwipeRefreshLayout;import android.support.v7
Android 自定義下拉重新整理和上拉載入
完整程式碼在最下面。。 頭佈局xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_pare
採用SwipeFreshLayout+Recyclerview實現下拉重新整理和上拉載入更多以及CoordinatorLayout的引入
之前都是採用PullToRefresh進行下拉重新整理和下拉載入,現在採用谷歌自己的控制元件SwipeFreshLayout,配合Recyclerview來實現這一效果。使用SwipeRefreshLayout可以實現下拉重新整理,前提是佈局裡需要包裹一個可以
template-web.js 結合dropload.min.js下拉外掛實現下拉重新整理和上拉載入
//引入js,所需要的js已經上傳到個人資源 <script type="text/javascript" src="/web/home/js/template-web.js"></script> <link href="/web/h
Flutter如何實現下拉重新整理和上拉載入更多
效果 下拉重新整理 如果實現下拉重新整理,必須藉助RefreshIndicator,在listview外面包裹一層RefreshIndicator,然後在RefreshIndicator裡面實現onRefresh方法。 body: movie
RecyclerView三種顯示方式的下拉重新整理和上拉載入更多
但是之前寫的那個有一點點的小問題,如果上拉重新整理,重新整理小圖示還沒有移動到重新整理位置,重新整理資料就已經獲取到,並且呼叫了setRefreshing(false),在setRefreshing(false)中會去呼叫translationTo(int from,i
Android RecyclerView下拉重新整理和上拉載入封裝
效果圖:程式碼已經同步到github~Gradle引入依賴: allprojects { repositories { ... maven { url 'https://jitpack.io' } } }
iOS UIScrollView 的下拉重新整理和上拉載入的實現
iOS UIScrollView的下拉重新整理和上拉載入的實現 下面我簡單的說一說iOS UIScrollView的下拉重新整理和上拉載入的實現。 首先匯入第三方庫: MJRefre
ionic2下拉重新整理和上拉載入功能實現
先看程式碼: <!--預設顯示出來的資料--> <ion-list> <ion-item *ngFor="let i of items">{{i}}</ion-item> </ion-list> <
Android簡單實現下拉重新整理和上拉重新整理
先把佈局檔案裡面新增一個ListView控制元件, <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.a
使用PullToRefresh實現下拉重新整理和上拉載入
PullToRefresh是一套實現非常好的下拉重新整理庫,它支援: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多種常用的需要重新整理的View型別,而且使用起來也十分方便。 (下載地址:https://gi
3秒鐘不懂你砍我:RecyclerView下拉重新整理和上拉載入更多(開源中國List業務流程全解析)
這裡以開源中國開源資訊頁面為例子。 這個頁面資料的url:http://www.oschina.net/action/apiv2/news?pageToken= 是這樣的 json資料的結構: NewsBean返回成功與否的code和msg。 ResultBean返回的
通過ViewGroup實現下拉重新整理和上拉載入,2018/2/12 06
為了重新瞭解一下自定義ViewGroup,自己實現了一個下拉重新整理view,衝突的解決Recyclerview滾動到底部和頂部的處理全部放在了父view 中,滾動實現使用的是Scroller,所以使整個控制元件還有類似ios的彈性效果,程式碼很簡單,使用也很簡