SwipeRefreshLayout的下拉刷新、上拉加載

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);
            }
        });
    }
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末命雀,一起剝皮案震驚了整個濱河市蒜哀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吏砂,老刑警劉巖撵儿,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異狐血,居然都是意外死亡淀歇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門匈织,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浪默,“玉大人,你說我怎么就攤上這事缀匕≡『瑁” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵弦追,是天一觀的道長岳链。 經(jīng)常有香客問我,道長劲件,這世上最難降的妖魔是什么掸哑? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮零远,結果婚禮上苗分,老公的妹妹穿的比我還像新娘。我一直安慰自己牵辣,他們只是感情好摔癣,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纬向,像睡著了一般择浊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逾条,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天琢岩,我揣著相機與錄音,去河邊找鬼师脂。 笑死担孔,一個胖子當著我的面吹牛江锨,可吹牛的內容都是我干的。 我是一名探鬼主播糕篇,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啄育,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拌消?” 一聲冷哼從身側響起挑豌,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拼坎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體完疫,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡泰鸡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壳鹤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盛龄。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芳誓,靈堂內的尸體忽然破棺而出余舶,到底是詐尸還是另有隱情,我是刑警寧澤锹淌,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布匿值,位于F島的核電站,受9級特大地震影響赂摆,放射性物質發(fā)生泄漏挟憔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一烟号、第九天 我趴在偏房一處隱蔽的房頂上張望绊谭。 院中可真熱鬧,春花似錦汪拥、人聲如沸达传。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宪赶。三九已至,卻和暖如春脯燃,著一層夾襖步出監(jiān)牢的瞬間逊朽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工曲伊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叽讳,地道東北人追他。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像岛蚤,于是被迫代替她去往敵國和親邑狸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容