Android中RecyclerView实现多级折叠列表效果(二)

前言

在本文开始之前请大家先看一下这篇文章:http://www.jb51.net/article/113510.htm

上面的这篇文章是之前写的,里面发现有很多不好用地方,也学到些新姿势,改动了许多地方。下面来看看详细的介绍:

要点:

1.可以通过后台控制Item的展示.

2.TreeRecyclerAdapter,可以展开,折叠.多级展示

3.adapter可以使用装饰者模式进行扩展.支持EmptyAdapter.可以添加headview和footview

4.item的样式可以编写文档,type与Class进行对应,实现后台控置,相同Item复用.

思路:(包含第一篇的思路)

1.adapter应该只需要关心List<baseItem> datas 的内容

2.把每个item看成独立的个体. 布局样式,每行所占比,onbindViewHolder由各个item实现。

3.每一个item应该只关心自己的数据和自己的下一级的数据,不会去关心上上级,下下级

4.展开的实现,点击时item把子数据拿出来,然后添加到adapter的datas中,变成同级,因为只会展开自己的下级数据。

5.折叠的实现,拿到下级数据(可以理解因为一个文件夹下文件),然后从adapter的datas中删除这些数据。

6.后台控制可以通过初始化注册的方法,将Item的Class注册.保存到集合里

7.后台返回字段,获取对应class文件,通过Class.newInstance()方法构建实例.

8.将ViewHolder与Adapter写成通用的,不需要再写多个Adatper与ViewHolder,只需要写多个Baseitem.与BaseItamData(JavaBean).

目录介绍

+ 1.Adapter
 * Wapper------扩展的wapper,
 * EmptyWapper --------当无数据时显示页面.
 * HeaderAndFootWapper --------添加头部view和尾部view

 - BaseRecyclerAdapter --------封装的Adatper基类
 - ItemManager --------接口,管理Adatper刷新,增删操作
 - TreeRecyclerAdapter ----多级列表,树形结构的adapter
 - TreeRecyclerViewType ----多级列表的显示样式,枚举
 - ViewHolder----封装的通用viewHodler

* 2.base
BaseItem<D extends BaseItemData> ------item的封装
BaseItemData-----item的数据要求.javabean需要继承该类.

* 3.factory
ItemConfig ----添加item的class,配置样式
Itemfactory----通过class生成BaseItem的工厂类

* 4.view
TreeItem ----树形列表的子item
TreeItemGroup ----树形列表的父item
TreeParent---TreeItemGroup 实现该接口
TreeSelectItemGroup---可以选中子item的TreeItemGroup. demo:见购物页面

来张丑丑的图:

下面贴出部分代码:

(一).BaseRecyclerAdapter :

/**
 * 普通BaseRecyclerAdapter,itme无父子关系.
 * 限定泛型为BaseItem的子类.
 * 通过BaseItem去处理ViewHolder
 */
public class BaseRecyclerAdapter<T extends BaseItem> extends
 RecyclerView.Adapter<ViewHolder> {

 private List<T> mDatas;//展示数据
 private ItemManager<T> mItemManager;
 private CheckItem mCheckItem;

 @Override
 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 //看源码,这里的parent就是Recyclerview,所以不会为null.可以通过它拿到context
 return ViewHolder.createViewHolder(parent.getContext(), parent, viewType);
 }

 @Override
 public void onBindViewHolder(ViewHolder holder, int position) {
 T t = getDatas().get(position);
 //检查是否绑定了ItemManage,因为item需要通过ItemManage告诉adapter刷新,增删
 checkItemManage(t);
 //具体onBindViewHolder放到item里面去实现
 t.onBindViewHolder(holder);
 //实现点击事件
 onBindViewHolderClick(holder);
 }
 /**
 * 实现item的点击事件
 *
 * @param holder 绑定点击事件的ViewHolder
 */
 public void onBindViewHolderClick(final ViewHolder holder) {
 //判断当前holder是否已经设置了点击事件
 if (!holder.itemView.hasOnClickListeners()) {
  holder.itemView.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   //获得holder的position
   int layoutPosition = holder.getLayoutPosition();
   //检查position是否可以点击
   if (getCheckItem().checkPosition(layoutPosition)) {
   //检查并得到真实的position
   int itemPosition = getCheckItem().getAfterCheckingPosition(layoutPosition);
   //拿到对应item,回调.
   getDatas().get(itemPosition).onClick();
   }
  }
  });
 }
 }
 /**
 * 这里将LayoutId作为type,因为LayoutId不可能相同,个人觉得可以作为item的标志
 * @param position
 * @return
 */
 @Override
 public int getItemViewType(int position) {
 return mDatas.get(position).getLayoutId();
 }

 @Override
 public int getItemCount() {
 return mDatas == null ? 0 : mDatas.size();
 }

 public List<T> getDatas() {
 if (mDatas == null) {
  mDatas = new ArrayList<>();
 }
 return mDatas;
 }

 /**
 * 需要手动setDatas(List<T> datas),否则数据为空
 * @param datas
 */
 public void setDatas(List<T> datas) {
 if (datas != null) {
  mDatas = datas;
  getItemManager().notifyDataSetChanged();
 }
 }
}

