美文网首页高级UIAndroid应用开发那些事
SwipeRefreshLayout的下拉刷新、上拉加载

SwipeRefreshLayout的下拉刷新、上拉加载

作者: zhangwenhao | 来源:发表于2019-10-22 10:28 被阅读0次

    SwipeRefreshLayout的下拉刷新、上拉加载


    前言

    • 这次在小项目中用到了下拉刷新、上拉加载,这次就记录一下
    • 博主小白一枚,正在努力进阶,如有错误,欢迎指正!

    上拉加载

    • 以下操作是在 Adapter 中,实现 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() 方法

    // 根据你想要的放置的 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. 根据 Item 的类型,来定义对应的 ViewHolder

    • 如果只是要展示出来就不需要进行 实例的获取了
    • 如果后续操作需要实例,那么就在 ViewHolder 的构造方法中获取
    // 后续操作需要实例的
        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);
            }
        }
        
    //后续操作不需要实例的
        class FunctionViewHolder extends RecyclerView.ViewHolder {
    
            public FunctionViewHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    

    4. 在 onCreateViewHolder() 方法中进行判断 item 类型,来加载不同的布局

    • 注意,上拉加载
    • 方法中的第二个参数 i 就是 getItemViewType() 方法中返回的
      • 这里是我的猜测,但我想应该也没有多大的偏差吧
    // 根据不同的类型,加载对应的 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. 定义滑动变量、滑动状态常量,并提供相应的 set 方法

    //滑动状态常量
    public final int STATE_LOADING = 0;
    public final int STATE_FINISH  = 1;
    
    //滑动状态变量
    private int state = STATE_LOADING;
    
    //相应的改变滑动状态的 set方法
    public void setLoadState(int state) {
        this.state = state;
    }
    

    6. 在 onBindViewHolder() 方法中根据不同的 ViewHolder 来对相应的布局实例进行操作

    • 这里注意一点,我们在使用 RecyclerView 的时候,对于布局的具体加载,也就是对布局中的实例进行的一系列操作,应该放在 onBindViewHolder() 方法中

    其实对于上拉加载这个功能来说,这一步就是上拉加载 UI 的具体展示

    • 在下面的代码在匹配到 FooterViewHolder 中进行了判断当前的状态,这样给用户 UI 呈现
      • 根据当前的 滑动状态,对应进行不同的布局操作
     @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
            
            // 此处省略部分代码,下面的是重点
            ···
            
            }else if (viewHolder instanceof FooterViewHolder) {
            //根据当前的滑动状态,对应的是实现 进度条的显示、隐藏等
                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 的工作已经作完啦,接下来就是活动、碎片的工作吧!

    7. 关于加载的数据

    • 我认为,上拉加载最主要的就是 分页思想
      • 加载加载大量的数据时,不需要一次全部加载完毕,而是首先加载用户可见的部分(及手机屏幕)
      • 而在用户进行上拉的时候,在加载后面的数据
    • 分页思想就需要我们将数据处理好了

    需要进行处理的内容

    • 控制数据的加载
      • 我想的就是没加载一次就请求一部分数据,然后放入一个集合中,就可以进行加载了,当全部的数据都请求完毕的时候,就不再请求,而是要通知 UI 进行更新提示数据一加载完毕了
    //下面使用的是本地的数据,也控制了只能加载两次,超过两次将不再进行加载
    private void getData() {
        if (loadCount <= 2){
            for (int i = 0; i < 2; i++) {
                urlList.add(String.valueOf(i));
            }
            Log.d("TAG","getData执行");
            //加载次数加一
            loadCount++;
        }
    }
    

    8. 最后一步,对 RecyclerView 的滑动监听进行处理

    • RecyclerView 的 addOnScrollListener() 方法用于给 RecyclerView 添加一个滑动监听器,也可以实现 RecyclerView.OnScrollListener 这个接口来添加监听
    • 添加监听会重写 onScrollStateChanged()onScrolled() 这两个方法,前者在滑动状态改变的时候会被调用,后者在滑动完成后会被调用
    • onScrollStateChanged() 方法的滑动状态有三个状态:
      • RecyclerView.SCROLL_STATE_IDLE:屏幕停止滚动
      • RecyclerView.SCROLL_STATE_DRAGGING:屏幕在滚动
      • RecyclerView.SCROLL_STATE_SETTLING:屏幕自动滚动,手指放开了
    • 判断是否是当前子项的最后一个,即是否需要进行加载数据
      • 总 item 数量 - 1 == 最后一个 Item 的位置
      • 总 item 数量是通过 getItemCount()得到的
    • 上面的判断成立就开始请求数据,请求完毕后,调用 notifyDataSetChanged() 方法通知 Adapter 更新数据
    • 如果多次请求之后已经请求完毕了,这时,就调用我们在 Adapter 中定义的改变滑动状态的方法了,设置已经加载完毕的状态,这个时候,因为我们在 onBindViewHolder() 中进行了判断的,所以底部的布局就会改变啦
    • 注意下面使用了 Hanlder 发送了一个延迟消息,目的就是让底部布局的加载状态能够保留一段时间,这样 UI 效果会好一些
    //使用的是本地数据
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
    
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                //下面的manger是RecyclerView的主布局线性布局的实例,通过new出来的,需要传入几个参数
                    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()方法执行");
                                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 发送一条空的延迟消息,然后进行操作,注意上面所说的
    //这是项目中的代码,不要这么死板,看懂就行啦
        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);
            //设置刷新监听
            refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                //这个方法就是下拉刷新的时候会触发的,清楚原有数据,重新获取数据,通知Adapter更新数据
                    urlList.clear();
                    loadCount = 0;
                    getData();
                    adapter.notifyDataSetChanged();
                    refreshLayout.setRefreshing(false);
                }
            });
        }
    

    相关文章

      网友评论

        本文标题:SwipeRefreshLayout的下拉刷新、上拉加载

        本文链接:https://www.haomeiwen.com/subject/csafvctx.html