Android5.0新特性:RecyclerView实现上拉加载更多

  RecyclerView是Android5.0以后推出的新控件,相比于ListView可定制性更大,大有取代ListView之势。下面这篇博客主要来实现RecyclerView的上拉加载更多功能。

  基本思路是让RecyclerView的Adapter加载两种布局,第一个布局来显示主界面,第二个布局来显示上拉加载时的提示信息,让RecyclerView监听是否滑动到最后一个item,如果是,则调用上拉刷新的逻辑,拉取远程数据,并显示第二个布局。等加载完毕时,刷新

Adapter,并隐藏第二个布局。下面分析代码。

  要加载两种不同的布局,Adapter要重写getItemViewType方法。

  

 @Override
    public int getItemViewType(int position) {
        if (position == dataList.size())
            return 1;
        else
            return 0;
    }

  

onCreateViewHolder根据viewtype加载ViewHolder.
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == 0) {
            view = LayoutInflater.from(context).inflate(R.layout.grid_redu_item, parent, false);
            return new NormalHolder(view);
        } else {
            view = LayoutInflater.from(context).inflate(R.layout.sample_common_list_footer, parent, false);
            mFooterHolder = new FooterHolder(view);
            return mFooterHolder;
        }
    }
注意getItemCount长度要加1。
 @Override
    public int getItemCount() {
        return dataList.size() + 1;
    }

NormalHolder
 1     class NormalHolder extends RecyclerView.ViewHolder {
 2         ImageView img;
 3         TextView name;
 4
 5         public NormalHolder(View itemView) {
 6             super(itemView);
 7             img = (ImageView) itemView.findViewById(R.id.homepage_grid_picpic);
 8             name = (TextView) itemView.findViewById(R.id.homepage_grid_name);
 9         }
10
11         public void setData(int position) {
12             imageLoader.displayImage(context, imgUrls[position % imgUrls.length], img);
13             name.setText(dataList.get(position));
14         }
15     }

  

FooterHolder
 1     public class FooterHolder extends RecyclerView.ViewHolder {
 2         View mLoadingViewstubstub;
 3         View mEndViewstub;
 4         View mNetworkErrorViewstub;
 5
 6         public FooterHolder(View itemView) {
 7             super(itemView);
 8             mLoadingViewstubstub = itemView.findViewById(R.id.loading_viewstub);
 9             mEndViewstub = itemView.findViewById(R.id.end_viewstub);
10             mNetworkErrorViewstub = itemView.findViewById(R.id.network_error_viewstub);
11         }
12
13         //根据传过来的status控制哪个状态可见
14         public void setData(LoadingFooter.FooterState status) {
15             Log.d("TAG", "reduAdapter" + status + "");
16             switch (status) {
17                 case Normal:
18                     setAllGone();
19                     break;
20                 case Loading:
21                     setAllGone();
22                     mLoadingViewstubstub.setVisibility(View.VISIBLE);
23                     break;
24                 case TheEnd:
25                     setAllGone();
26                     mEndViewstub.setVisibility(View.VISIBLE);
27                     break;
28                 case NetWorkError:
29                     setAllGone();
30                     mNetworkErrorViewstub.setVisibility(View.VISIBLE);
31                     break;
32                 default:
33                     break;
34             }
35
36         }
37
38         //全部不可见
39         void setAllGone() {
40             if (mLoadingViewstubstub != null) {
41                 mLoadingViewstubstub.setVisibility(View.GONE);
42             }
43             if (mEndViewstub != null) {
44                 mEndViewstub.setVisibility(View.GONE);
45             }
46             if (mNetworkErrorViewstub != null) {
47                 mNetworkErrorViewstub.setVisibility(View.GONE);
48             }
49         }
50
51     }

  

  FooterHolder布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/loading_view"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:gravity="center"
    android:orientation="vertical"
    tools:layout_height="wrap_content">

    <include
        android:id="@+id/loading_viewstub"
        layout="@layout/sample_common_list_footer_loading"
        android:layout_width="match_parent"
        android:layout_height="40dp" />

    <include
        android:id="@+id/end_viewstub"
        layout="@layout/sample_common_list_footer_end"
        android:layout_width="match_parent"
        android:layout_height="40dp" />

    <include
        android:id="@+id/network_error_viewstub"
        layout="@layout/sample_common_list_footer_network_error"
        android:layout_width="match_parent"
        android:layout_height="40dp" />
