一個功能強大的自定義下拉刷新組件。 SwipeRefreshLayout也是一種下拉刷新控件,不同的它的刷新狀態效果和傳統的PuulToRefresh完全不一樣。 SwipeRefreshLayout 是谷歌公司推出的用于下拉刷新的控件,SwipeRefreshLayout已經被放到了sdk中,在Version 19.1之后SwipeRefreshLayout 被放到support v4中。
setOnRefreshListener(OnRefreshListener):添加下拉刷新監聽器 setRefreshing(boolean):顯示或者隱藏刷新進度條 isRefreshing():檢查是否處于刷新狀態 setColorSchemeResources():設置進度條的顏色主題,最多設置四種,以前的setColorScheme()方法已經棄用了。
1.SwipeRefreshLayout本身自帶下拉刷新的效果,那么我們可以選擇在RecyclerView布局外部嵌套一層SwipeRefreshLayout布局即可,具體布局文件如下:
<?xmlversionxmlversion="1.0" encoding="utf-8"?> <LinearLayoutxmlns:androidLinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"android:layout_width="match_parent" android:layout_height="match_parent"> <includelayoutincludelayout="@layout/common_top_bar_layout"/> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/demo_swiperefreshlayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scrollbars="vertical" > <android.support.v7.widget.RecyclerView android:id="@+id/demo_recycler" android:layout_width="fill_parent" android:layout_height="fill_parent" ></android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout> </LinearLayout>2.接著在Activity中獲取SwipeRefreshLayout控件并且設置OnRefreshListener監聽器,同時實現里邊的onRefresh()方法,在該方法中進行網絡請求最新數據,然后刷新RecyclerView列表同時設置SwipeRefreshLayout的進度Bar的隱藏或者顯示效果。具體代碼如下:
demo_swiperefreshlayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { Log.d("zttjiangQQ","invoke onRefresh..."); new Handler().postDelayed(newRunnable() { @Override public void run() { List<String> newDatas = new ArrayList<String>(); for (int i = 0; i <5; i++) { int index = i + 1; newDatas.add("new item" + index); } adapter.addItem(newDatas); demo_swiperefreshlayout.setRefreshing(false); Toast.makeText(RecyclerRefreshActivity.this, "更新了五條數據...", Toast.LENGTH_SHORT).show(); } }, 5000); } });SwipeRefreshLayout里面需要注意的Api:
1、setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener):設置手勢滑動監聽器。 2、setPRogressBackgroundColor(int colorRes):設置進度圈的背景色。 3、setColorSchemeResources(int… colorResIds):設置進度動畫的顏色。 4、setRefreshing(Boolean refreshing):設置組件的刷洗狀態。 5、setSize(int size):設置進度圈的大小,只有兩個值:DEFAULT、LARGE原理:是一個刷新布局,來自兼容包v4可以運行在低版本,控件如果想要支持下拉刷新,只要使用當前布局包裹 setColorSchemeColors:修改旋轉顏色,可以添加多種顏色 setRefreshing: 是否顯示loading狀態 setOnRefreshListener:下拉刷新監聽
例子:public class MainActivity extends AppCompatActivity { private SwipeRefreshLayout swipeRefreshLayout; protected void onCreate(Bundle savedInstanceState) { ····· swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout); //設置旋轉的顏色效果 swipeRefreshLayout.setColorSchemeColors(Color.GREEN, Color.YELLOW, Color.RED); //設置下拉刷新的監聽器 swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { public void onRefresh() { requestData(); } }); } private void requestData() { new Handler().postDelayed(new Runnable() {//延時加載 public void run() { String json = "{name:小米}"; TextView text = (TextView) findViewById(R.id.text); text.setText(json); swipeRefreshLayout.setRefreshing(false);//關閉顯示 } }, 2000); }加載更多——上滑加載數據 思路:1.滾動到底部 getItemCount()-2 ==bottomPosition 2.不處理滾動中 OnScrollListener監聽滾動加載的監聽器 int dy 滾動距離,向上滾動為正 layoutManager.findLastVisibleItemPosition獲取處于底部數據的下標 dy>0與isLoading 都是用來控件靈敏度
public class HomeFragment extends Fragment { private SwipeRefreshLayout swipeRefreshLayout; private RecyclerView recyclerView; private AppAdapter adapter; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { //有一個顯示網絡狀態 //StateLayout stateLayout = new StateLayout(container.getContext()); swipeRefreshLayout = new SwipeRefreshLayout(container.getContext()); //設置顏色 swipeRefreshLayout.setColorSchemeColors(Color.GREEN); //設置下拉監聽 swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { HttpConnect.get(ApiUrls.HOME+"?index=0", callback); } }); recyclerView = new RecyclerView(container.getContext()); //設置排列規則 recyclerView.setLayoutManager(new LinearLayoutManager(container.getContext())); //預先設置了Noemal視圖,但是normal視圖沒有內容 stateLayout.addNormalView(recyclerView); swipeRefreshLayout.addView(recyclerView); //發送請求給服務器 HttpConnect.get(ApiUrls.HOME+"?index=0",callback); return swipeRefreshLayout; } DefaultCallBack callback = new DefaultCallBack() { @Override public void onStart(int what) { swipeRefreshLayout.setRefreshing(true); } @Override public void onFinish(int what) { swipeRefreshLayout.setRefreshing(false); } //拿到數據 protected void createView(String json) { HomeWebInfo info = new Gson().fromJson(json, HomeWebInfo.class); //創建控件,設置適配器 adapter=new AppAdapter(info.list); recyclerView.setAdapter(adapter); //上滑加載數據 addLoadMoreList(); } }; private void addLoadMoreList(){ recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){ private boolean isLoading = false; //int dy 上下滑動的距離 +數代表往上滑動 public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //判斷 是否是排列布局 RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); //判斷是否是線性排列,并且是否滑動距離 if(layoutManager instanceof LinearLayoutManager && dy>0 ){ //當前是列表 int total = adapter.getItemCount(); int lastPosition = total-2; //獲取rv 的bottom條目 int currLastPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); if(currLastPosition==lastPosition&&!isLoading){ } isLoading=true; Toast.makeText(MyApp.getContext(),"加載更多...",Toast.LENGTH_SHORT).show(); new Handler().postDelayed(new Runnable() { @Override public void run() { Toast.makeText(MyApp.getContext(), "加載成功", Toast.LENGTH_SHORT).show(); isLoading=false; } },5000); } } }); } }
源碼點擊查看 RecyclerRefreshLayout 基于 {@link android.support.v4.widget.SwipeRefreshLayout} RecyclerRefreshLayout 可以被用于用戶通過一個垂直滑動的手勢刷新當前 view 內容的場景. 實例化這個視圖的操作中總應該添加一個OnRefreshListener監聽刷新動作完成后通知。 RecyclerRefreshLayout 每次手勢操作完成后都會通知監聽器(OnRefreshListener), 監聽器負責決定何時來發起一個刷新操作。 如果監聽器決定不觸發刷新操作則需要調用 setRefreshing(false) 取消刷新的任何可視指示. 如果用戶想要強制執行一次刷新動畫, 則需要調用 setRefreshing(true). 如果想要禁用刷新動畫,則可以調用 setEnabled(false)。
注意: RecyclerRefreshLayout 支持所有的View: ListView, GridView, ScrollView, FrameLayout, 甚至一個 TextView
在你的build.gradle文件里添加下面依賴:
dependencies { compile 'com.dinuscxj:recyclerrefreshlayout:2.0.3' }在xml中配置
<?xml version="1.0" encoding="utf-8"?><com.dinuscxj.refresh.RecyclerRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /></app.dinus.com.refresh.RecyclerRefreshLayout>配置下面的屬性(* 必選)
設置監聽器監聽手勢操作是否觸發刷新操作
RecyclerRefreshLayout.setOnRefreshListener(OnRefreshListener);通知刷新狀態已經改變. 當刷新由滑動手勢觸發不要調用它。
RecyclerRefreshLayout.setRefreshing(boolean);配置下面的屬性(可選)
設置將刷新動畫從手勢釋放的位置移動到刷新位置的動畫所需要的Interpolator
RecyclerRefreshLayout.setAnimateToRefreshInterpolator(Interpolator);設置將刷新動畫從手勢釋放的位置(或刷新位置)移動到起始位置的動畫所需要的Interpolator
RecyclerRefreshLayout.setAnimateToStartInterpolator(Interpolator);設置將刷新動畫從手勢釋放的位置移動到刷新位置的動畫所需要的時間
RecyclerRefreshLayout.setAnimateToRefreshDuration(int);設置將刷新動畫從手勢釋放的位置(或刷新位置)移動到起始位置的動畫所需要的時間
RecyclerRefreshLayout.setAnimateToStartDuration(int);設置RefreshView相對父組件的初始位置
RecyclerRefreshLayoutsetRefreshInitialOffset(float)設置觸發刷新需要滑動的最小距離
RecyclerRefreshLayout.setRefreshTargetOffset(float)設置RefreshView的樣式
RecyclerRefreshLayout.setRefreshStyle(@NonNull RefreshStyle)自定義 為 RecyclerRefreshLayout 自定義刷新動畫 (需要實現接口 IRefreshStatus)
public interface IRefreshStatus {/*** 當手勢操作完成且刷新動畫滑動到起始位置*/void reset();/*** 正在刷新*/void refreshing();/*** 刷新動畫被下拉到刷新位置*/void pullToRefresh();/*** 刷新動畫被釋放到刷新位置*/void releaseToRefresh();/*** @param pullDistance 刷新動畫被拖動的距離* @param pullProgress 刷新動畫被拖動的進度,當大于觸發刷新的距離會大于1.0f* pullProgress = pullDistance / refreshTargetOffset*/void pullProgress(float pullDistance, float pullProgress);}需求:需要一個狀態控件,1:自定義控件 繼承ViewGroup/View 2:底層都使用Paint Canvas或者ImageView TextView
//步驟一 。完成構造函數public class StateLayout extends FrameLayout { private View mLoading = null; private View mError = null; private View mEmpty = null; private View mNormal = null; public StateLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //步驟二 將布局打氣進來并且作為一個元素添加當前的容器 View view = View.inflate(context, R.layout.state_layout, null); mLoading = view.findViewById(R.id.loading); mError = view.findViewById(R.id.error); mEmpty = view.findViewById(R.id.nodata);// mNormal = view.findViewById(R.id.normal); this.addView(view); } public StateLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public StateLayout(Context context) { this(context, null, 0); } //三。重置讓所有的控件變成gone private void reset() { mLoading.setVisibility(View.GONE); mError.setVisibility(View.GONE); mEmpty.setVisibility(View.GONE); if (mNormal != null) { mNormal.setVisibility(View.GONE); } } //顯示加載中 public void showLoading() { reset(); mLoading.setVisibility(View.VISIBLE); } //顯示網絡出錯 public void showError() { reset(); mError.setVisibility(View.VISIBLE); } //顯示空 public void showEmpty() { reset(); mEmpty.setVisibility(View.VISIBLE); } public void addNormalView(Object normalViewLayout) { if (normalViewLayout instanceof Integer) { mNormal = LayoutInflater.from(getContext()).inflate((Integer) normalViewLayout, this, false); } else { mNormal = (View) normalViewLayout; } this.addView(mNormal);//只有添加到當前布局的元素才可以顯示 } //顯示正常 public void showNormal() { reset(); mNormal.setVisibility(View.VISIBLE); }}新聞熱點
疑難解答