(二).TreeRecyclerAdapter

/**
 * Created by baozi on 2017/4/20.
 * 树级结构recycleradapter.
 * item之间有子父级关系,
 */

public class TreeRecyclerAdapter<T extends TreeItem> extends BaseRecyclerAdapter<T> {

 private TreeRecyclerViewType type;
 /**
 * 最初的数据.没有经过增删操作.
 */
 private List<T> initialDatas;

 @Override
 public void onBindViewHolderClick(final ViewHolder holder) {
 //判断是否已有点击监听
 if (!holder.itemView.hasOnClickListeners()) {
  holder.itemView.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   //获得holder的LayoutPosition.
   int layoutPosition = holder.getLayoutPosition();
   //判断是否需要点击
   if (getCheckItem().checkPosition(layoutPosition)) {
   int itemPosition = getCheckItem().getAfterCheckingPosition(layoutPosition);
   //展开,折叠和item点击不应该同时响应事件.
   if (type != TreeRecyclerViewType.SHOW_ALL) {
    //展开,折叠
    expandOrCollapse(itemPosition);
   } else {
    //点击事件
    T item = getDatas().get(itemPosition);
    TreeItemGroup itemParentItem = item.getParentItem();
    //判断上一级是否需要拦截这次事件,只处理当前item的上级,不关心上上级如何处理.
    if (itemParentItem != null && itemParentItem.onInterceptClick(item)) {
    return;
    }
    item.onClick();
   }
   }
  }
  });
 }
 }

 @Override
 public void setDatas(List<T> datas) {
 //保存未修改过的List
 initialDatas = datas;
 //如果展开显示全部,则需要递归处理添加所以的item
 if (type == TreeRecyclerViewType.SHOW_ALL) {
  for (int i = 0; i < datas.size(); i++) {
   T t = datas.get(i);
  getDatas().add(t);
  //判断item是否是TreeItemGroup
  if (t instanceof TreeItemGroup) {
   List childs = ((TreeItemGroup) t).getAllChilds();
   if (childs != null) {
   //添加到item的后面.
   getDatas().addAll(childs);
   }
  }
  }
 } else {
  super.setDatas(datas);
 }
 }

 /**
 * 相应RecyclerView的点击事件 展开或关闭某节点
 *
 * @param position 触发的条目
 */
 private void expandOrCollapse(int position) {
 T baseItem = getDatas().get(position);
 if (baseItem instanceof TreeItemGroup && ((TreeItemGroup) baseItem).isCanChangeExpand()) {
  TreeItemGroup treeParentItem = (TreeItemGroup) baseItem;
  boolean expand = treeParentItem.isExpand();
  List<T> allChilds = treeParentItem.getAllChilds();
  if (expand) {
  getDatas().removeAll(allChilds);
  treeParentItem.onCollapse();
  treeParentItem.setExpand(false);
  } else {
  getDatas().addAll(position + 1, allChilds);
  treeParentItem.onExpand();
  treeParentItem.setExpand(true);
  }
  getItemManager().notifyDataSetChanged();
 }
 }
}

(三).BaseItem(部分get.set代码省略)

/**
 * Item的基类
 */
public abstract class BaseItem<D extends BaseItemData> {
 /**
 * 当前item的数据
 */
 protected D data;
 /**
 * item在每行中的spansize
 * 默认为0,如果为0则占满一行
 *
 * @return 所占值, 比如recyclerview的列数为6, item需要占一半宽度, 就设置3
 */
 private int spanSize;
 /**
 * 可以通过ItemManager ,操作adatper
 * @return
 */
 private ItemManager mItemManager;

