精华内容
下载资源
问答
  • Android上拉加载更多

    千次下载 热门讨论 2013-09-02 19:05:26
    Android中实现上拉加载更多的一个小Demo
  • 本人在使用BaseQuickAdapter万能适配器进行上拉加载更多数据时,运行时不管我滑动不滑动界面,下拉加载却一直在加载更多数据,没有达到我想要的下拉到最后开始加载更多数据的要求 废话不多说,上布局: <?xml ...

    本人在使用BaseQuickAdapter万能适配器进行上拉加载更多数据时,运行时不管我滑动不滑动界面,下拉加载却一直在加载更多数据,没有达到我想要的下拉到最后开始加载更多数据的要求
    废话不多说,上布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                android:id="@+id/homeswipe"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
        <ScrollView android:layout_width="match_parent"
                    android:layout_height="wrap_content"
    
        >
            <RelativeLayout
                    android:descendantFocusability="blocksDescendants"
                   
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
        <com.youth.banner.Banner
                android:id="@+id/banner"
                android:layout_width="match_parent"
                android:layout_height="200dp" />
    
    
        <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/home_recyc"
                android:layout_below="@+id/banner"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
    
        </androidx.recyclerview.widget.RecyclerView>
            </RelativeLayout>
    </ScrollView>
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </LinearLayout>
    

    这里就是我的界面布局,scrollview嵌套轮播图和recyclerview

    导致问题的原因:

    scrollview嵌套recyclerview进行上拉加载更多数据的时候 会一直走onCreateViewHolder()方法,scrollowview嵌套recyclerview,recyclerview会一次性把所有的数据进行加载 就导致现在的问题

    解决方法:

    我们可以利用BaseQuickAdapter提供的添加头部 将banner定义到一个新的布局中,这样就可以不使用scrollview了 ,最简单的就是你可以直接将scrollview删除 不过这样会导致界面不太美观

    展开全文
  • 思路今天带大家实现一个上拉加载更多的ListView.GitHub传送门:PulmListView, 欢迎大家fork&&star.先带大家看一下示例效果: 然后带大家理一下实现思路, 如果我们要实现一个上拉加载更多的ListView, 我们需要实现的...

    声明

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布


    思路

    今天带大家实现一个上拉加载更多的ListView.GitHub传送门:PulmListView, 欢迎大家fork&&star.

    先带大家看一下示例效果:
    效果图

    然后带大家理一下实现思路, 如果我们要实现一个上拉加载更多的ListView, 我们需要实现的功能包括:

    1. 一个自定义的ListView, 并且该ListView能够判断当前是否已经处于最底部.
    2. 一个自定义的FooterView, 用于在ListView加载更多的过程中进行UI展示.
    3. 关联FooterView和ListView, 包括加载时机判断、FooterView的显示和隐藏.
    4. 提供一个加载更多的接口, 便于回调用户真正加载更多的功能实现.
    5. 提供一个加载更多结束的回调方法, 用于添加用户的最新数据并更新相关状态标记和UI显示.

    针对上面的5个功能, 我们挨个分析对应的实现方法.


    功能1(自定义ListView)

    我们可以通过继承ListView, 实现一个自定义的PulmListView.

    public class PulmListView extends ListView {
        public PulmListView(Context context) {
            this(context, null);
        }
    
        public PulmListView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PulmListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // 初始化
            init();
        }
    }

    只是实现ListView的三个构造函数还不够, 我们需要ListView能够判断当前的ListView是否滑动到最后一个元素.

    判断是否滑动到最后一个元素, 我们可以通过为ListView设置OnScrollListener来实现.代码如下:

    private void init() {
        super.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // 调用用户设置的OnScrollListener
                if (mUserOnScrollListener != null) {
                    mUserOnScrollListener.onScrollStateChanged(view, scrollState);
                }
            }
    
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 调用用户设置的OnScrollListener
                if (mUserOnScrollListener != null) {
                    mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }
    
                // firstVisibleItem是当前屏幕能显示的第一个元素的位置
                // visibleItemCount是当前屏幕能显示的元素的个数
                // totalItemCount是ListView包含的元素总数
                int lastVisibleItem = firstVisibleItem + visibleItemCount;
                if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
                    if (mOnPullUpLoadMoreListener != null) {
                        mIsLoading = true;
                        mOnPullUpLoadMoreListener.onPullUpLoadMore();
                    }
                }
            }
        });
    }

    从代码注释可以知道, 通过(firstVisibleItem + visibleItemCount)可以获取当前屏幕已经展示的元素个数, 如果已经展示的元素个数等于ListView的元素总数, 则此时可以认为ListView已经滑动到底部.


    功能2(自定义的FooterView)

    这里我们可以实现一个比较简单的FooterView, 即加载更多的UI布局.例如我们可以展示一个ProgressBar和一行文字, 具体代码如下:

    /**
     * 加载更多的View布局,可自定义.
     */
    public class LoadMoreView extends LinearLayout {
    
        public LoadMoreView(Context context) {
            this(context, null);
        }
    
        public LoadMoreView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            LayoutInflater.from(getContext()).inflate(R.layout.lv_load_more, this);
        }
    }

    布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/id_load_more_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_margin="@dimen/loading_view_margin_layout">
    
        <ProgressBar
            android:id="@+id/id_loading_progressbar"
            android:layout_width="@dimen/loading_view_progress_size"
            android:layout_height="@dimen/loading_view_progress_size"
            android:indeterminate="true"
            style="?android:progressBarStyleSmall"/>
    
        <TextView
            android:id="@+id/id_loading_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/page_loading"/>
    </LinearLayout>

    功能3(关联ListView和FooterView)

    第一,我们需要在ListView中通过一个变量保存FooterView, 并且在构造函数中将其实例化.

    private View mLoadMoreView;
    private void init() {
        mLoadMoreView = new LoadMoreView(getContext());
    }

    第二,我们需要控制FooterView的显示和隐藏.考虑一下FooterView的显示和隐藏的时机:

    • 显示的时机: ListView处于最底部并且当前还有更多的数据需要加载.
    • 隐藏的时机: ListView结束完加载更多的操作.

    为了判断当前是否还有数据需要加载, 因此我们需要定义一个boolean变量mIsPageFinished, 表示数据加载是否结束.
    为了保证同一时间只进行一次数据加载过程, 因此我们还需要定义一个boolean变量mIsLoading, 表示当前是否已经处于数据加载状态.

    明确了FooterView的显示和隐藏时机, 也有了控制状态的变量, 代码也就比较容易实现了.

    显示时机:

    private void init() {
        mIsLoading = false; // 初始化时没处于加载状态
        mIsPageFinished = false; // 初始化时默认还有更多数据需要加载
        mLoadMoreView = new LoadMoreView(getContext()); // 实例化FooterView
        super.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // 调用用户设置的OnScrollListener
                if (mUserOnScrollListener != null) {
                    mUserOnScrollListener.onScrollStateChanged(view, scrollState);
                }
            }
    
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // 调用用户设置的OnScrollListener
                if (mUserOnScrollListener != null) {
                    mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }
    
                int lastVisibleItem = firstVisibleItem + visibleItemCount;
                // 当处于ListView尾部且有更多数据需要加载且当前没有加载程序再进行中时, 执行加载更多操作
                if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
                    if (mOnPullUpLoadMoreListener != null) {
                        mIsLoading = true; // 将加载更多进行时状态设置为true
                        showLoadMoreView(); // 显示加载更多布局
                        mOnPullUpLoadMoreListener.onPullUpLoadMore(); // 调用用户设置的加载更多回调接口
                    }
                }
            }
        });
    }
    
    private void showLoadMoreView() {
        // 这里将加载更多的根布局id设置为id_load_more_layout, 便于用户自定制加载更多布局.
        if (findViewById(R.id.id_load_more_layout) == null) {
            addFooterView(mLoadMoreView);
        }
    }

    隐藏时机:

    /**
     * 加载更多结束后ListView回调方法.
     *
     * @param isPageFinished 分页是否结束
     * @param newItems       分页加载的数据
     * @param isFirstLoad    是否第一次加载数据(用于配置下拉刷新框架使用, 避免出现页面闪现)
     */
    public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {
        mIsLoading = false; // 标记当前已经没有加载更多的程序在执行
        setIsPageFinished(isPageFinished); // 设置分页是否结束标志并移除FooterView
    }
    
    private void setIsPageFinished(boolean isPageFinished) {
        mIsPageFinished = isPageFinished;
        removeFooterView(mLoadMoreView);
    }

    功能4(上拉加载更多实现的回调接口)

    这个比较简单, 我们定义一个interface, 便于回调用户真正的加载更多的实现方法.

    /**
     * 上拉加载更多的回调接口
     */
    public interface OnPullUpLoadMoreListener {
        void onPullUpLoadMore();
    }
    
    private OnPullUpLoadMoreListener mOnPullUpLoadMoreListener;
    /**
     * 设置上拉加载更多的回调接口.
     * @param l 上拉加载更多的回调接口
     */
    public void setOnPullUpLoadMoreListener(OnPullUpLoadMoreListener l) {
        this.mOnPullUpLoadMoreListener = l;
    }

    功能5(加载更多的结束回调)

    为了在PulmListView中维护数据集合, 必须自定义一个Adapter, 在Adapter中使用List存储数据集合, 并提交增删的方法.

    自定义的Adapter:

    /**
     * 抽象的Adapter.
     */
    public abstract class PulmBaseAdapter<T> extends BaseAdapter {
        protected List<T> items;
    
        public PulmBaseAdapter() {
            this.items = new ArrayList<>();
        }
    
        public PulmBaseAdapter(List<T> items) {
            this.items = items;
        }
    
        public void addMoreItems(List<T> newItems, boolean isFirstLoad) {
            if (isFirstLoad) {
                this.items.clear();
            }
            this.items.addAll(newItems);
            notifyDataSetChanged();
        }
    
        public void removeAllItems() {
            this.items.clear();
            notifyDataSetChanged();
        }
    }

    为什么在addMoreItems方法中要增加一个isFirstLoad变量呢?

    是因为上拉加载更多通常要配合下拉刷新使用.而下拉刷新的过程中会牵扯到ListView的数据集合clear然后再addAll.如果没有isFirstLoad参数, 那用户下拉刷新去更新ListView的数据集合就必须分为两步:

    1. removeAllItems并进行notifyDataSetChanged.
    2. addMoreItems并进行notifyDataSetChanged.

    同一时间连续两次notifyDataSetChanged会导致屏幕闪屏, 因此这里提交了一个isFirstLoad方法.当是第一次加载数据时, 会先clear掉所有的数据, 然后再addAll, 最后再notify.

    有了自定义的adapter, 就可以写加载更多结束的回调函数了:

    /**
     * 加载更多结束后ListView回调方法.
     *
     * @param isPageFinished 分页是否结束
     * @param newItems       分页加载的数据
     * @param isFirstLoad    是否第一次加载数据(用于配置下拉刷新框架使用, 避免出现页面闪现)
     */
    public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {
        mIsLoading = false;
        setIsPageFinished(isPageFinished);
        // 添加更新后的数据
        if (newItems != null && newItems.size() > 0) {
            PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();
            adapter.addMoreItems(newItems, isFirstLoad);
        }
    }

    这里需要注意, 当添加了FooterView或者HeaderView之后, 我们无法通过listview.getAdapter拿到我们自定义的adapter, 必须按照如下步骤:

    PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();

    参考

    1. PagingListView
    展开全文
  • Android BaseRecyclerViewAdapterHelper上拉加载更多

    这里写图片描述

    private boolean isErr = false; //是否加载错误
    private int TOTAL_COUNTER = 16; //一共模拟加载16条数据,所有的数据总数
    private int mCurrentCounter = 6; //当前的数据总数,因为第一次默认加载6个
    
    //1.上拉加载
            mImgDetailsAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
            @Override public void onLoadMoreRequested() {
                imgDetailRecycler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mCurrentCounter >= TOTAL_COUNTER) {
                            //数据全部加载完毕
                            mImgDetailsAdapter.loadMoreEnd();
                        } else {
                            if (!isErr) {
                                //成功获取更多数据
                                mImgDetailsAdapter.addData(getServerDatas());
                                mCurrentCounter = mImgDetailsAdapter.getData().size();
                                mImgDetailsAdapter.loadMoreComplete();
                            } else {
                                //获取更多数据失败 PullToRefreshUseActivity
                                isErr = true;
                                Toast.makeText(ImgDetailsActivity.this, "获取更多数据失败", Toast.LENGTH_LONG).show();
                                mImgDetailsAdapter.loadMoreFail();
    
                            }
                        }
                    }
    
                }, 1500);
            }
        }, imgDetailRecycler);
    //模拟从服务器获取数据
        public List<ImgDetails> getServerDatas(){
            ImgDetails details;
            List<ImgDetails> newDatas = new ArrayList<ImgDetails>();
            //for (int i = 0; i < 1; i++) {
                details = new ImgDetails();
                details.setUrl("http://t1.hxzdhn.com/uploads/tu/sm/201601/18/35.jpg");
                newDatas.add(details);
            //}
            return newDatas;
        }    
    
    展开全文
  • 在项目中使用列表的下拉刷新和上拉加载更多是很常见的功能,下拉刷新我们可以用android自带的SwipeRefreshLayout这个很好解决。但是上拉加载更多就要去找一些框架了,刚开始的时候我找到一个Mugen的github开源框架,...

    在项目中使用列表的下拉刷新和上拉加载更多是很常见的功能,下拉刷新我们可以用android自带的SwipeRefreshLayout这个很好解决。但是上拉加载更多就要去找一些框架了,刚开始的时候我找到一个Mugen的github开源框架,但是有个问题,当页面能够一次加载全部item的时候,上拉加载的功能就失效了。
    这是因为当界面一次能够加载完全部item的时候,继续往上拉,Recyclerview的滑动监听,中的onScrolled方法只会在页面加载的时候调用一次,只后就不会被调用了,并且dy=0

     @Override
     public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                }

    代码如下:

    package com.appnews.utils;
    
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.Toast;
    
    /**
     * Created by Administrator on 2017/5/17.
     */
    
    public class LoadMoreForRecyclerView {
        //最后一个显示的item的position
        private int lastVisibleItemPosition;
        //触摸记录之前的触摸位置
        private float oldY;
        //滑动状态
        private int state;
        //滑动时Y轴偏移(大于0表示向上滑动)
        private int offsetY = 0;
        //touch事件中移动的距离(当前触摸的位置-oldY)
        private float moveY;
    
        /**
         * 构造方法
         * @param recyclerView
         * @param loadMoreListener
         */
        public LoadMoreForRecyclerView(RecyclerView recyclerView, LoadMoreListener loadMoreListener) {
            width(recyclerView, loadMoreListener);
        }
    
        /**
         *
         * @param recyclerView  recyclerview
         * @param loadMoreListener 回调监听
         */
        public void width(final RecyclerView recyclerView, LoadMoreListener loadMoreListener) {
    
            mLoadMoreListener = loadMoreListener;
            //线性布局管理
            final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
           //recyclerview设置滑动监听
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    //滑动状态
                    state = newState;
                    //获得最后一个显示的item位置
                    lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    //记录Y轴偏移量
                    offsetY = dy;
                }
            });
    
            //设置touch监听
            recyclerView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    switch (motionEvent.getAction()) {
                        case MotionEvent.ACTION_MOVE:
                            //计算出移动的距离(小于0表示向上拖动)
                            moveY = motionEvent.getY() - oldY;
                            //记录当前触摸的位置
                            oldY = motionEvent.getY();
                            break;
                        case MotionEvent.ACTION_UP:
                            //如果是拖动或者飞快滑动并且显示的是适配器中最后一条数据
                            if ((state == 1 || state == 2) && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1) {
                                if (offsetY > 0) {//如果偏移量大于0
                                    if (mLoadMoreListener != null) {
                                        //回调加载更多监听
                                        mLoadMoreListener.loadListener();
                                    }
                                } else if (offsetY == 0) {//如果偏移量一直等于0
                                    if ((moveY) < 0) {//手指移动的距离小于0(向上拖动recyclerView)
                                        if (mLoadMoreListener != null) {
                                            //回调加载更多
                                            mLoadMoreListener.loadListener();
                                        }
                                    }
                                }
                            }
    
                            break;
                    }
                    //返回值要为false,不会拦截滑动事件
                    return false;
                }
            });
        }
    
        private LoadMoreListener mLoadMoreListener;
        /**
         * 回调接口
         */
        public interface LoadMoreListener {
            void loadListener();
        }
    }
    

    使用的时候:

    //上拉加载更多滑动监听
            new LoadMoreForRecyclerView(rc, new LoadMoreForRecyclerView.LoadMoreListener() {
                @Override
                public void loadListener() {
                    showToast("开始加载");
                    getData(2);
                }
            });

    rc就是recyclerview,在重写的方法中,进行数据处理。

    效果图:
    Recyclerview上拉加载更多
    如果去研究SwipeRefreshLayout的源码,应该可以实现差不多的效果。

    展开全文
  • Android recyclerview上拉加载更多

    万次阅读 2019-05-31 14:59:04
    记录一下视频列表(recyclerview)上拉显示一个“加载更多”的item,然后加载数据。 效果图: 实现思路: 1.写两个item布局,一个用来展示数据,一个用来展示加载中也就是滑到最下方的时候显示的“加载更多”。 2....
  • android中gridview的上拉加载更多

    千次阅读 2015-12-27 15:51:40
    gridview上拉加载更多
  • Android下拉刷新和上拉加载更多

    万次阅读 多人点赞 2018-01-31 11:06:29
    Android下拉刷新和上拉加载更多 下拉刷新 通过android系统提供的组件:SwipeRefreshLayout 一、基本使用 1 xml中 添加 SwipeRefreshLayout 组件 该组件包含着要操作下拉刷新的控件 如ListView RecyclerView...
  • android 上拉刷新下拉加载更多的开源框架 XRefreshView项目地址:[https://github.com/huxq17/XRefreshView][6],对比了网上流行的开源项目,个人认为: XRefreshView 扩展性高。 可自定义Footers,上拉样式,完全...
  • 这篇文章主要为大家详细介绍了Android RecyclerView实现下拉刷新和上拉加载更多,具有一定的参考价值,感兴趣的小伙伴们可以下载参考一下! (Android)五分钟让你轻松学会下拉刷新和上拉加载更多。文章地址 ...
  • android Listview下拉刷新 上拉(滑动分页)加载更多 高仿新浪微博下拉刷新,同时实现了滑动加载下一页
  • Android SDK中并没有默认添加下拉刷新组件,但是在Support V4中官方给出了一个SwipeRefreshLayout组件,它支持下拉刷新功能,但却不支持滑动到底部时的上拉加载更多的功能,这里我们就让Android Support V4中的...
  • 需求分析上拉加载更多也就是拉到RecyclerView底部,再上拉就会显示一个正在加载更多信息,如下图所示: 当上拉加载没有更多数据时,就显示没有更多的提示信息,如下所示: 上拉加载更多 比 下拉刷新更简单
  • 无论是Android应用,还是IOS应用,我们每个app几乎都离不开下拉刷新和上拉加载更多的功能,这已经作为一个app的最基本的功能, Android5.1之前并没有提供系统原生的下拉刷新控件,直到android5.1开始,谷歌的Android...
  • 本来想要找一个支持下拉刷新和上拉加载更多的ListView代码,但没找到满意的,大多要导入一些包,很是受不了,而且也有很多问题。于是干脆自己写,一个类搞定,无需任何包。这里我用的是GridView,GridView和ListView...
  • Android中 scrollview中嵌套listview实现listview的下拉刷新上拉加载更多
  • 手机app 列表页很常用,当数据特别的时候,为了好地用户体验,需要进行分页处理。那么分页功能怎么做呢? 看如下核心代码 if (mPage == 1 &amp;&amp; mList != null) { mList.clear(); } if (mList ...
  • 主要是实现下拉可以获取更多新内容,上拉获取更早的内容,在网上看了一些资料,比较靠谱的是github上的 PushtoRefresh项目,可以直接作为类库项目引入到自己的项目中,但是看到网上的文章大部分都是用了其中的单独...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 165,004
精华内容 66,001
关键字:

android上拉加载更多