SwipeRefreshLayout的下拉刷新癣丧、上拉加載
前言
- 這次在小項目中用到了下拉刷新槽畔、上拉加載,這次就記錄一下
- 博主小白一枚胁编,正在努力進階厢钧,如有錯誤,歡迎指正嬉橙!
上拉加載
- 以下操作是在 Adapter 中坏快,實現(xiàn) Adapter 就不多說了,如果還不熟悉憎夷,建議先熟悉再做這個
1. 明確子項 Item 的類型莽鸿,定義幾個 int 類型的常量作為 Item 類型
- 作用:作為不同類型的 Item 的標識符,通過判斷來加載對應的布局
- 使用在兩個地方
- 你的 Adapter 中的
onCreateViewHolder()
方法中
- 重寫的
getItemType()
方法中
private static final int TYPE_BANNER = 0; //第一個Banner布局
private static final int TYPE_FUNCTION = 1; //第二個功能表布局
private static final int TYPE_SELLERS = 2; //第三個熱銷榜布局
private static final int TYPE_FRUIT = 3; //第四個水果Item布局
private static final int TYPE_FOOTER = 4; //第五個底部加載布局
2. 重寫 getItemViewType() 方法
// 根據(jù)你想要的放置的 item 位置來返回不同的類型
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_BANNER;
}else if (position == 1) {
return TYPE_FUNCTION;
}else if (position == 2) {
return TYPE_SELLERS;
}else if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
}else {
return TYPE_FRUIT;
}
}
3. 根據(jù) Item 的類型拾给,來定義對應的 ViewHolder
- 如果只是要展示出來就不需要進行 實例的獲取了
- 如果后續(xù)操作需要實例祥得,那么就在 ViewHolder 的構造方法中獲取
// 后續(xù)操作需要實例的
class BannerViewHolder extends RecyclerView.ViewHolder {
ViewPager viewPager;
LinearLayout linearLayout;
public BannerViewHolder(@NonNull View itemView) {
super(itemView);
viewPager = itemView.findViewById(R.id.home_view_pager);
linearLayout = itemView.findViewById(R.id.home_ll_indicator);
}
}
//后續(xù)操作不需要實例的
class FunctionViewHolder extends RecyclerView.ViewHolder {
public FunctionViewHolder(@NonNull View itemView) {
super(itemView);
}
}
4. 在 onCreateViewHolder() 方法中進行判斷 item 類型,來加載不同的布局
- 注意蒋得,上拉加載
- 方法中的第二個參數(shù) i 就是
getItemViewType()
方法中返回的
// 根據(jù)不同的類型,加載對應的 View额衙,并返回對應的 ViewHolder
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (i == TYPE_BANNER) {
View view = LayoutInflater.from(context).inflate(R.layout.fragment_home_banner,
viewGroup,false);
return new BannerViewHolder(view);
}else if (i == TYPE_FUNCTION) {
View view = LayoutInflater.from(context).inflate(R.layout.fragment_home_function
viewGroup,false);
return new FunctionViewHolder(view);
}
···
}else if (i == TYPE_FOOTER) {
View view = LayoutInflater.from(context).inflate(R.layout.fragment_home_footer,
viewGroup,false);
return new FooterViewHolder(view);
}
//當 else if 語句的條件都不滿足的時候饮焦,該方法就無返回值了,所以這里加一個返回值
//不過應該是不會用到的
return null;
}
5. 定義滑動變量窍侧、滑動狀態(tài)常量县踢,并提供相應的 set 方法
//滑動狀態(tài)常量
public final int STATE_LOADING = 0;
public final int STATE_FINISH = 1;
//滑動狀態(tài)變量
private int state = STATE_LOADING;
//相應的改變滑動狀態(tài)的 set方法
public void setLoadState(int state) {
this.state = state;
}
6. 在 onBindViewHolder() 方法中根據(jù)不同的 ViewHolder 來對相應的布局實例進行操作
- 這里注意一點,我們在使用 RecyclerView 的時候伟件,對于布局的具體加載硼啤,也就是對布局中的實例進行的一系列操作,應該放在
onBindViewHolder()
方法中
其實對于上拉加載這個功能來說斧账,這一步就是上拉加載 UI 的具體展示
- 在下面的代碼在匹配到 FooterViewHolder 中進行了判斷當前的狀態(tài)谴返,這樣給用戶 UI 呈現(xiàn)
- 根據(jù)當前的 滑動狀態(tài),對應進行不同的布局操作
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
// 此處省略部分代碼咧织,下面的是重點
···
}else if (viewHolder instanceof FooterViewHolder) {
//根據(jù)當前的滑動狀態(tài)嗓袱,對應的是實現(xiàn) 進度條的顯示、隱藏等
FooterViewHolder footerViewHolder = (FooterViewHolder)viewHolder;
switch (state) {
case STATE_LOADING:
footerViewHolder.progressBar.setVisibility(View.VISIBLE);
footerViewHolder.textView.setText("正在加載...");
break;
case STATE_FINISH:
footerViewHolder.progressBar.setVisibility(View.GONE);
footerViewHolder.textView.setText("我也是有底線的哦~");
default:
break;
}
}
}
- 好啦习绢,Adapter 的工作已經(jīng)作完啦渠抹,接下來就是活動、碎片的工作吧!
7. 關于加載的數(shù)據(jù)
- 我認為逼肯,上拉加載最主要的就是 分頁思想
- 加載加載大量的數(shù)據(jù)時,不需要一次全部加載完畢桃煎,而是首先加載用戶可見的部分(及手機屏幕)
- 而在用戶進行上拉的時候篮幢,在加載后面的數(shù)據(jù)
- 分頁思想就需要我們將數(shù)據(jù)處理好了
需要進行處理的內容
- 控制數(shù)據(jù)的加載
- 我想的就是沒加載一次就請求一部分數(shù)據(jù),然后放入一個集合中为迈,就可以進行加載了三椿,當全部的數(shù)據(jù)都請求完畢的時候,就不再請求葫辐,而是要通知 UI 進行更新提示數(shù)據(jù)一加載完畢了
//下面使用的是本地的數(shù)據(jù)搜锰,也控制了只能加載兩次,超過兩次將不再進行加載
private void getData() {
if (loadCount <= 2){
for (int i = 0; i < 2; i++) {
urlList.add(String.valueOf(i));
}
Log.d("TAG","getData執(zhí)行");
//加載次數(shù)加一
loadCount++;
}
}
8. 最后一步耿战,對 RecyclerView 的滑動監(jiān)聽進行處理
- RecyclerView 的
addOnScrollListener()
方法用于給 RecyclerView 添加一個滑動監(jiān)聽器蛋叼,也可以實現(xiàn) RecyclerView.OnScrollListener
這個接口來添加監(jiān)聽
- 添加監(jiān)聽會重寫
onScrollStateChanged()
、onScrolled()
這兩個方法剂陡,前者在滑動狀態(tài)改變的時候會被調用狈涮,后者在滑動完成后會被調用
-
onScrollStateChanged()
方法的滑動狀態(tài)有三個狀態(tài):
- RecyclerView.SCROLL_STATE_IDLE:屏幕停止?jié)L動
- RecyclerView.SCROLL_STATE_DRAGGING:屏幕在滾動
- RecyclerView.SCROLL_STATE_SETTLING:屏幕自動滾動,手指放開了
- 判斷是否是當前子項的最后一個鸭栖,即是否需要進行加載數(shù)據(jù)
- 總 item 數(shù)量 - 1 == 最后一個 Item 的位置
- 總 item 數(shù)量是通過 getItemCount()得到的
- 上面的判斷成立就開始請求數(shù)據(jù)歌馍,請求完畢后,調用
notifyDataSetChanged()
方法通知 Adapter 更新數(shù)據(jù)
- 如果多次請求之后已經(jīng)請求完畢了晕鹊,這時松却,就調用我們在 Adapter 中定義的改變滑動狀態(tài)的方法了,設置已經(jīng)加載完畢的狀態(tài)溅话,這個時候晓锻,因為我們在
onBindViewHolder()
中進行了判斷的,所以底部的布局就會改變啦
- 注意下面使用了 Hanlder 發(fā)送了一個延遲消息飞几,目的就是讓底部布局的加載狀態(tài)能夠保留一段時間带射,這樣 UI 效果會好一些
//使用的是本地數(shù)據(jù)
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//下面的manger是RecyclerView的主布局線性布局的實例,通過new出來的循狰,需要傳入幾個參數(shù)
int lastItemPosition = manager.findLastCompletelyVisibleItemPosition();
int itemCount = manager.getItemCount();
if (itemCount - 1 == lastItemPosition) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d("TAG","onSrcolled()方法執(zhí)行");
getData();
if (loadCount <= 2) {
adapter.setLoadState(adapter.STATE_LOADING);
}else {
adapter.setLoadState(adapter.STATE_FINISH);
}
adapter.notifyDataSetChanged();
}
},1000);
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView,dx,dy);
}
});
下拉刷新
- 這個比較簡單窟社,使用的是 谷歌官方的 SwipeRefreshLayout,是design庫下的
- 注意一點:
.setRefreshing();
方法并不會調用 onRefresh()
方法
- 關于自動刷新绪钥,可以使用 Hanlder 發(fā)送一條空的延遲消息灿里,然后進行操作,注意上面所說的
//這是項目中的代碼程腹,不要這么死板匣吊,看懂就行啦
private void initSwipeRefresh() {
refreshLayout = viewHome.findViewById(R.id.home_swipe_refresh);
//設置 加載的那個圈圈的顏色,最多四種,這個顏色是依次加載的
refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light,
android.R.color.holo_red_light, android.R.color.holo_orange_light,
android.R.color.holo_green_light);
//設置刷新監(jiān)聽
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//這個方法就是下拉刷新的時候會觸發(fā)的色鸳,清楚原有數(shù)據(jù)社痛,重新獲取數(shù)據(jù),通知Adapter更新數(shù)據(jù)
urlList.clear();
loadCount = 0;
getData();
adapter.notifyDataSetChanged();
refreshLayout.setRefreshing(false);
}
});
}