</LinearLayout>

  显示效果:

  主要逻辑放在Fragment里。  首先我们要绑定为RecyclerView绑定一个监听器,监听RecyclerView是否滑到了底部。  Listener代码:  
package com.yctime.truelove.LoadMore;

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

import com.yctime.truelove.ImageLoader.UILPauseOnScrollListener;

/**
 * Created by xjx
 * <p/>
 * 继承自RecyclerView.OnScrollListener,一:可以监听到是否滑动到页面最低部。二:滑动时停止加载图片
 */
public class EndlessRecyclerOnScrollListener extends UILPauseOnScrollListener {

    /**
     * 当前RecyclerView类型
     */
    protected LayoutManagerType layoutManagerType;

    /**
     * 最后一个的位置
     */
    private int[] lastPositions;

    /**
     * 最后一个可见的item的位置
     */
    private int lastVisibleItemPosition;

    /**
     * 当前滑动的状态
     */
    private int currentScrollState = 0;

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

        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

        if (layoutManagerType == null) {
            if (layoutManager instanceof LinearLayoutManager) {
                layoutManagerType = LayoutManagerType.LinearLayout;
            } else if (layoutManager instanceof GridLayoutManager) {
                layoutManagerType = LayoutManagerType.GridLayout;
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                layoutManagerType = LayoutManagerType.StaggeredGridLayout;
            } else {
                throw new RuntimeException(
                        "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
            }
        }

        switch (layoutManagerType) {
            case LinearLayout:
                lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case GridLayout:
                lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case StaggeredGridLayout:
                StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                if (lastPositions == null) {
                    lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
                }
                staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
                lastVisibleItemPosition = findMax(lastPositions);
                break;
        }
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        currentScrollState = newState;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        int visibleItemCount = layoutManager.getChildCount();
        int totalItemCount = layoutManager.getItemCount();
        if ((visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE && (lastVisibleItemPosition) >= totalItemCount - 1)) {
            onLoadNextPage(recyclerView);
        }
    }

    /**
     * 取数组中最大值
     *
     * @param lastPositions
     * @return
     */
    private int findMax(int[] lastPositions) {
        int max = lastPositions[0];
        for (int value : lastPositions) {
            if (value > max) {
                max = value;
            }
        }

        return max;
    }

    public void onLoadNextPage(final View view) {
    }

