首页 文章 精选 留言 我的

精选列表

搜索[流式渲染],共10001篇文章
优秀的个人博客,低调大师

Android RecyclerView详解及实现瀑布流式布局

RecyclerView一个可以代替ListView和GridView的控件,那么RecyclerView到底比他们好在哪里? RecyclerView架构提供了一种插拔式的体验,所以实现了代码的高度解耦,使用起来也异常的灵活。 我们可以通过设置它的LayoutManager控制其显示的方式,通过ItemDecoration控制Item间的间隔,通过ItemAnimator控制Item的增删动画 RecyclerView.LayoutManager提供了三个实现类其中LinearLayoutManager 现行管理器,支持横向、纵向,GridLayoutManager 网格布局管理器,StaggeredGridLayoutManager 瀑布就式布局管理器 那么先从LinearLayoutManager看起 先在gradle中引用compile 'com.android.support:recyclerview-v7:23.4.0' Activity布局文件如下: <?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.lg.recyclerviewdemo.LinearActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/linear_recycler" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> item布局文件: <?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns: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:gravity="center"> <ImageView android:layout_width="70dp" android:layout_height="70dp" android:src="@drawable/android"/> <TextView android:id="@+id/recycler_item_tv" android:layout_width="wrap_content" android:layout_height="100dp" android:layout_marginLeft="20dp" android:gravity="center" android:textColor="@color/colorPrimary" android:textSize="20sp" android:textStyle="bold"/> </LinearLayout> </RelativeLayout> 在Acitvity中初始化数据: mDatas=newArrayList<String>(); for(inti=1;i<=65;i++){ mDatas.add("item"+i); } 核心代码: recyclerAdapter=newRecyclerAdapter(); //设置布局管理器 linear_recycler.setLayoutManager(newLinearLayoutManager(this)); //设置adapter linear_recycler.setAdapter(recyclerAdapter); //添加分割线 linear_recycler.addItemDecoration(newDividerLinearItemDecoration(this,DividerLinearItemDecoration.VERTICAL_LIST)); 接下来自制adapter: publicclassRecyclerAdapterextendsRecyclerView.Adapter<LinearHolder>{ privateViewview; @Override publicLinearHolderonCreateViewHolder(ViewGroupparent,intviewType){ //利用反射将item的布局加载出来 view=LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item,null); //new一个我们的ViewHolder,findViewById操作都在LinearHolder的构造方法中进行了 returnnewLinearHolder(view); } @Override publicvoidonBindViewHolder(LinearHolderholder,intposition){ holder.recycler_item.setText(MainActivity.mDatas.get(position)); } @Override publicintgetItemCount(){ returnMainActivity.mDatas.size(); } } classLinearHolderextendsRecyclerView.ViewHolder{ TextViewrecycler_item; publicLinearHolder(ViewitemView){ super(itemView); recycler_item=(TextView)itemView.findViewById(R.id.recycler_item_tv); } 再绘画它的分割线: publicclassDividerLinearItemDecorationextendsRecyclerView.ItemDecoration{ privatestaticfinalint[]ATTRS=newint[]{ android.R.attr.listDivider }; publicstaticfinalintHORIZONTAL_LIST=LinearLayoutManager.HORIZONTAL; publicstaticfinalintVERTICAL_LIST=LinearLayoutManager.VERTICAL; privateDrawablemDivider; privateintmOrientation; publicDividerLinearItemDecoration(Contextcontext,intorientation){ finalTypedArraya=context.obtainStyledAttributes(ATTRS); mDivider=a.getDrawable(0); a.recycle(); setOrientation(orientation); } publicvoidsetOrientation(intorientation){ if(orientation!=HORIZONTAL_LIST&&orientation!=VERTICAL_LIST){ thrownewIllegalArgumentException("invalidorientation"); } mOrientation=orientation; } @Override publicvoidonDraw(Canvasc,RecyclerViewparent){ if(mOrientation==VERTICAL_LIST){ drawVertical(c,parent); }else{ drawHorizontal(c,parent); } } publicvoiddrawVertical(Canvasc,RecyclerViewparent){ finalintleft=parent.getPaddingLeft(); finalintright=parent.getWidth()-parent.getPaddingRight(); finalintchildCount=parent.getChildCount(); for(inti=0;i<childCount;i++){ finalViewchild=parent.getChildAt(i); RecyclerViewv=newRecyclerView(parent.getContext()); finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child .getLayoutParams(); finalinttop=child.getBottom()+params.bottomMargin; finalintbottom=top+mDivider.getIntrinsicHeight(); mDivider.setBounds(left,top,right,bottom); mDivider.draw(c); } } publicvoiddrawHorizontal(Canvasc,RecyclerViewparent){ finalinttop=parent.getPaddingTop(); finalintbottom=parent.getHeight()-parent.getPaddingBottom(); finalintchildCount=parent.getChildCount(); for(inti=0;i<childCount;i++){ finalViewchild=parent.getChildAt(i); finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child .getLayoutParams(); finalintleft=child.getRight()+params.rightMargin; finalintright=left+mDivider.getIntrinsicHeight(); mDivider.setBounds(left,top,right,bottom); mDivider.draw(c); } } @Override publicvoidgetItemOffsets(RectoutRect,intitemPosition,RecyclerViewparent){ if(mOrientation==VERTICAL_LIST){ outRect.set(0,0,0,mDivider.getIntrinsicHeight()); }else{ outRect.set(0,0,mDivider.getIntrinsicWidth(),0); } } } 好了,我们来看看效果: 嘛,貌似和ListView没什么区别,还这么麻烦 别急,我们试试GridLayoutManager 很简单,我们只需要改变LayoutManager和ItemDecoration就行了: grid_recycler.setLayoutManager(newGridLayoutManager(this,2)); grid_recycler.addItemDecoration(newDividerGridItemDecoration(this)); DividerGridItemDecoration代码: publicclassDividerGridItemDecorationextendsRecyclerView.ItemDecoration{ privatestaticfinalint[]ATTRS=newint[]{android.R.attr.listDivider}; privateDrawablemDivider; publicDividerGridItemDecoration(Contextcontext) { finalTypedArraya=context.obtainStyledAttributes(ATTRS); mDivider=a.getDrawable(0); a.recycle(); } @Override publicvoidonDraw(Canvasc,RecyclerViewparent,RecyclerView.Statestate) { drawHorizontal(c,parent); drawVertical(c,parent); } privateintgetSpanCount(RecyclerViewparent) { //列数 intspanCount=-1; RecyclerView.LayoutManagerlayoutManager=parent.getLayoutManager(); if(layoutManagerinstanceofGridLayoutManager) { spanCount=((GridLayoutManager)layoutManager).getSpanCount(); }elseif(layoutManagerinstanceofStaggeredGridLayoutManager) { spanCount=((StaggeredGridLayoutManager)layoutManager) .getSpanCount(); } returnspanCount; } publicvoiddrawHorizontal(Canvasc,RecyclerViewparent) { intchildCount=parent.getChildCount(); for(inti=0;i<childCount;i++) { finalViewchild=parent.getChildAt(i); finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child .getLayoutParams(); finalintleft=child.getLeft()-params.leftMargin; finalintright=child.getRight()+params.rightMargin +mDivider.getIntrinsicWidth(); finalinttop=child.getBottom()+params.bottomMargin; finalintbottom=top+mDivider.getIntrinsicHeight(); mDivider.setBounds(left,top,right,bottom); mDivider.draw(c); } } publicvoiddrawVertical(Canvasc,RecyclerViewparent) { finalintchildCount=parent.getChildCount(); for(inti=0;i<childCount;i++) { finalViewchild=parent.getChildAt(i); finalRecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)child .getLayoutParams(); finalinttop=child.getTop()-params.topMargin; finalintbottom=child.getBottom()+params.bottomMargin; finalintleft=child.getRight()+params.rightMargin; finalintright=left+mDivider.getIntrinsicWidth(); mDivider.setBounds(left,top,right,bottom); mDivider.draw(c); } } privatebooleanisLastColum(RecyclerViewparent,intpos,intspanCount, intchildCount) { RecyclerView.LayoutManagerlayoutManager=parent.getLayoutManager(); if(layoutManagerinstanceofGridLayoutManager) { if((pos+1)%spanCount==0)//如果是最后一列,则不需要绘制右边 { returntrue; } }elseif(layoutManagerinstanceofStaggeredGridLayoutManager) { intorientation=((StaggeredGridLayoutManager)layoutManager) .getOrientation(); if(orientation==StaggeredGridLayoutManager.VERTICAL) { if((pos+1)%spanCount==0)//如果是最后一列,则不需要绘制右边 { returntrue; } }else { childCount=childCount-childCount%spanCount; if(pos>=childCount)//如果是最后一列,则不需要绘制右边 returntrue; } } returnfalse; } privatebooleanisLastRaw(RecyclerViewparent,intpos,intspanCount, intchildCount) { RecyclerView.LayoutManagerlayoutManager=parent.getLayoutManager(); if(layoutManagerinstanceofGridLayoutManager) { childCount=childCount-childCount%spanCount; if(pos>=childCount)//如果是最后一行,则不需要绘制底部 returntrue; }elseif(layoutManagerinstanceofStaggeredGridLayoutManager) { intorientation=((StaggeredGridLayoutManager)layoutManager) .getOrientation(); //StaggeredGridLayoutManager且纵向滚动 if(orientation==StaggeredGridLayoutManager.VERTICAL) { childCount=childCount-childCount%spanCount; //如果是最后一行,则不需要绘制底部 if(pos>=childCount) returntrue; }else //StaggeredGridLayoutManager且横向滚动 { //如果是最后一行,则不需要绘制底部 if((pos+1)%spanCount==0) { returntrue; } } } returnfalse; } @Override publicvoidgetItemOffsets(RectoutRect,intitemPosition, RecyclerViewparent) { intspanCount=getSpanCount(parent); intchildCount=parent.getAdapter().getItemCount(); if(isLastRaw(parent,itemPosition,spanCount,childCount))//如果是最后一行,则不需要绘制底部 { outRect.set(0,0,mDivider.getIntrinsicWidth(),0); }elseif(isLastColum(parent,itemPosition,spanCount,childCount))//如果是最后一列,则不需要绘制右边 { outRect.set(0,0,0,mDivider.getIntrinsicHeight()); }else { outRect.set(0,0,mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } } 看下效果吧: 渍,有点意思,不过也没那么神乎其神啊 别忘了,我们还有个StaggeredGridLayoutManager没用 展示了那么多纵向的,我们来个横向的,同样改变LayoutManager stag_grid_recycler.setLayoutManager(newStaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL)); 看下效果: 一个RecyclerView就能实现这么多功能,确实强大啊 不过,你以为这样就完了?下来要放大招了 看标题,瀑布流有木有,你用ListView不会那么简单就实现吧,但是用RecyclerView分分钟 稍微改变item布局,让图片放在字的上面 我们在onBindViewHolder给item设置随机高度: LayoutParamslayoutParams=holder.sg_item.getLayoutParams(); layoutParams.height=heights.get(position); 看下大招效果: 我就问你6不6,6的话还不快关注我(嘎嘎) 好吧,可能吓到你了,什么?点击事件? 好吧,很不幸告诉你,要自己写,对,就是要自己写。 前面已经说过了,RecyclerView实现了高度解耦,非常的灵活(你要干什么,自己去写)。那就写吧! 先写个接口: publicinterfaceOnItemClickLitener{ /*点击事件*/ voidonItemClick(Viewview,intposition); /*长按事件*/ voidonItemLongClick(Viewview,intposition); } 在adapter中加入代码: privateOnItemClickLitenermOnItemClickLitener; publicvoidsetOnItemClickLitener(OnItemClickLitenermOnItemClickLitener){ this.mOnItemClickLitener=mOnItemClickLitener; } onBindViewHolder方法中加入: holder.sg_item.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(Viewv){ intpos=holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView,pos); } }); holder.sg_item.setOnLongClickListener(newView.OnLongClickListener(){ @Override publicbooleanonLongClick(Viewv){ intpos=holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView,pos); returnfalse; } }); 然后在Activity中调用: staggeredGridAdapter.setOnItemClickLitener(newOnItemClickLitener(){ @Override publicvoidonItemClick(Viewview,intposition){ staggeredGridAdapter.notifyItemRemoved(position); } @Override publicvoidonItemLongClick(Viewview,finalintposition){ android.support.v7.app.AlertDialog.Builderbuilder=newAlertDialog.Builder(StaggeredGridVActivity.this); builder.setTitle("Delete?") .setNegativeButton("no",null) .setPositiveButton("yes",newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ staggeredGridAdapter.notifyItemRemoved(position); Toast.makeText(StaggeredGridVActivity.this,MainActivity.mDatas.get(position),Toast.LENGTH_SHORT).show(); } }).show(); } }); 效果图: 怎么样?厉害吧。不过你以为这样就完了? 如果我想要将item托拉拽再加上侧滑删除呢? 首先,如果要实现托拉拽功能,那item长按事件还是不要写代码的,避免事件冲突 然后在Activity中加入代码: ItemTouchHelperitemTouchHelper=newItemTouchHelper(callback); itemTouchHelper.attachToRecyclerView(stag_v_recycler); callback代码: ItemTouchHelper.Callbackcallback=newItemTouchHelper.Callback(){ //这个方法是用来设置我们拖动的方向以及侧滑的方向的 @Override publicintgetMovementFlags(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder){ //设置拖拽方向为上下左右 finalintdragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN| ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT; //设置侧滑方向为从左到右和从右到左都可以 finalintswipeFlags=ItemTouchHelper.START|ItemTouchHelper.END; //将方向参数设置进去 returnmakeMovementFlags(dragFlags,swipeFlags); } /** *@paramrecyclerView *@paramviewHolder拖动的ViewHolder *@paramtarget目标位置的ViewHolder *@return */ @Override publicbooleanonMove(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,RecyclerView.ViewHoldertarget){ intfromPosition=viewHolder.getAdapterPosition();//得到拖动ViewHolder的position inttoPosition=target.getAdapterPosition();//得到目标ViewHolder的position if(fromPosition<toPosition){ //分别把中间所有的item的位置重新交换 for(inti=fromPosition;i<toPosition;i++){ Collections.swap(MainActivity.mDatas,i,i+1); } }else{ for(inti=fromPosition;i>toPosition;i--){ Collections.swap(MainActivity.mDatas,i,i-1); } } staggeredGridAdapter.notifyItemMoved(fromPosition,toPosition); //返回true表示执行拖动 returntrue; } @Override publicvoidonSwiped(RecyclerView.ViewHolderviewHolder,intdirection){ intposition=viewHolder.getAdapterPosition(); staggeredGridAdapter.notifyItemRemoved(position); } @Override publicvoidonChildDraw(Canvasc,RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,floatdX,floatdY,intactionState,booleanisCurrentlyActive){ super.onChildDraw(c,recyclerView,viewHolder,dX,dY,actionState,isCurrentlyActive); if(actionState==ItemTouchHelper.ACTION_STATE_SWIPE){ //滑动时改变Item的透明度 finalfloatalpha=1-Math.abs(dX)/(float)viewHolder.itemView.getWidth(); viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } } }; OK,我们来看看效果: 如果你喜欢我的文章,那就关注我的博客吧,我会不定期的发些技术贴 源码地址:http://down.51cto.com/data/2222200

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册