 public int getLayoutId() {
 if (initLayoutId() <= 0) {
  throw new Resources.NotFoundException("请设置布局Id");
 }
 return initLayoutId();
 }

 /**
 * 子类需要实现该方法,并返回item的布局id
 *
 * @return 返回布局id.如果返回0,则会抛出异常
 */
 protected abstract int initLayoutId();

 /**
 * 抽象holder的绑定
 */
 public abstract void onBindViewHolder(ViewHolder viewHolder);

 /**
 * 当前条目的点击回调
 * 如果不需要点击事件,则可以不复写该方法.
 */
 public void onClick() {

 }

(四).TreeItem

/**
 * 组合模式
 * TreeRecyclerAdapter的item
 */
public abstract class TreeItem<D extends BaseItemData> extends BaseItem<D> {
 private TreeItemGroup parentItem;

 public void setParentItem(TreeItemGroup parentItem) {
 this.parentItem = parentItem;
 }

 /**
 * 获取当前item的父级
 *
 * @return
 */
 @Nullable
 public TreeItemGroup getParentItem() {
 return parentItem;
 }
}

(五).TreeItemGroup

/**
 * Created by baozi on 2016/12/22.
 * 拥有子集
 * 子集可以是parent,也可以是child
 */

public abstract class TreeItemGroup<D extends BaseItemData> extends TreeItem<D>
 implements TreeParent {
 /**
 * 持有的子item
 */
 private List<? extends BaseItem> childs;
 /**
 * 是否展开
 */
 private boolean isExpand;
 /**
 * 能否展开
 */
 protected boolean isCanChangeExpand = true;

 /**
 * 展开
 */
 @Override
 public void onExpand() {

 }

 /**
 * 折叠
 */
 @Override
 public void onCollapse() {

 }

 /**
 * 获得自己的childs.
 * @return
 */
 @Nullable
 public List<? extends BaseItem> getChilds() {
 return childs;
 }
 /**
 * 获得所有childs,包括子item的childs
 * @return
 */
 @Nullable
 public List<? extends BaseItem> getAllChilds() {
 if (getChilds() == null) {
  return null;
 }
 ArrayList<BaseItem> baseItems = new ArrayList<>();
 for (int i = 0; i < childs.size(); i++) {
  //下级
  BaseItem baseItem = childs.get(i);
  baseItems.add(baseItem);
  //判断是否还有下下级,并且处于expand的状态
  if (baseItem instanceof TreeItemGroup && ((TreeItemGroup) baseItem).isExpand()) {
  //调用下级的getAllChilds遍历,相当于递归遍历
  List list = ((TreeItemGroup) baseItem).getAllChilds();
  if (list != null && list.size() > 0) {
   baseItems.addAll(list);
  }
  }
 }
 return baseItems;
 }

 public int getChildsCount() {
 return childs == null ? 0 : childs.size();
 }

 /**
 * 初始化子集
 *
 * @param data
 * @return
 */
 protected abstract List<? extends BaseItem> initChildsList(D data);

 /**
 * 是否消费child的click事件
 *
 * @param child 具体click的item
 * @return 返回true代表消费此次事件,child不会走onclick(),返回false说明不消费此次事件,child依然会走onclick()
 */
 public boolean onInterceptClick(TreeItem child) {
 return false;
 }

(六).TreeSelectItemGroup

/**
 * Created by baozi on 2016/12/22.
 * 可以选中子item的TreeItemGroup,点击的item会保存起来.可以通过 getSelectItems()获得选中item
 */
public abstract class TreeSelectItemGroup<D extends BaseItemData>
 extends TreeItemGroup<D> {
 /**
 * 选中的子item.只支持下一级,不支持下下级
 */
 private List<BaseItem> selectItems;

 public List<BaseItem> getSelectItems() {
 if (selectItems == null) {
  selectItems = new ArrayList<>();
 }
 return selectItems;
 }
 /**
 * 是否有选中item,
 * @return
 */
 public boolean isHaveCheck() {
 return !getSelectItems().isEmpty();
 }

 @Override
 public boolean onInterceptClick(TreeItem child) {
 //单选
 if (selectFlag() == SelectFlag.SINGLE_CHOICE) {
  //如果已经有选中的,则替换
  if (getSelectItems().size() != 0) {
  getSelectItems().set(0, child);
  } else {
  //没有选中的则添加
  getSelectItems().add(child);
  }
 } else {
  //判断是否已添加.
  int index = getSelectItems().indexOf(child);
  if (index == -1) {//不存在则添加
  getSelectItems().add(child);
  } else {//存在则删除
  getSelectItems().remove(index);
  }
 }
 return super.onInterceptClick(child);
 }

 /**
 * 必须指定选中样式
 * @return
 */
 public abstract SelectFlag selectFlag();

 /**
 * 决定TreeSelectItemGroup的选中样式
 */
 public enum SelectFlag {
 /**
  * 单选
  */
 SINGLE_CHOICE,
 /**
  * 多选
  */
 MULTIPLE_CHOICE
 }

具体的使用实例效果:

1.购物页面:

Demo中的代码:

//拿到数据
List<StoreBean> storeBean = initData();
//通过ItemFactory生成第一级Item,如果是通过后台控制,则不需要传Class
//List<ShopTitileItem> itemList = ItemFactory.createItemList(storeBean);
List<ShopTitileItem> itemList = ItemFactory.createItemList(storeBean, ShopTitileItem.class);
//创建TreeRecyclerAdapter
mAdapter = new TreeRecyclerAdapter<>();
//设置adapter的显示样式
mAdapter.setType(TreeRecyclerViewType.SHOW_ALL);
//将数据设置到Adapter中
mAdapter.setDatas(itemList);
//设置adapter
mRecyclerView.setAdapter(mAdapter);

/**
 * item的代码
 * Created by baozi on 2016/12/22.
 */
public class ShopTitileItem extends TreeSelectItemGroup<StoreBean> {

 @Override
 protected List<? extends BaseItem> initChildsList(StoreBean data) {
 return ItemFactory.createTreeItemList(data.getShopListBeen(), this);
 }

 @Override
 protected int initLayoutId() {
 return R.layout.item_shopcart_title;
 }

 @Override
 public void onBindViewHolder(ViewHolder holder) {
 holder.setChecked(R.id.cb_ischeck, isHaveCheck());
 }

 @Override
 public void onClick() {
 if (!isHaveCheck()) {
  getSelectItems().clear();
  getSelectItems().addAll(getChilds());
 } else {
  getSelectItems().clear();
 }
 int size = getChilds().size();
 for (int i = 0; i < size; i++) {
  ShopListBean data = (ShopListBean) getChilds().get(i).getData();
  data.setCheck(isHaveCheck());
 }
 getItemManager().notifyDataSetChanged();
 }

 @Override
 public SelectFlag selectFlag() {
 return SelectFlag.MULTIPLE_CHOICE;
 }

 @Override
 public boolean canExpandOrCollapse() {
 return false;
 }

2.多级列表

Demo中的代码:

 //拿到数据
 List<CityBean> cityBeen = initData();
//通过ItemFactory生成List<BaseItem>
List<OneTreeItemParent> itemList = ItemFactory.createItemList(cityBeen);
 TreeRecyclerAdapter treeRecyclerAdapter = new TreeRecyclerAdapter();
//设置数据
 treeRecyclerAdapter.setDatas(itemList);
 recyclerView.setAdapter(treeRecyclerAdapter);

/**
 *item的代码
 * Created by baozi on 2016/12/8.
 */
public class OneTreeItemParent extends TreeItemGroup<CityBean> {
 @Override
 public List<? extends TreeItem> initChildsList(CityBean data) {
 return ItemFactory.createTreeItemList(data.getCitys(), TwoTreeItemParent.class, this);
 }

 @Override
 public int initLayoutId() {
 return R.layout.itme_one;
 }

 @Override
 public void onBindViewHolder(ViewHolder holder) {
 holder.setText(R.id.tv_content, data.getProvinceName());
 }

 @Override
 public boolean canExpandOrCollapse() {
 return false;
 }
}

3.多种type的列表

总结:

1.我觉得像购物车那种页面挺复杂的,既然写了多级列表,何不扩展一个出来

2.RecyclerView的点击事件,看了很多封装,发现很多都是每次onBindViewHolder去重新设置一遍,感觉挺不好的.

3.我喜欢把数据集合让Adatper去持有,然后通过Adapter进行增删改查操作.直接在Activity里持有数据集合进行操作,我不是习惯(- -)

4.用的习惯没bug的才是好东西,如果你觉得实用或者能学到姿势,就点个赞把,哈哈.

5.大部分的逻辑都在Item中,由于拆分开了,会发现每个item的代码也不会很多

6.多级列表我已经用在某个项目里了(- -),还没发现什么问题(多级列表的简单使用- -)

下面附上Demo.详细代码

github传送门:TreeRecyclerView

本地下载:http://xiazai.jb51.net/201705/yuanma/TreeRecyclerView(jb51.net).rar

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Android嵌套RecyclerView左右滑动替代自定义view

    以前的左右滑动效果采用自定义scrollview或者linearlayout来实现,recyclerview可以很好的做这个功能,一般的需求就是要么一个独立的左右滑动效果,要么在一个列表里的中间部分一个左右滑动效果 而列表里面也容易,只是需要解决一点小问题,个人认为值得一提的就是高度问题,一般的人采用固定死的高度,可是在列表里面展示和机型的不同,固定死的话很难保证美观,动态的高度才能解决问题的所在 首先在一个列表控件布局上添加一个recyclerview控件 <android.support.v

  • Android中RecyclerView 滑动时图片加载的优化

    RecyclerView 滑动时的优化处理,在滑动时停止加载图片,在滑动停止时开始加载图片,这里用了Glide.pause 和Glide.resume.这里为了避免重复设置增加开销,设置了一个标志变量来做判断. mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, in

  • Android中RecyclerView实现分页滚动的方法详解

    一.需求分析 最近公司项目要实现一个需求要满足以下功能: 1)显示一个 list 列表, item 数量不固定. 2)实现翻页功能,一次翻一页. 3)实现翻至某一页功能. 下面介绍通过 RecyclerView 实现该需求的实现过程(效果图如下). 二.功能实现 2.1 OnTouchListener 记录当前开始滑动位置 要实现翻页滑动首先我们要确定是向前翻页还是向后翻页,这里通过记录开始翻页前当前的位置和滑动后的位置比较即可得知,下面选择手指触摸按下时滑动的位置为当前开始滑动位置: //当前

  • Android RecyclerView的卡顿问题的解决方法

    RecyclerView为什么会卡 RecyclerView作为v7包的新控件,自从推出就广受Android Developer们欢迎,实际上它已经取代了ListView和GridView两位老前辈的地位.然而不少亲们想必也已经发现了:没有优化过的Recycler性能很poor.上一篇博主使用的item也仅仅是一个图两串字而已,结果一滑动就卡的要命,不能忍! 那么why?回想在用ListView和GridView的adapter时,我们是用一种叫ViewHolder的自定义类(容器)来实现优化的

  • Android Recyclerview实现多选,单选,全选,反选,批量删除的功能

    效果图如下: Recyclerview 实现多选,单选,全选,反选,批量删除的步骤 1.在Recyclerview布局中添加上底部的全选和反选按钮,删除按钮,和计算数量等控件 2.这里选中的控件没有用checkbox来做,用的是imageview,选中和不选中其实是两张图片 3.默认是不显示选中的控件的,点击编辑的时候显示,点击取消的时候隐藏 4.通过adapter和activity数据之间的传递,然后进行具体的操作 具体代码如下: 在recyclerview的布局中写全选,反选,删除,计数等相

  • Android RecyclerView显示Item布局不一致解决办法

    RecyclerView显示Item布局不一致 在自定义RecyclerAdapter的时候,在重写onCreateViewHolder方法是使用了 @Override public H onCreateViewHolder(ViewGroup parent, int viewType) { View view=View.inflate(context,layoutId,null); return view; } 进行生成布局,结果发现生成的布局没有LayoutParams.以前自定义View的

  • android中RecyclerView悬浮吸顶效果

    MultiType-Adapter打造悬浮吸顶效果 注:当前版本只适合配合RecyclerView快速打造一款 展示UI 悬浮吸顶效果,如 通讯录效果,由于实现机制的原因,暂时不支持触摸事件. MultiType-Adapter介绍地址:MultiType-Adapter 是一款轻量级支持多数据类型的 RecyclerView 适配器; 使用简单,完全解耦; 悬浮吸顶效果 ```groovy // root build.gradle repositories { jcenter() maven

  • Android中RecyclerView实现多级折叠列表效果(二)

    前言 在本文开始之前请大家先看一下这篇文章:http://www.jb51.net/article/113510.htm 上面的这篇文章是之前写的,里面发现有很多不好用地方,也学到些新姿势,改动了许多地方.下面来看看详细的介绍: 要点: 1.可以通过后台控制Item的展示. 2.TreeRecyclerAdapter,可以展开,折叠.多级展示 3.adapter可以使用装饰者模式进行扩展.支持EmptyAdapter.可以添加headview和footview 4.item的样式可以编写文档,t

  • Android中RecyclerView实现多级折叠列表效果(TreeRecyclerView)

    前言 首先不得不吐槽一下产品,尼玛为啥要搞这样的功能....搞个两级的不就好了嘛...自带控件,多好.三级,四级,听说还有六级的....这样丧心病狂的设计,后台也不好给数据吧. 先看看效果: 两级的效果: 三级的效果: 全部展开的效果(我只写了五级) 说说为什么写这货吧: 公司产品提出三级这个需求后,我就在网上找啊找. 找的第一个,发现实现其实是ExpandListview嵌套. 找的第二个,ExpandRecyclview,然后就用呗,发现三级展开很卡,看源码, 发现是RecyclerView

  • Android中RecyclerView拖拽、侧删功能的实现代码

    废话不多说,下面展示一下效果. 这是GridView主文件实现. public class GridViewActivity extends AppCompatActivity { RecyclerView mRecyclerView; List<String> mStringList; RecyclerAdapter mRecyAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { s

  • Android中RecyclerView实现Item添加和删除的代码示例

    本文介绍了Android中RecyclerView实现Item添加和删除的代码示例,分享给大家,具体如下: 先上效果图: RecyclerView简介: RecyclerView用以下两种方式简化了数据的展示和处理: 1. 使用LayoutManager来确定每一个item的排列方式. 2. 为增加和删除项目提供默认的动画效果,也可以自定义. RecyclerView项目结构如下: Adapter:使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器

  • Android中利用viewflipper动画切换屏幕效果

    整个项目的 package com.example.viewflipper; import android.R.integer; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector.OnDoubleTapListener; import android.view.Menu; import android.view.Me

  • Android 中RecyclerView多种item布局的写法(头布局+脚布局)

    RecyclerView多个item布局的写法(头布局+脚布局) 上图 github 下载源码 Initial commit第一次提交的代码,为本文内容 以下的为主要代码,看注释即可,比较简单 MainActivity 含上拉加载更多 package com.anew.recyclerviewall; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivi

  • Android中RecyclerView的item宽高问题详解

    前言 本文主要给大家介绍了关于Android中RecyclerView的item宽高问题的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 在创建viewholder传入的View时,如果不指定其viewgroup,就会出现宽高只包裹显示内容的问题. View view = LayoutInflater.from(context).inflate(R.layout.test_test,null); 上面的做法就会出问题 改成这样就可以正常显示设置的宽高 View vie

  • Android中recyclerView底部添加透明渐变效果

    前言 最近实现一个recyclerView透明渐变的效果,遇到了一些坑,尝试了一些方法,这里记录一下. 效果图 图片在上面显示2列,文字在下面显示1列:底部要有个透明渐变的效果,直到完全看不到. gridLayoutManager动态设置列数 大概是分两类,一类以图片为item 一行2个,一类以文字为item 一行一个. 这个第一反应是用viewType去区分图片类型,但是由于起初不知道gridLayout可以动态列数.就在上面两列,下面一列上为难起来了. 如果统一用一列吧,那就把两个image

  • Android中使用RecylerView实现聊天框效果

    从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传统的ListView,更加强大和灵活.在上篇文章给大家介绍了Android RecylerView入门教程,大家可以点击查看详情. 效果图如下:(其中,聊天框背景图用9-patch图,可以内容自适应调节.利用AndroidStudio自带的功能制作就行了,图片->右键->create 9-patch file. 其中要注意的是: 1.将9-patch图保存到drawable目录下才管用

  • Android中使用itemdecoration实现时间线效果

    代码如下: // 时间线装饰器 public class TimeLineDecoration extends RecyclerView.ItemDecoration { private Paint mPaint; public TimeLineDecoration() { mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.BLUE); mPaint.setStrokeWidth(5);

随机推荐