    public static enum LayoutManagerType {
        LinearLayout,
        StaggeredGridLayout,
        GridLayout
    }
}
 下面是Fragment完整代码:
  1 package com.yctime.truelove.fragment;
  2
  3
  4 import android.support.v4.app.Fragment;
  5 import android.support.v7.widget.DefaultItemAnimator;
  6 import android.support.v7.widget.GridLayoutManager;
  7 import android.support.v7.widget.LinearLayoutManager;
  8 import android.support.v7.widget.RecyclerView;
  9 import android.util.Log;
 10 import android.view.LayoutInflater;
 11 import android.view.View;
 12
 13 import com.yctime.truelove.LoadMore.EndlessRecyclerOnScrollListener;
 14 import com.yctime.truelove.LoadMore.LoadingFooter;
 15 import com.yctime.truelove.MainActivity;
 16 import com.yctime.truelove.Utils.NetworkUtils;
 17 import com.yctime.truelove.login.R;
 18
 19 import java.util.ArrayList;
 20
 21
 22 /**
 23  * A simple {@link Fragment} subclass.
 24  */
 25 public class HomeReDuFragment extends BaseFragment {
 26
 27     private RecyclerView mRecyclerView;
 28     private GridAdapter_Redu gridReDuAdapter;
 29     // 服务器端一共多少条数据
 30     private static final int TOTAL_COUNTER = 50;
 31     // 每一页展示多少条数据
 32     private static final int REQUEST_COUNT = 12;
 33     // 已经获取到多少条数据了
 34     private int mCurrentCounter = 0;
 35     //模拟的数据源
 36     private ArrayList<String> dataList;
 37
 38
 39     protected LoadingFooter.FooterState mState = LoadingFooter.FooterState.Normal;
 40
 41     protected void setState(LoadingFooter.FooterState mState) {
 42         this.mState = mState;
 43         ((MainActivity) mContext).runOnUiThread(new Runnable() {
 44             @Override
 45             public void run() {
 46                 changeAdaperState();
 47             }
 48         });
 49     }
 50
 51     //改变底部bottom的样式
 52     protected void changeAdaperState() {
 53         if (gridReDuAdapter != null && gridReDuAdapter.mFooterHolder != null) {
 54             gridReDuAdapter.mFooterHolder.setData(mState);
 55         }
 56     }
 57
 58     public HomeReDuFragment() {
 59     }
 60
 61
 62     @Override
 63     protected View initView() {
 64         View mView = LayoutInflater.from(mContext).inflate(R.layout.homepage_viewpager_item_redu, null);
 65         mRecyclerView = (RecyclerView) mView.findViewById(R.id.home_page_recyclerview);
 66         return mView;
 67     }
 68
 69     @Override
 70     protected void initData() {
 71         initGridView();
 72     }
 73
 74
 75     private View initGridView() {
 76         mRecyclerView.setHasFixedSize(true);
 77         //滑动暂停加载网络图片,而且可以监听recycler是否滑动到底部
 78         mRecyclerView.addOnScrollListener(mOnScrollListener);
 79         mRecyclerView.setItemAnimator(new DefaultItemAnimator());
 80         gridReDuAdapter = new GridAdapter_Redu(mContext);
 81         gridReDuAdapter.addAll(getRemoteData());
 82         mRecyclerView.setAdapter(gridReDuAdapter);
 83         GridLayoutManager layoutManager = new GridLayoutManager(mContext, 3);
 84         layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
 85         layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
 86             @Override
 87             public int getSpanSize(int position) {
 88                 //如果是最后一个item,则设置占据3列,否则占据1列
 89                 boolean isFooter = position == gridReDuAdapter.getItemCount() - 1;
 90                 return isFooter ? 3 : 1;
 91             }
 92         });
 93         mRecyclerView.setLayoutManager(layoutManager);
 94         return mRecyclerView;
 95     }
 96
 97     private EndlessRecyclerOnScrollListener mOnScrollListener = new EndlessRecyclerOnScrollListener() {
 98         @Override
 99         public void onLoadNextPage(View view) {
100             super.onLoadNextPage(view);
101
102             if (mState == LoadingFooter.FooterState.Loading) {
103                 Log.d("@TAG", "the state is Loading, just wait..");
104                 return;
105             }
106
107             if (mCurrentCounter < TOTAL_COUNTER) {
108                 // loading more
109                 requestData();
110                 Log.d("TAG", "请求数据");
111             } else {
112                 //the end
113                 setState(LoadingFooter.FooterState.TheEnd);
114             }
115         }
116     };
117
118
119     /**
120      * 模拟请求网络
121      */
122     private void requestData() {
123         setState(LoadingFooter.FooterState.Loading);
124         new Thread() {
125             @Override
126             public void run() {
127                 super.run();
128                 try {
129                     Thread.sleep(1000);
130                 } catch (InterruptedException e) {
131                     e.printStackTrace();
132                 }
133                 if (NetworkUtils.isNetAvailable(mContext)) {
134                     //模拟请求远程数据
135                     gridReDuAdapter.addAll(getRemoteData());
136                     //加载完毕时
137                     setState(LoadingFooter.FooterState.Normal);
138                     Log.d("TAG", mCurrentCounter + "");
139                 } else {
140                     //模拟一下网络请求失败的情况
141                     setState(LoadingFooter.FooterState.NetWorkError);
142                 }
143             }
144         }.start();
145     }
146
147     //模拟请求数据
148     private ArrayList<String> getRemoteData() {
149         if (dataList == null)
150             dataList = new ArrayList<>();
151         //每次都清空一下
152         dataList.clear();
153         //要减去adapter最后一页
154         for (int i = 0; i < REQUEST_COUNT; i++) {
155             if (dataList.size() + mCurrentCounter >= TOTAL_COUNTER) {
156                 break;
157             }
158             dataList.add("账号" + (mCurrentCounter + i));
159         }
160         mCurrentCounter += dataList.size();
161         return dataList;
162     }
163
164
165 }
需要注意的是这个方法:
  //改变底部bottom的样式
    protected void changeAdaperState() {
        if (gridReDuAdapter != null && gridReDuAdapter.mFooterHolder != null) {
            gridReDuAdapter.mFooterHolder.setData(mState);
        }
    }
