RecyclerView---高仿网易新闻客户端
来源:互联网 发布:mac怎么关掉客人用户 编辑:程序博客网 时间:2024/05/16 17:17
本文将使用RecyclerView,带领大家实现类似网易新闻客户端的Tab界面效果。
先贴上效果图:
关于RecyclerView的基本使用大家可以参考鸿洋的文章:http://blog.csdn.net/lmj623565791/article/details/45059587
好的,下面进入本文主题。。。
添加依赖包
build.gradle
compile 'com.android.support:recyclerview-v7:23.2.1'
实现界面布局
首先,可以看到每一个Tab有一个背景样式。在drawable文件夹下新建xml文件。
drawable/tv_bg.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <stroke android:width="1dp" android:color="#aaa"/> <solid android:color="#eee"/> <corners android:radius="5dp"/></shape>
矩形的shape,stoke为边框,solid为背景色,corners为圆角矩形的半径。
item.xml
下面,是RecyclerView中每一个Item的布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv" android:layout_width="74dp" android:layout_height="34dp" android:layout_marginTop="5dp" android:layout_marginLeft="5dp" android:background="@drawable/tv_bg" android:gravity="center" android:text="头条" android:textSize="14sp" /> <ImageView android:id="@+id/delelte" android:layout_width="15dp" android:layout_height="15dp" android:visibility="invisible" android:src="@mipmap/delete"/></FrameLayout>
就是一个TextView和一个ImageView,ImageView为左上角小的删除图标,默认情况下是invisible状态。
下面就是Activity的主布局文件:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="8dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="8dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="切换栏目"/> <TextView android:id="@+id/tv_finish" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="完成" android:textColor="@android:color/holo_red_light" android:textSize="16sp" android:visibility="invisible"/> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/darker_gray"/> <android.support.v7.widget.RecyclerView android:id="@+id/recycle_selected" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginRight="8dp" android:text="长按排序或删除" android:textColor="@android:color/darker_gray"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingTop="8dp" android:background="#ddd" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingLeft="16dp" android:text="点击添加更多栏目"/> <android.support.v7.widget.RecyclerView android:id="@+id/recycle_unselected" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp"/> </LinearLayout> </LinearLayout></ScrollView>
准备数据
public class MainActivity extends AppCompatActivity{ ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecycleSelected = (RecyclerView) findViewById(R.id.recycle_selected); mRecycleUnSelected = (RecyclerView) findViewById(R.id.recycle_unselected); mFinishedText = (TextView) findViewById(R.id.tv_finish); initData(); initView(); initEvent(); } ...}
在Activity的onCreate()方法中拿到两个RecyclerView的实例,和右上方”完成”按钮的实例。
先贴一下initData()代码:
private void initData(){ mSelectedDatas = new ArrayList<String>(); mSelectedDatas.add("头条"); mSelectedDatas.add("娱乐"); mSelectedDatas.add("精选"); mSelectedDatas.add("热点"); mSelectedDatas.add("体育"); mSelectedDatas.add("网易号"); mSelectedDatas.add("直播"); mSelectedDatas.add("财经"); mSelectedDatas.add("科技"); mSelectedDatas.add("房产"); mSelectedDatas.add("汽车"); mSelectedDatas.add("轻松一刻"); mSelectedDatas.add("跟帖"); mSelectedDatas.add("图片"); mSelectedDatas.add("段子"); mSelectedDatas.add("家具"); mSelectedDatas.add("游戏"); mSelectedDatas.add("健康"); mSelectedDatas.add("政务"); mSelectedDatas.add("漫画"); mSelectedDatas.add("中国足球"); mSelectedDatas.add("数码"); mSelectedDatas.add("趣闻"); mUnselectedDatas = new ArrayList<String>(); mUnselectedDatas.add("NBA"); mUnselectedDatas.add("社会"); mUnselectedDatas.add("军事"); mUnselectedDatas.add("欧洲杯"); mUnselectedDatas.add("CBA"); mUnselectedDatas.add("跑步"); mUnselectedDatas.add("移动互联"); mUnselectedDatas.add("云课堂"); mUnselectedDatas.add("房产"); mUnselectedDatas.add("旅游"); mUnselectedDatas.add("读书"); mUnselectedDatas.add("酒香"); mUnselectedDatas.add("教育"); mUnselectedDatas.add("亲子"); mUnselectedDatas.add("暴雪游戏"); mUnselectedDatas.add("态度营销"); mUnselectedDatas.add("时尚"); mUnselectedDatas.add("情感"); mUnselectedDatas.add("艺术"); mUnselectedDatas.add("海外"); mUnselectedDatas.add("博客"); mUnselectedDatas.add("论坛"); mUnselectedDatas.add("型男"); mUnselectedDatas.add("萌宠");}
没什么好说的,就是为两个RecyclerView准备了一些数据。
下面看initView()的代码:
private void initView(){ mRecycleSelected.setLayoutManager(new GridLayoutManager(this, 4)); mSelectedAdatper = new SelectedRecycleAdapter(this, mSelectedDatas); mRecycleSelected.setAdapter(mSelectedAdatper); mRecycleSelected.addItemDecoration(new SpaceItemDecoration(8)); mRecycleUnSelected.setLayoutManager(new GridLayoutManager(this, 4)); mUnSelectedAdatper = new UnSelectedRecycleAdapter(this, mUnselectedDatas); mRecycleUnSelected.setAdapter(mUnSelectedAdatper); mRecycleUnSelected.addItemDecoration(new SpaceItemDecoration(8));}
这个方法中,为两个RecyclerView设置了LayoutManager、RecyclerView.Adapter以及RecyclerView.ItemDecoration。其中LayoutManager为GridLayoutManager,列数为4。SpaceItemDecoration主要功能就是为每一个Item添加间隙。不然你会发现所有的Item都挤在一起。
下面看一下ItemDecoration的代码:
public class SpaceItemDecoration extends RecyclerView.ItemDecoration{ private int mSpace; public SpaceItemDecoration(int space) { mSpace = space; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); outRect.left = mSpace; outRect.top = 0; outRect.right = mSpace; outRect.bottom = mSpace; }}
复写了getItemOffsets()方法,其中outRect参数是为每个Item设置一个区域。RecyclerView.ItemDecoration中的onDraw()方法会在outRect所指定的范围进行绘制。通过LinearLayoutManager实现ListView的效果,其中分隔线就在ItemDecoration中进行绘制。详情请参考: Android RecyclerView 使用完全解析 体验艺术般的控件
下面看SelectedRecycleAdapter和UnSelectedRecycleAdapter的代码,两个Adapter的代码很相似,这里我就贴一个:
SelectedRecycleAdapter.java
public class SelectedRecycleAdapter extends RecyclerView.Adapter<SelectedRecycleAdapter.MyViewHolder>{ ... ... private List<String> mDatas; private MainActivity mContext; public SelectedRecycleAdapter(Context context, List<String> datas) { mDatas = datas; mContext = (MainActivity) context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false); MyViewHolder viewHolder = new MyViewHolder(itemView); return viewHolder; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv.setText(mDatas.get(position)); ... ... } @Override public int getItemCount() { return mDatas.size(); } class MyViewHolder extends RecyclerView.ViewHolder { TextView tv; ImageView ivDelete; public MyViewHolder(View itemView) { super(itemView); tv = (TextView) itemView.findViewById(R.id.tv); ivDelete = (ImageView) itemView.findViewById(R.id.delelte); } }}
OK,Adapter主要负责为RecyclerView准备数据,并且Android已经强制我们使用ViewHolde模式来编写Adapter。
至此,整体界面框架就写好了,界面应该能够正常显示了。下面就是事件处理代码。
事件处理
实现点击、长按事件
为RecyclerView提供点击、长按事件,需要自己定义接口,并提供给外部设置回调。
首先是,SelectedRecycleAdapter.java
public class SelectedRecycleAdapter extends RecyclerView.Adapter<SelectedRecycleAdapter.MyViewHolder>{ ... public interface OnItemClickListener { void onItemClickListener(MyViewHolder viewHolder, int pos); void onItemLongClickListener(MyViewHolder viewHolder, int pos); } private OnItemClickListener mListener; public void setOnItemClickListener(OnItemClickListener listener) { this.mListener = listener; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv.setText(mDatas.get(position)); ... if(mListener != null) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mListener.onItemClickListener(holder, position); } }); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mListener.onItemLongClickListener(holder, position); return false; } }); }}
接下来,在外部设置该接口:
MainActivity.java
private void initEvent(){ ... mSelectedAdatper.setOnItemClickListener(new SelectedRecycleAdapter.OnItemClickListener() { @Override public void onItemClickListener(SelectedRecycleAdapter.MyViewHolder viewHolder, int pos) { if(!isDeleteIconsShow) { Toast.makeText(MainActivity.this, mSelectedDatas.get(pos), Toast.LENGTH_SHORT).show(); } } @Override public void onItemLongClickListener(SelectedRecycleAdapter.MyViewHolder viewHolder, int pos) { if(!isDeleteIconsShow) { showAllDeleteIcons(); mFinishedText.setVisibility(View.VISIBLE); } } }); ...}
如果发生点击事件,简单弹一个Toast出来;如果是长按,就显示所有的Delete Icon图标,并且显示右上角”完成”TextView。
长按拖动排序
借助ItemTouchHelper来实现长按拖动排序的功能。首先查看一下这个类的作用:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
大致意思:ItemTouchHelper是一个工具类,为RecyclerView提供拖拽、滑动的支持。并且配合一起工作的还有个ItemTouchHelper.Callback类,这个类内部可以处理用户具体的action事件。
首先,编写Callback类, ItemTouchHelperCallback .java:
/** * Created by hzh on 2016/7/8. * 该类工作与ItemTouchHelper和你的app之间,起一个桥梁的作用 * 主要负责,定义用户drag和swipe的方向,以及当户产生了指定手势会收到相应的回调方法 */public class ItemTouchHelperCallback extends ItemTouchHelper.Callback{ private OnItemPositionChangeListener mListener; //通过构造函数,设置接口实例 public ItemTouchHelperCallback(OnItemPositionChangeListener mListener) { this.mListener = mListener; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { //the direction of item which be dragged final int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN; //can be dragged, can not be swiped return makeMovementFlags(dragFlags, 0); } //接口回调,Adapter根据这个接口交换item的位置 @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { if(mListener != null) { return mListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); } return false; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { } public interface OnItemPositionChangeListener { boolean onItemMove(int fromPos, int toPos); }}
这个类的构造函数,需要外部设置一个OnItemPositionChangeListener 接口传递进来,可以看到这是一个自定义的接口,用来实现拖动排序的功能。复写getMovementFlags()方法,这个方法用来用户控制拖动的方向。onMove()方法,当用户在RecyclerView上move,就会回调这个方法,并且这个方法还会将RecyclerView,SrcViewHolder,targetViewHodler作为参数传递进来,在方法内部调用mListener.onItemMove()让Adapter根据移动的位置变化去更新数据集中的数据的位置。具体大家可以查阅官方文档。
接下来,SelectedRecycleAdapter需要实现这个接口。
SelectedRecycleAdapter.java
public class SelectedRecycleAdapter extends RecyclerView.Adapter<SelectedRecycleAdapter.MyViewHolder> implements ItemTouchHelperCallback.OnItemPositionChangeListener{ ... //根据用户的手势,交换Adapter数据集中item的位置 @Override public boolean onItemMove(int fromPos, int toPos) { Collections.swap(mDatas, fromPos, toPos); notifyItemMoved(fromPos, toPos); return true; } ...}
Adapter实现了自定义接口并复写onItemMove(),根据传过来的两个位置,去交换数据集合中数据的位置,之后调用notifyItemMoved(fromPos, toPos)方法去通过UI,数据发生了移动。这就实现了拖动排序的功能。
接下来看,Activity中使用:
private void initEvent(){ //初始化ItemTouchHelper实例 ItemTouchHelperCallback callback = new ItemTouchHelperCallback(mSelectedAdatper); mItemTouchHelper = new ItemTouchHelper(callback); //mItemTouchHelper关联RecyclerView mItemTouchHelper.attachToRecyclerView(mRecycleSelected); ....}
new了ItemTouchHelper实例,并且ItemTouchHelper需要传入ItemTouchHelper.Callback实例。最后通过ItemTouchHelper.attachToRecyclerView()方法关联具体的RecyclerView。
点击添加、删除Item
直接看代码:
MainActivity.java
private void initEvent(){ ... mSelectedAdatper.setOnDeleteIconClickListener(new SelectedRecycleAdapter.OnDeleteIconClickListener() { @Override public void onDeleteIconClick(int pos) { mUnSelectedAdatper.addData(mSelectedDatas.get(pos), mUnselectedDatas.size()); mSelectedAdatper.removeData(pos); } }); ...}
为delete Icon注册点击事件,在事件处理方法中,实现RecyclerView数据的添加或删除。
下面看一下addData()和removeData()方法的实现:
SelectedRecycleAdapter.java
public class SelectedRecycleAdapter extends RecyclerView.Adapter<SelectedRecycleAdapter.MyViewHolder> implements ItemTouchHelperCallback.OnItemPositionChangeListener{ ... public void addData(String data, int pos) { mDatas.add(pos, data); notifyItemInserted(pos); } public void removeData(int pos) { mDatas.remove(pos); notifyItemRemoved(pos); } ...}
先更新数据集mDatas中的数据,然后通过notifyItemInserted()和notifyItemRemoved()通知所有的观察者Adapter中的数据发生了变化,这样在UI中可以同步更新。
总结
做一个简单的总结:
- RecyclerView基本使用:导入依赖包,RecyclerView、RecyclerView.Adapter、RecyclerView.LayoutManager、RecyclerView.ItemDecoration之间的关系。
- 为RecyclerView实现点击、长按事件处理。
- 了解ItemTouchHelper的功能、用法。可以通过这个类实现RecyclerView的长按拖动排序的功能。
源码下载
- RecyclerView---高仿网易新闻客户端
- 网易新闻客户端(高仿)
- 新闻客户端(高仿网易)
- Toolbar+DrawerLayout高仿网易新闻客户端
- Toolbar+DrawerLayout高仿网易新闻客户端
- Toolbar+DrawerLayout高仿网易新闻客户端
- 仿网易新闻客户端
- 仿网易新闻客户端
- 仿网易新闻客户端
- 仿网易新闻客户端
- RecyclerView学习(二)----高仿网易新闻栏目动画效果
- 【无限互联】高仿网易新闻iOS客户端
- Android高仿网易新闻客户端之首页
- Android高仿网易新闻客户端之动态添加标签
- Android高仿网易新闻客户端之侧滑菜单
- 高仿网易新闻客户端tabs选择频道:RecycleView&ItemTouchHelp
- 史上最简的ViewPagerIndicate,高仿网易新闻客户端效果
- android 仿网易新闻客户端
- iOS开发---本地通知(UILocalNotification)
- CSS水平居中和垂直居中解决方案
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- CSS-DOM设计style属性的艺术
- 组合算法
- RecyclerView---高仿网易新闻客户端
- Python从入门到放弃(一):概论
- 不要轻易挑战用户的习惯,否则会被用户打脸!
- 如何判断链表中存在环路
- 从今天开始,我也开始使用csdn发一些我学习和研究的东西。
- ZOJ - 1149 Dividing
- linux/centos 搭建 bgp 网络
- web支持emoji表情(mysql)
- 乐观锁