zoukankan      html  css  js  c++  java
  • [Android]使用RecyclerView替代ListView(三)

    以下内容为原创,转载请注明:

    来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4268097.html 

    这次来使用RecyclerView实现PinnedListView的效果,效果很常见:

    开发的代码建立在上一篇([Android]使用RecyclerView替代ListView(二)http://www.cnblogs.com/tiantianbyconan/p/4242541.html)基础之上。

    修改布局如下:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 
     3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     4               android:orientation="vertical"
     5               android:layout_width="match_parent"
     6               android:layout_height="match_parent">
     7 
     8     <android.support.v7.widget.Toolbar
     9             android:id="@+id/recycler_view_pinned_toolbar"
    10             android:layout_height="wrap_content"
    11             android:layout_width="match_parent"
    12             android:background="?attr/colorPrimary"
    13             />
    14     <android.support.v4.widget.SwipeRefreshLayout
    15             android:id="@+id/recycler_view_pinned_srl"
    16             android:layout_width="match_parent"
    17             android:layout_height="wrap_content"
    18             >
    19 
    20         <com.wangjie.androidbucket.support.recyclerview.pinnedlayout.PinnedRecyclerViewLayout
    21                 android:id="@+id/recycler_view_pinned_layout"
    22                 android:layout_width="match_parent" android:layout_height="match_parent">
    23             <android.support.v7.widget.RecyclerView
    24                     android:id="@+id/recycler_view_pinned_rv"
    25                     android:scrollbars="vertical"
    26                     android:layout_width="match_parent"
    27                     android:layout_height="match_parent"
    28                     android:background="#bbccaa"
    29                     />
    30             <Button
    31                     android:id="@+id/recycler_view_pinned_add_btn"
    32                     android:layout_width="wrap_content" android:layout_height="wrap_content"
    33                     android:layout_centerVertical="true"
    34                     android:background="#abcabc"
    35                     android:text="add"
    36                     />
    37 
    38         </com.wangjie.androidbucket.support.recyclerview.pinnedlayout.PinnedRecyclerViewLayout>
    39 
    40     </android.support.v4.widget.SwipeRefreshLayout>
    41 
    42 </LinearLayout>

    可以看到RecyclerView是被一个PinnedRecyclerViewLayouthttps://github.com/wangjiegulu/AndroidBucket/blob/master/src/com/wangjie/androidbucket/support/recyclerview/pinnedlayout/PinnedRecyclerViewLayout.java包含在里面的。这个在项目AndroidBuckethttps://github.com/wangjiegulu/AndroidBucket中。先看看代码中怎么使用吧,具体实现待会说。

    1 pinnedLayout.initRecyclerPinned(recyclerView, layoutManager, LayoutInflater.from(context).inflate(R.layout.recycler_view_item_float, null));
    2 pinnedLayout.setOnRecyclerViewPinnedViewListener(this);

    如上,使用方式很简单:

    Line1:初始化绑定PinnedRecyclerViewLayout和RecyclerView,并设置需要被顶上去的pinnedView

    Line2:设置OnRecyclerViewPinnedViewListener,作用是在顶部被顶上去替换掉的时候,会回调重新渲染数据,传入的OnRecyclerViewPinnedViewListener是this,显然,此Activity实现了这个接口,实现代码如下:

     1 // 渲染pinnedView数据
     2     @Override
     3     public void onPinnedViewRender(PinnedRecyclerViewLayout pinnedRecyclerViewLayout, View pinnedView, int position) {
     4         switch (pinnedRecyclerViewLayout.getId()) {
     5             case R.id.recycler_view_pinned_layout:
     6                 TextView nameTv = (TextView) pinnedView.findViewById(R.id.recycler_view_item_float_name_tv);
     7                 nameTv.setText(personList.get(position).getName());
     8                 TextView ageTv = (TextView) pinnedView.findViewById(R.id.recycler_view_item_float_age_tv);
     9                 ageTv.setText(personList.get(position).getAge() + "岁");
    10                 break;
    11         }
    12     }

    然后,我们来看看PinnedRecyclerViewLayout是怎么实现的。

      1 /**
      2  * Author: wangjie
      3  * Email: tiantian.china.2@gmail.com
      4  * Date: 2/2/15.
      5  */
      6 public class PinnedRecyclerViewLayout extends RelativeLayout {
      7 
      8     private static final String TAG = PinnedRecyclerViewLayout.class.getSimpleName();
      9 
     10     public static interface OnRecyclerViewPinnedViewListener {
     11         void onPinnedViewRender(PinnedRecyclerViewLayout pinnedRecyclerViewLayout, View pinnedView, int position);
     12     }
     13 
     14     private OnRecyclerViewPinnedViewListener onRecyclerViewPinnedViewListener;
     15 
     16     public void setOnRecyclerViewPinnedViewListener(OnRecyclerViewPinnedViewListener onRecyclerViewPinnedViewListener) {
     17         this.onRecyclerViewPinnedViewListener = onRecyclerViewPinnedViewListener;
     18     }
     19 
     20     public PinnedRecyclerViewLayout(Context context) {
     21         super(context);
     22         init(context);
     23     }
     24 
     25     public PinnedRecyclerViewLayout(Context context, AttributeSet attrs) {
     26         super(context, attrs);
     27         init(context);
     28     }
     29 
     30     public PinnedRecyclerViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
     31         super(context, attrs, defStyleAttr);
     32         init(context);
     33     }
     34 
     35     private void init(Context context) {
     36     }
     37 
     38     private View pinnedView;
     39     private ABaseLinearLayoutManager layoutManager;
     40 
     41     public void initRecyclerPinned(RecyclerView recyclerView, ABaseLinearLayoutManager layoutManager, View pinnedView) {
     42         this.pinnedView = pinnedView;
     43         this.layoutManager = layoutManager;
     44         this.addView(this.pinnedView);
     45         RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
     46         this.pinnedView.setLayoutParams(lp);
     47         layoutManager.getRecyclerViewScrollManager().addScrollListener(recyclerView, new OnRecyclerViewScrollListener() {
     48             @Override
     49             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
     50             }
     51 
     52             @Override
     53             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
     54                 refreshPinnedView();
     55             }
     56         });
     57         pinnedView.setVisibility(GONE);
     58     }
     59 
     60     // 保存上次的position
     61     private int lastPosition = RecyclerView.NO_POSITION;
     62 
     63     public void refreshPinnedView() {
     64         if (null == pinnedView || null == layoutManager) {
     65             Logger.e(TAG, "Please init pinnedView and layoutManager with initRecyclerPinned method first!");
     66             return;
     67         }
     68         if (VISIBLE != pinnedView.getVisibility()) {
     69             pinnedView.setVisibility(VISIBLE);
     70         }
     71         int curPosition = layoutManager.findFirstVisibleItemPosition();
     72         if (RecyclerView.NO_POSITION == curPosition) {
     73             return;
     74         }
     75         View curItemView = layoutManager.findViewByPosition(curPosition);
     76         if (null == curItemView) {
     77             return;
     78         }
     79         // 如果当前的curPosition和上次的lastPosition不一样,则说明需要重新刷新数据,避免curPosition一样的情况下重复刷新相同数据
     80         if (curPosition != lastPosition) {
     81             if (null != onRecyclerViewPinnedViewListener) {
     82                 onRecyclerViewPinnedViewListener.onPinnedViewRender(this, pinnedView, curPosition);
     83             }
     84             lastPosition = curPosition;
     85         }
     86 
     87         int displayTop;
     88         int itemHeight = curItemView.getHeight();
     89         int curTop = curItemView.getTop();
     90         int floatHeight = pinnedView.getHeight();
     91         if (curTop < floatHeight - itemHeight) {
     92             displayTop = itemHeight + curTop - floatHeight;
     93         } else {
     94             displayTop = 0;
     95         }
     96         RelativeLayout.LayoutParams lp = (LayoutParams) pinnedView.getLayoutParams();
     97         lp.topMargin = displayTop;
     98         pinnedView.setLayoutParams(lp);
     99         pinnedView.invalidate();
    100     }
    101 
    102 
    103 }

    这个PinnedRecyclerViewLayout 是继承RelativeLayout的,因为我们需要在里面添加一个被顶上去的pinnedView,需要覆盖在RecyclerView上面。

    Line44:把传进来的pinnedView增加到PinnedRecyclerViewLayout 里面

    Line47~56:在ABaseLinearLayoutManager中增加一个滚动的监听器,因为我们需要在滚动的时候动态的改变pinnedView的位置,这样才能模拟顶上去的效果。并滚动时调用refreshPinnedView来刷新pinnedView的位置。

    Line57:因为在调用initRecyclerPinned方法时,RecyclerView可能还没有数据源,所以不需要显示这个pinnedView,等到真正滚动的时候再显示就可以了。

    refreshPinnedView()方法的作用是在滚动的同时用来刷新pinnedView的位置和显示的数据:

    Line71~78:通过layoutManager获取当前第一个显示的数据position,然后根据position获取当前第一个显示的View。

    Line79~85:如果当前的curPosition和上次的lastPosition不一样,则说明需要重新刷新数据,避免curPosition一样的情况下重复刷新相同数据。

    Line87~95:根据当前第一个显示的View,根据它的top、它的高度和pinnedView的高度计算出pinnedView需要往上移动的距离(画个几何图一目了然了)。

    Line96~99:刷新pinnedView的位置

    示例代码:

    https://github.com/wangjiegulu/RecyclerViewSample

    [Android]使用RecyclerView替代ListView(一)

    http://www.cnblogs.com/tiantianbyconan/p/4232560.html

    [Android]使用RecyclerView替代ListView(二) 

    http://www.cnblogs.com/tiantianbyconan/p/4242541.html

  • 相关阅读:
    Coded UI Test(二)创建一个Coded UI Test
    Coded UI Test(一)概述
    面向接口编程思想与实现可维护的代码 (一)
    KMP算法字符串模式匹配算法
    新的博客,新的起点
    第十三章:字符串 《Thinking in java》学习笔记
    稀疏矩阵三元组表来压缩存储及转置
    eclipse svn的使用+小组开发
    第十一章:持有对象 《Thinking in java》学习笔记
    双端队列(deque)课堂跳了的内容
  • 原文地址:https://www.cnblogs.com/tiantianbyconan/p/4268097.html
Copyright © 2011-2022 走看看