Adapter的应用调用Adapter里面的方法,来切换Adaper的样式。  Adapter完整代码:
  1 package com.yctime.truelove.fragment;
  2
  3 import android.content.Context;
  4 import android.content.Intent;
  5 import android.support.v7.widget.RecyclerView;
  6 import android.util.Log;
  7 import android.view.LayoutInflater;
  8 import android.view.View;
  9 import android.view.ViewGroup;
 10 import android.widget.ImageView;
 11 import android.widget.TextView;
 12
 13 import com.yctime.truelove.ImageLoader.MyImageLoader;
 14 import com.yctime.truelove.ImageLoader.UILImageLoader;
 15 import com.yctime.truelove.LoadMore.LoadingFooter;
 16 import com.yctime.truelove.drawer.MyZoneActivity;
 17 import com.yctime.truelove.login.R;
 18
 19 import java.util.ArrayList;
 20
 21
 22 public class GridAdapter_Redu extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 23
 24
 25     public String[] imgUrls = {
 26             "http://img5.duitang.com/uploads/item/201402/22/20140222113830_X3ddd.jpeg",
 27             "http://v1.qzone.cc/avatar/201403/01/10/36/531147afa4197738.jpg!200x200.jpg",
 28             "http://g.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=e4d7ed147af40ad115b1cfe7621c3de9/b7fd5266d016092445b47837d50735fae6cd340d.jpg",
 29             "http://img5q.duitang.com/uploads/item/201502/19/20150219182507_vGVaK.jpeg",
 30             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/12/2013031212190118646.jpg",
 31             "http://img5.duitang.com/uploads/item/201412/08/20141208221323_YVJFk.png",
 32             "http://cdn.duitang.com/uploads/item/201408/02/20140802222651_GWuU2.png",
 33             "http://ent.dzwww.com/yulezhuanti/mtcbg/201510/W020151027467479100669.jpg",
 34             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/10/2013031009323656495.jpg",
 35             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/12/2013031212295986807.jpg",
 36             "http://f.hiphotos.baidu.com/zhidao/wh%3D600%2C800/sign=10742594d739b6004d9b07b1d9601912/9f2f070828381f30ec9eabdeab014c086f06f0c5.jpg",
 37             "http://a.hiphotos.baidu.com/zhidao/wh%3D600%2C800/sign=5bda8a18a71ea8d38a777c02a73a1c76/5882b2b7d0a20cf4598dc37c77094b36acaf9977.jpg",
 38             "http://a1.att.hudong.com/36/98/300001051406133039983418031.jpg"
 39     };
 40     public Context context;
 41     MyImageLoader imageLoader = new UILImageLoader();
 42     private ArrayList<String> dataList = new ArrayList<>();
 43
 44
 45     private final int NORMALLAYOUT = 0;
 46     private final int FOOTERLAYOUT = 1;
 47     public FooterHolder mFooterHolder;
 48
 49     public GridAdapter_Redu(Context context) {
 50         this.context = context;
 51     }
 52
 53     public void addAll(ArrayList<String> list) {
 54         int lastIndex = this.dataList.size();
 55         if (this.dataList.addAll(list)) {
 56             notifyItemRangeInserted(lastIndex, list.size());
 57         }
 58     }
 59
 60     @Override
 61     public int getItemViewType(int position) {
 62         if (position == dataList.size())
 63             return FOOTERLAYOUT;
 64         else
 65             return NORMALLAYOUT;
 66     }
 67
 68
 69     @Override
 70     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 71         View view;
 72         if (viewType == NORMALLAYOUT) {
 73             view = LayoutInflater.from(context).inflate(R.layout.grid_redu_item, parent, false);
 74             return new NormalHolder(view);
 75         } else {
 76             view = LayoutInflater.from(context).inflate(R.layout.sample_common_list_footer, parent, false);
 77             mFooterHolder = new FooterHolder(view);
 78             return mFooterHolder;
 79         }
 80     }
 81
 82     @Override
 83     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 84         if (holder instanceof NormalHolder) {
 85             //点击事件
 86             holder.itemView.setOnClickListener(new View.OnClickListener() {
 87                 @Override
 88                 public void onClick(View v) {
 89                     Intent intent = new Intent(context, MyZoneActivity.class);
 90                     context.startActivity(intent);
 91                 }
 92             });
 93             ((NormalHolder) holder).setData(position);
 94         }
 95     }
 96
 97     @Override
 98     public int getItemCount() {
 99         return dataList.size() + 1;
100     }
101
102
103     class NormalHolder extends RecyclerView.ViewHolder {
104         ImageView img;
105         TextView name;
106
107         public NormalHolder(View itemView) {
108             super(itemView);
109             img = (ImageView) itemView.findViewById(R.id.homepage_grid_picpic);
110             name = (TextView) itemView.findViewById(R.id.homepage_grid_name);
111         }
112
113         public void setData(int position) {
114             imageLoader.displayImage(context, imgUrls[position % imgUrls.length], img);
115             name.setText(dataList.get(position));
116         }
117     }
118
119     public class FooterHolder extends RecyclerView.ViewHolder {
120         View mLoadingViewstubstub;
121         View mEndViewstub;
122         View mNetworkErrorViewstub;
123
124         public FooterHolder(View itemView) {
125             super(itemView);
126             mLoadingViewstubstub = itemView.findViewById(R.id.loading_viewstub);
127             mEndViewstub = itemView.findViewById(R.id.end_viewstub);
128             mNetworkErrorViewstub = itemView.findViewById(R.id.network_error_viewstub);
129         }
130
131         //根据传过来的status控制哪个状态可见
132         public void setData(LoadingFooter.FooterState status) {
133             Log.d("TAG", "reduAdapter" + status + "");
134             switch (status) {
135                 case Normal:
136                     setAllGone();
137                     break;
138                 case Loading:
139                     setAllGone();
140                     mLoadingViewstubstub.setVisibility(View.VISIBLE);
141                     break;
142                 case TheEnd:
143                     setAllGone();
144                     mEndViewstub.setVisibility(View.VISIBLE);
145                     break;
146                 case NetWorkError:
147                     setAllGone();
148                     mNetworkErrorViewstub.setVisibility(View.VISIBLE);
149                     break;
150                 default:
151                     break;
152             }
153
154         }
155
156         //全部不可见
157         void setAllGone() {
158             if (mLoadingViewstubstub != null) {
159                 mLoadingViewstubstub.setVisibility(View.GONE);
160             }
161             if (mEndViewstub != null) {
162                 mEndViewstub.setVisibility(View.GONE);
163             }
164             if (mNetworkErrorViewstub != null) {
165                 mNetworkErrorViewstub.setVisibility(View.GONE);
166             }
167         }
168
169     }
170
171 }
运行效果:
 


 

  



  

 
 
 

  

