RecyclerView 的研究和使用
2016-03-11 19:21
525 查看
</pre> 最近在需求中遇到实现图片的滚动的效果,之前使用Gallry 这个控件就可以实现,但是在Gallry 这个控件在anroid中被舍弃掉了,因为它比较耗内存的原因,后来很多中解决方案的出现去解决图片滚动的效果比如用ScrollView 还有用viewPager 这种控件,但是自身都存在着很多缺陷,后来出现了RecyclerView 这个控件,替代了<span style="font-size:18px">Gallry 。</span><p></p><p><span style="font-size:18px"><span style="font-size:18px"></span></span></p><p><span style="font-size:18px"><span style="font-size:18px">具体使用方法:</span></span></p><p><span style="font-size:18px"><span style="font-size:18px">1 在代码中会经常这么写;</span></span></p><p><span style="font-size:18px"><span style="font-size:18px"></span></span></p><p><span style="font-size:18px"><span style="font-size:18px"></span></span></p><pre name="code" class="java">LinearLayoutManager NearbySitesLayoutManager = new LinearLayoutManager(mFragment.getActivity()); NearbySitesLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); mNearBySitesRecyclerView.setLayoutManager(NearbySitesLayoutManager); mNearBySitesRecyclerView.setHasFixedSize(true); mNearbySitesImageAdapter = new NearbyImageAdapter(mFragment.getActivity(), mDetailCacheBean.scenicList); mNearBySitesRecyclerView.setAdapter(mNearbySitesImageAdapter);
</pre><pre name="code" class="java">
(1)首先我们在创建LayoutManager,对于RecyclerView 这个控件 常见用到的LayoutManager 有:
LinearLayoutManager
GridLayoutManager
StaggeredGridLayoutManager
LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。回收或重用一个View的时候,LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法,
(2)
NearbySitesLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL)
是设置滚动方向的
(3)
mNearBySitesRecyclerView.setHasFixedSize(true);
是固定滚动的item 高度,最好设置下
(4)
mNearbySitesImageAdapter = new NearbyImageAdapter(mFragment.getActivity(), mDetailCacheBean.scenicList); mNearBySitesRecyclerView.setAdapter(mNearbySitesImageAdapter);
设置adapter 这个和Gallery 有些类似
其次是adapter 的创建,和之前adapter 创建有些区别,
public class NearbyImageAdapter extends RecyclerView.Adapter<NearbyImageAdapter.ViewHolder> { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {.... // 这里是创建view 的地方,和常规的adaper 的getView 类似,这里还可以设置设置view 的尺寸等 } @Override public void onBindViewHolder(ViewHolder holder, final int position) { // 这个接口是现实显示数据的地方 } public static class ViewHolder extends RecyclerView.ViewHolder { // 这里是创建ViewHolder的地方 和常规的Adaper 类似 } @Override public int getItemCount() { // item 的个数,类似常规的getCount() }其实在adapter 的使用上,和常用的adapter 有些类似,只是表现的形式有点不一样。
再次,其次在 RecyclerView 的控制如何控制每个item 之间的距离时,网上有很多的说法,其中最常见的一种方法,就是继承ItemDecoration 这个类,常见的写法是
public class SpaceItemDecoration extends RecyclerView.ItemDecoration{ private int space; public SpaceItemDecoration(int space) { this.space = space; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if(parent.getChildPosition(view) != 0) outRect.top = space; } }这种方式去控制item 的空隙,最后用addItemDecoration()这种方法设置间距,其实在项目中,我发现一种相对比较简单的方式,比如要是设置在每个item第一张图片的左边没有间距,同时最后一张图片的右边没有间距,同时每个item
的之间的间距为20dp 我想这是常见的滚动需求。我的实现方式如下:
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout...., parent, false); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); params.rightMargin = 20dp; view.setLayoutParams(params); ViewHolder vh = new ViewHolder(view); return vh; } // 在这个方法,首先给个每个item 创建的时候,设置20dp 的空隙,
@Override public void onBindViewHolder(ViewHolder holder, final int position) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams(); if (DataList.size() > 0 && position == DataList.size() - 1) { params.rightMargin = 0; } else { params.rightMargin = 20dp } }
去根据position 设置右间距这是一种控制每个item
间距的一中处理方式。
再次,就是针对每个item 设置点击事件,因为RecyclerView 没有itemOnClick 事件,我们一般会在item 的OnClick 事件中去回调自定义点击接口:
holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mItemClickListener != null) { mItemClickListener.onItemClick(v, .); } } });
通过这种方式去实现点击的回调。
(5) 在使用RecycleView 如果每个item 的宽高的高度不一致,有的时候,会出现高度不一样,解决方案如下:
mMutexRecyclerLayout = (RecyclerView) view.findViewById(R.id.mutex_recycler_layout); MyLayoutManager recyclerLayoutManager = new MyLayoutManager(mContext);
重写recyclerLayoutManager 代码如下:
class MyLayoutManager extends LinearLayoutManager { public MyLayoutManager(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { int childCount = getItemCount(); int maxHigh = 0; for (int i = 0; i < childCount; i++) { View view = recycler.getViewForPosition(i); if (view != null) { measureChild(view, widthSpec, heightSpec); int measuredHeight = view.getMeasuredHeight(); maxHigh = maxHigh >= measuredHeight ? maxHigh : measuredHeight; } } if (maxHigh == 0) { super.onMeasure(recycler, state, widthSpec, heightSpec); } else { setMeasuredDimension(View.MeasureSpec.getSize(widthSpec), maxHigh); } } }
在onMeasure 的时候,根据测量实际的高度 动态的分配测量的高度
(6)
在item 中默认之间是没有设置间隙的,解决这个问题的之前 的方案是:
// 在这个方法,首先给个每个item 创建的时候,设置20dp 的空隙,
@Override public void onBindViewHolder(ViewHolder holder, final int position) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams(); if (DataList.size() > 0 && position == DataList.size() - 1) { params.rightMargin = 0; } else { params.rightMargin = 20dp } }
现在的结局方案是:
mRecyclerView = (RecyclerView) mGiftChoiceLayout.findViewById(R.id.gifts_givers_recyclerview); mGifsGiverChoiceAdapter = new GifsGiverChoiceAdapter(this, mHotelGiftsChoiceModelList); mRecyclerView.setAdapter(mGifsGiverChoiceAdapter); LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(this); recyclerLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); RecyclerViewItemDecoration itemDecoration = new RecyclerViewItemDecoration(LinearLayoutManager.HORIZONTAL); itemDecoration.setColor(Color.WHITE); itemDecoration.setSize(DeviceInfoUtil.getPixelFromDip(10)); mRecyclerView.addItemDecoration(itemDecoration);
自定义itemDecoration 实现 item 之间的空隙: 代码如下
package ctrip.android.hotel.order.librichtexteditor.viewholders; import android.graphics.Canvas; import android.graphics.Paint; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by bkhu on 16/11/22. */ public class RecyclerViewItemDecoration extends RecyclerView.ItemDecoration { /** * 水平方向 */ public static final int HORIZONTAL = LinearLayoutManager.HORIZONTAL; /** * 垂直方向 */ public static final int VERTICAL = LinearLayoutManager.VERTICAL; private Paint mPaint; private int mSize; private int mOrientation; public RecyclerViewItemDecoration(int orientation) { this.mOrientation = orientation; mPaint = new Paint(); } public void setSize(int size) { this.mSize = size; } public void setColor(int color) { mPaint.setColor(color); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); if (mOrientation == HORIZONTAL) { drawVertical(c, parent); } else if (mOrientation == VERTICAL) { drawHorizontal(c, parent); } } private void drawVertical(Canvas canvas, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); int childCount = parent.getChildCount(); int right = 0; for (int i = 0; i < childCount; i++) { View itemView = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) itemView.getLayoutParams(); params.rightMargin = mSize; itemView.setLayoutParams(params); final int left = itemView.getRight(); right = left + mSize; if (i == childCount - 1) right = left; canvas.drawRect(left, top, right, bottom, mPaint); } } private void drawHorizontal(Canvas canvas, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); int bottom = 0; for (int i = 0; i < childCount; i++) { View itemView = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) itemView.getLayoutParams(); params.bottomMargin = mSize; itemView.setLayoutParams(params); final int top = itemView.getBottom(); bottom = top + mSize; if (i == childCount - 1) bottom = top; canvas.drawRect(left, top, right, bottom, mPaint); } } }
这里重写onDraw 这个方法,针对垂直和水平的布局,都能在每个item 的之间设置间隙。
具体实现原理的页面在这里
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0630/4400.html
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories