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

来自天天博客: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.SwipeRefreshLayout15             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.PinnedRecyclerViewLayout21                 android:id="@+id/recycler_view_pinned_layout"22                 android:layout_width="match_parent" android:layout_height="match_parent">23             <android.support.v7.widget.RecyclerView24                     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             <Button31                     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是被一个PinnedRecyclerViewLayout(https://github.com/wangjiegulu/AndroidBucket/blob/master/src/com/wangjie/androidbucket/support/recyclerview/pinnedlayout/PinnedRecyclerViewLayout.java)包含在里面的。这个在项目AndroidBucket(https://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

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  3. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  4. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  5. Android(安卓)点击文字实现跳转
  6. 安卓布局应用学习代码附带效果图
  7. 27 Android(安卓)ActionBar
  8. LocationManager的使用
  9. android百度地图

随机推荐

  1. Android(安卓)实现中文按拼音排序方法
  2. Android和H5、JS进行交互调用
  3. Android Studio自带的多渠道打包简单使用
  4. Android有望结束碎片化
  5. Android学习笔记2之基于XML的布局
  6. android 本地化[ICU4J Android 框架 API]
  7. Android(安卓)Crash 报告反馈
  8. 初学Android,"Hello World" 第一个Androi
  9. android小白
  10. Android(安卓)调用相机以及调用系统图片