时间: 2024-10-02 23:42:21

Android5.0新特性:RecyclerView实现上拉加载更多的相关文章

Recyclerview 实现上拉加载更多

LinearLayoutManager layoutManager; layoutManager = new LinearLayoutManager(getActivity()); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerview.setLayoutManager(layoutManager); mRecyclerview.addOnScrollListener(new OnScrollListen

原生js移动端touch事件实现上拉加载更多

大家都知道jQuery里没有touch事件,所以在移动端使用原生js实现上拉加载效果还是很不错的,闲话不多说,代码如下: 1 //获取要操作的元素 2 var objSection = document.getElementsByTagName("div")[0]; 3 //给元素绑定监听事件 个人习惯把监听事件写在一块 4 objSection.addEventListener("touchstart", touchStart, false); 5 objSect

vue2.0 移动端,下拉刷新,上拉加载更多插件,修改版

在[实现丰盛]的插件基础修改[vue2.0 移动端,下拉刷新,上拉加载更多 插件], 1.修改加载到尾页面,返回顶部刷新数据,无法继续加重下一页 2.修改加载完成文字提示 原文链接:http://www.cnblogs.com/sichaoyun/p/6647458.html <template lang="html"> <div class="yo-scroll" :class="{'down':(state===0),'up':(st

Andorid上拉加载更多的几种实现方式

1.前言 Andriod中上拉加载更多的效果随处可见,因为一次性要展现的数据太多信息量太大的话,给用户的体验就很差(加载慢,界面卡顿.流量消耗大等),而加载更多可以控制每次加载条目的数量以达到快速加载,底部加载更多的方式就显得更人性化,今天就把用过的几种方式总结一下. 2.上拉加载更多的实现方式 ListView控件;作为一种传统列表展现的方式,ListView控件的addHeaderView(...).addFooterView(...)方法很方便的支持头布局.脚布局,参数就是打气筒打出来的布

Android实战简易教程-第五十三枪(通过实现OnScrollListener接口实现上拉加载更多功能)

支持上拉加载更多的控件有很多,但是你知道背后的原理吗?有一些面试官可能会问到这方便的知识,他们认为会用不是目的,懂背后的原理才是真人才.下面我们通过实现OnScrollListener接口实现上拉加载更多的效果,这里用到了回调接口,你需要对回调进行比较好的理解,回调机制是Android中很重要的机制,下面我们看一下代码: 1.定义一个footer.xml,用于下拉提示的效果: <?xml version="1.0" encoding="utf-8"?>

06---数据的下拉刷新上拉加载更多实现

以我最近做的微格项目为例,谈谈关于数据的下拉刷新上拉加载更多实现 页面加载数据: #pragma mark - 加载微博数据 - (void)loadStatusData { _statusesFrame = [NSMutableArray array]; // 微博管理 加载 [StatusManage getStatusesWithSendSinceId:0 maxId:0 Success:^(NSArray *statues) { for (Status *s in statues) {

Android 开发 上拉加载更多功能实现

实现思维 开始之前先废话几句,Android系统没有提供上拉加载的控件,只提供了下拉刷新的SwipeRefreshLayout控件.这个控件我们就不废话,无法实现上拉刷新的功能.现在我们说说上拉加载更多的功能实现 思维步骤: 首先需要创建一个叫页尾的布局文件,它用来在列表的最后面显示使用 接着我们需要想办法在RecyclerView的适配器里导入这个页尾布局.你的列表内容适配器的普通item该如何实现还是如何实现. 为了导入这个页尾布局,我们需要在导入的List长度+1,因为这个页尾布局是另外加

vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多

一.思路分析和效果图 用vue来实现一个瀑布流效果,加载网络图片,同时有下拉刷新和上拉加载更多功能效果.然后针对这几个效果的实现,捋下思路: 根据加载数据的顺序,依次追加标签展示效果: 选择哪种方式实现瀑布流,这里选择绝对定位方式: 关键问题:由于每张图片的宽高不一样,而瀑布流中要求所有图片的宽度一致,高度随宽度等比缩放.而且由于图片的加载是异步延迟.在不知道图片高度的情况下,每个图片所在的item盒子不好绝对定位.因此在渲染页面前先获取所有图片的高度,是解决问题的关键点!这里选择用JS中的Im

android 安卓 listview 支持下拉刷新 上拉加载更多

[1]重写listView import java.text.SimpleDateFormat; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGrou