澳门威利斯人_威利斯人娱乐「手机版」

来自 澳门威利斯人 2020-02-27 07:13 的文章
当前位置: 澳门威利斯人 > 澳门威利斯人 > 正文

GridView并且实现瀑布流,让我欢喜让我忧的

Adapter的常规使用办法

实在很简单,只供给后续RecyclerView.艾达pter<VH extends ViewHolder>传入范型类型为ViewHolder的子类就可以,代码演示如下:MainActivity.java

public class MainActivity extends AppCompatActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { ... List<String> datas = new ArrayList<>(); for (int i = 0; i < 20;   i) { datas.add("item:"   ; } layoutManager = new LinearLayoutManager; recyclerView.setLayoutManager(layoutManager); MyAdapter myAdapter = new MyAdapter; myAdapter.setItemClickListener(new MyAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..."   position); } }); recyclerView.setAdapter(myAdapter); } private static class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{ private List<String> dataList; private ItemClickListener itemClickListener; public MyAdapter(List<String> dataList){ this.dataList = dataList; } public interface ItemClickListener { void onItemClicked(View view,int position); } //设置点击回调接口 public void setItemClickListener(ItemClickListener itemClickListener) { this.itemClickListener = itemClickListener; } //生成ViewHolder @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext.inflate(R.layout.item_view_main1, parent, false); return new ViewHolder; } private String getItem(int position){ return dataList.get; } //更新列表Item视图(根据需要绑定click事件) @Override public void onBindViewHolder(ViewHolder holder, final int position) { String str = getItem;// holder.icon.setImageDrawable; holder.name.setText; holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick { if(itemClickListener != null) itemClickListener.onItemClicked(v,position); } }); } @Override public int getItemCount() { return dataList.size(); } //ViewHolder保存每个item视图 public class ViewHolder extends RecyclerView.ViewHolder{ private ImageView icon; private TextView name; private View root; public ViewHolder(View itemView) { super; icon = (ImageView)itemView.findViewById(R.id.icon); name = itemView.findViewById(R.id.id_text); root = itemView.findViewById(R.id.root); } } }}

通过以上代码演示,大家得以得出结论:构造八个比较完好的Adapter最少需求做到以下三件事情

  1. onCreateViewHolder经过视图Id加载差异Item视图并生成ViewHolder用来保存每一个列表Item视图
  2. onBindViewHolder履新列表Item视图(填充model数据)
  3. 新建ViewHolder类来存款和储蓄Item视图及其子视图

一旦急需贯彻点击事件,须要在onBindViewHolder中正巧绑定点击事件,譬喻在以上代码中绑定了点击列表视图中的Item根视图的点击事件如下:

holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick { if(itemClickListener != null) itemClickListener.onItemClicked(v,position); }});

在急需得以实现具体的点击事件时调用如下代码:

myAdapter.setItemClickListener(new MyAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..."   position); }});
  1. 如果急需实以后同一个Item视图中式茶食击分裂view要促成不相同成效比方以上代码中拍卖了点击Item跟视图的点击事件,假设必要点击根视图中的icon子视图什么兑现?是否继续写setOnXXXListener,麻烦也不太现实
  2. 若果要兑现列表中多视图显示如何得以完成?符合规律如果急需扶助多视图大家是在onCreateViewHolder措施中依照区别的ViewType来加载区别的Item视图代码演示如下:
//重写getItemViewType函数,更具需要返回不同的viewType@Overridepublic int getItemViewType(int position) { String model = getItem(); if{ return 1; }else if{ return 2; } return super.getItemViewType;}//生成ViewHolder@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { int itemViewId = -1; if(viewType == 1){ itemViewId = R.layout.item_view_main1; }else if(viewType == 2){ itemViewId = R.layout.item_view_main2; } View itemView = LayoutInflater.from(parent.getContext.inflate(itemViewId, parent, false); return new ViewHolder;}

如上方案纯属针对某种列表来兑现的,假使换了二个列表视图我们就要求重现创设adapter并各自在onCreateViewHolder,onBindViewHolder方法中达成分化逻辑并再一次创立xxxViewHolder世袭ViewHolder来保存分歧的Item视图

相对来讲一下,眨眼之间间以为 ListView 弱爆了。。。

   List<Integer> mHeights=new ArrayList<>();
    for (int i = 0; i < 30; i  ) {
        mHeights.add((int) ((100 Math.random()) 10*i));
    }

缓和方案

依靠上述难题,给出如下方案LGViewHolder.java用来陈设通用的ViewHolder

public class LGViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViews; private View mConvertView;//缓存itemView内部的子View public LGViewHolder(View itemView) { super; mConvertView = itemView; mViews = new SparseArray<>(); } /** * 加载layoutId视图并用LGViewHolder保存 * @param parent * @param layoutId * @return */ protected static LGViewHolder getViewHolder(ViewGroup parent, int layoutId) { View itemView = LayoutInflater.from(parent.getContext.inflate(layoutId, parent, false); return new LGViewHolder; } /** * 根据ItemView的id获取子视图View * @param viewId * @return */ public View getView(int viewId) { View view = mViews.get; if (view == null) { view = mConvertView.findViewById; mViews.put(viewId, view); } return view; }}

LGRecycleViewAdapter.java

public abstract class LGRecycleViewAdapter<T> extends RecyclerView.Adapter<LGViewHolder> { private final String TAG = "LGRecycleViewAdapter"; //存储监听回调 private SparseArray<ItemClickListener> onClickListeners; private List<T> dataList; public interface ItemClickListener { void onItemClicked(View view,int position); } public LGRecycleViewAdapter(List<T> dataList) { this.dataList = dataList; onClickListeners = new SparseArray<>(); } /** * 存储viewId对应的回调监听实例listener * @param viewId * @param listener */ public void setOnItemClickListener(int viewId,ItemClickListener listener) { ItemClickListener listener_ = onClickListeners.get; if(listener_ == null){ onClickListeners.put(viewId,listener); } } /** * 获取列表控件的视图id * @param viewType * @return */ public abstract int getLayoutId(int viewType); //更新itemView视图 public abstract void convert(LGViewHolder holder, T t, int position); public T getItem(final int position){ if(dataList == null) return null; return dataList.get; } @Override public LGViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { int layoutId = getLayoutId; LGViewHolder viewHolder = LGViewHolder.getViewHolder(parent, layoutId); return viewHolder; } @Override public void onBindViewHolder(LGViewHolder holder, final int position) { T itemModel = dataList.get; convert(holder, itemModel, position);//更新itemView视图 //设置点击监听 for (int i = 0; i < onClickListeners.size{ int id = onClickListeners.keyAt; View view = holder.getView; if(view == null) continue; final ItemClickListener listener = onClickListeners.get; view.setOnClickListener(new View.OnClickListener() { @Override public void onClick { if(listener != null){ listener.onItemClicked(v,position); } } }); } } @Override public int getItemCount() { if (dataList == null) return 0; return dataList.size(); } public void destroyAdapter(){ if(onClickListeners != null) onClickListeners.clear(); onClickListeners = null; if(dataList != null) dataList.clear(); dataList = null; }}

动用方式如下:单视图格局:定义adapter

private static class MainAdapter extends LGRecycleViewAdapter<String> { ... @Override public int getLayoutId(int viewType) { return R.layout.item_view_main1; } @Override public void convert(LGViewHolder holder, String s, final int position) { TextView textView =  holder.getView(R.id.id_text); textView.setText; }}

在急需时选取:

mainAdapter = new MainAdapter;mainAdapter.setOnItemClickListener(R.id.root, new LGRecycleViewAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..."   position); }});mainAdapter.setOnItemClickListener(R.id.icon, new LGRecycleViewAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"icon clicked..."   position); }});recyclerView.setAdapter(mainAdapter);

能够看出大家轻易的兑现了同一Item视图差别子视图的点击监听,何况在MainAdapter子类中只需经过getLayoutId告诉父类Item视图对应的视图id,并在convert方法中只更新视图就能够假使急需辅助多视图格局则只需在子类中复发getViewType就能够,代码如下:MainAdapter.java

@Overridepublic int getLayoutId(int viewType) { if(viewType == 1) return R.layout.item_view_main1; return R.layout.item_view_main2;}//支持不同viewType视图@Overridepublic int getItemViewType(int position) { String model = getItem;//实际开发中可以通过model的属性来决定返回viewType类型 if(position % 2 == 0) return 1; return 2;}

说了那般多优点,说说短处,既然 RecyclerView 给大家提供了这么多扩大,能够高度定制,然则左臂难度同样扩大了绵绵四个阶段。还会有条款点击事件,大致病狂丧心,竟然接口都没提供。

那正是说什么样采纳RecycleView:

写在最终

为了轻便起见,本篇文章设计的adapter符合未有header和footer视图的RecycleView,至于这上头的功用筹划在github上立异完整的代码及案例能够到自身的github下载demo开源github地址如下:LGRecycleViewAdapter招待咱们访谈并star,假设有别的难点得以在七嘴八舌中加以提问,感激~~

好了,咱们要开首写代码了。

效果图:

实质上RecycleView已经出来非常长日子了,对RecycleView的用法兰西网球公开赛上也许有成千上万课程了。本篇小说不讲明RecycleView的用法,不疏解LayoutManager的用法也不批注ItemDecoration的用法,大家只关切Adapter的用法甚至哪些封装成贰个通用的Adapter

RecyclerView 是伴随着 android5.x 出来的控件,第4回提出应该是在14年的 谷歌(Google卡塔尔(قطر‎ I/O 大会(推测,懒得查,反正小编不 care 它是什么样时候出来的),到今后17年 Google I/O 大会甘休正好两年,相信我们都早就经把 RecyclerView 使用到花色在那之中了。

图片 1

  • 何以说 RecyclerView 让自家爱好让小编忧?
    垂怜因为用了 RecyclerView 之后,认为就再也不想去写 ListView 了;忧则是因为固然用了几年 RecyclerView,但直到以后认为 RecyclerView 照旧玩不溜,同感玩不溜的同室请握个抓。

  • 干什么说 RecyclerView 中度解耦
    作者们来探视 RecyclerView 的多少个大家熟知的章程:

    mRecyclerView.setLayoutManager(layout);
    //设置条约构造法规
    mRecyclerView.setItemAnimator();
    //设置条款动漫
    mRecyclerView.addItemDecoration();
    //自定义条款装饰
    mItemTouchHelper.attachToRecyclerView(mRecyclerView);
    //定制条目款项触摸
    近日我们来回想一下,对应的这多少个法规,大家的ListView 是怎么贯彻的,

  • layoutmanger:ListView 并不扶助那么些功用

  • ItemAnimation:在 艾达pter的 getView(卡塔尔方法里面给成立出来的 View 加动漫

  • ItemDecoration:在 Adapter 的 getView()方法里面自行管理

  • ItemTouchHelp: 在 Adapyer 的 getView()方法里面自行给 View 设置 Touch 事件管理。

在onCreateViewHolder中装置控件中度

四、ItemAnimator

一孔之见,条约动漫。本来不想写的,RecyclerView 有暗中同意的兑现动漫,况且列表中根本用不到炫酷的条目动漫,无语被自身早起规划的时候,参预了 RecyclerView 的知识点里面,在这里地质大学致讲一下吗。
接收办法如下:

 public void setItemAnimator(ItemAnimator animator) {
    if (mItemAnimator != null) {
        mItemAnimator.endAnimations();
        mItemAnimator.setListener(null);
    }
    mItemAnimator = animator;
    if (mItemAnimator != null) {
        mItemAnimator.setListener(mItemAnimatorListener);
    }
}

从这么些办法里面,我们得以 get 到多个基本点消息:

  • 自定义条目款项动漫必得一而再再而三ItemAnimator。
  • RecyclerView 有暗许的兑现动漫DefaultAnimation,而且在概念变量的时候就赋值给mItemAnimator。

好了,那么接下去咱们就透过学习DefaultAnimation的落到实处来源定义 ItemAnimation。

DefaultAnimation 世袭自SimpleItemAnimator,通过阅读 SimpleItemAnimator 的表明音信,大家知晓它是RecyclerView.ItemAnimator的直白子类,并且增添了ItemHolderInfo(一个精简的数据构造,保存了 Item 的界限消息,用于总结项目动漫)来支援条目款项动漫的施行。由此大家只要要自定义 ItemAnimation 最佳持续自SimpleItemAnimator。

好了,到那边,大家到底明白了如何自定义 ItemAnimation,接下去我们只必要顺藤摘瓜就足以了。

要追溯,得先找到藤,大家去会见ItemAnimation的架空方法,自定义 ItemAnimation 一共有多个相关的格局需求我们去手动完成

 //Item移除回调
 @Override
 public boolean animateRemove(RecyclerView.ViewHolder holder) {
     return false;
 }

 //Item添加回调
 @Override
 public boolean animateAdd(RecyclerView.ViewHolder holder) {
     return false;
 }

 //用于控制添加,移动更新时,其它Item的动画执行
 @Override
 public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
     return false;
 }

 //Item更新回调
 @Override
 public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
     return false;
 }

 //真正控制执行动画的地方
 @Override
 public void runPendingAnimations() {

 }
 //停止某个Item的动画
 @Override
 public void endAnimation(RecyclerView.ViewHolder item) {

 }

 //停止所有动画
 @Override
 public void endAnimations() {

 }

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

没个艺术的意义小编都在上头写了讲授,相信看懂应该轻巧,接下去我们再依赖那根藤回到 DefaultItemAnimation。

  • animateAdd起始吧,方法相当粗略,就三行代码。一是明亮和删除 Item 里面有着的动漫相关代码,二是把条约初叶化为透明状态(可相比较暗中认可实施动漫),三是把条目款项增添到等待运维动漫列表里面。
  @Override
   public boolean animateAdd(final ViewHolder holder) {
     resetAnimation(holder);
     ViewCompat.setAlpha(holder.itemView, 0);
     mPendingAdditions.add(holder);
     return true;
   }
  • animateRemove,和animateAdd相近,就少了一整套初始化条目款项标代码。
  @Override
   public boolean animateRemove(final ViewHolder holder) {
     resetAnimation(holder);
     mPendingRemovals.add(holder);
     return true;
 }
  • 再看animateMove(卡塔尔(قطر‎方法,忘记那个办法效果的同窗请再回头看看。这几个点子里面有多少个参数,分别是要运动的规规矩矩,伊始xy 轴的职位。里面包车型客车操作也很简短,移动Item,然后保留 Item 的移动消息。
  @Override
     public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
         int toX, int toY) {
     final View view = holder.itemView;
     fromX  = ViewCompat.getTranslationX(holder.itemView);
     fromY  = ViewCompat.getTranslationY(holder.itemView);
     resetAnimation(holder);
     int deltaX = toX - fromX;
     int deltaY = toY - fromY;
     if (deltaX == 0 && deltaY == 0) {
         dispatchMoveFinished(holder);
         return false;
     }
     if (deltaX != 0) {
         ViewCompat.setTranslationX(view, -deltaX);
     }
     if (deltaY != 0) {
         ViewCompat.setTranslationY(view, -deltaY);
     }
     mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
     return true;
 }
  • 接下去看animateChange(卡塔尔(قطر‎,大家见到,若是是同叁个 ViewHolder 则一直调用 animateMove(卡塔尔(قطر‎方法,不然在里边多记录了三个 阿尔法 的值
  @Override
   public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
         int fromX, int fromY, int toX, int toY) {
     if (oldHolder == newHolder) {
         // Don't know how to run change animations when the same view holder is re-used.
         // run a move animation to handle position changes.
         return animateMove(oldHolder, fromX, fromY, toX, toY);
     }
     final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
     final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
     final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
     resetAnimation(oldHolder);
     int deltaX = (int) (toX - fromX - prevTranslationX);
     int deltaY = (int) (toY - fromY - prevTranslationY);
     // recover prev translation state after ending animation
     ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
     ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
     ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
     if (newHolder != null) {
         // carry over translation values
         resetAnimation(newHolder);
         ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
         ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
         ViewCompat.setAlpha(newHolder.itemView, 0);
     }
     mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
     return true;
 }
  • endAnimation(卡塔尔国方法和endAnimations(卡塔尔国方法同样,正是循环把待管理的卡通新闻全体删掉,然后调用 cancelAll()结束正在运作的卡通片。

  • isRunning,通过推断动漫队列,看是否有动画待推行动漫恐怕正在实践的卡通片

  • runPendingAnimations(),真正实行动漫的地点,判别待试行的动漫片队列之中是或不是有亟待实施的卡通,假如有,就相继奉行,若无就退出。

  • animateAddImpl(State of Qatar、animateChangeImpl(卡塔尔国、animateMoveImpl、animateRemoveImpl(State of Qatar那多少个艺术分别是二种档期的顺序动漫的切实可行落到实处。

好累啊,终于把它深入分析完了,接下去大家一举,入手撸二个。不过自己项目中好像一贯不现有的,然后写动漫这种供给创新意识的事务本身心累,而且重借使实际上付出中差不离也略略用赢得。不过有一对校友大概会对动漫片比较感兴趣,于是趁机的小编去 github 上找了三个RecyclerView 的 Item 动漫库,大家能够对着笔者的深入分析去探视人家的兑现,贴上传送门:https://github.com/wasabeef/recyclerview-animators

image.png

二、封装RecyclerView 的 Adapter

Adapter是 RecycleView 中最要害的一个类,纵然尚未特意复杂难掌握的代码,但是 RecycleView 的刷新条款、多条约、点击事件都急需在内处。并且每一种 RecycleView 的 Adapter 大概都亟待带读写,所以那是多个高频率、代码量稍多的三个类,因而大家在应用的历程中平常会对 Adapter 进行一下卷入。

  • 多少管理用泛型标准输入数据

我们在其实项目成本个中,会有成千上万地方都用到 RecycleView(太长了,上边笔者用 rv 简单称谓吧),何况数量的布局各有分裂,因而,在 BaseAdapter 里面,大家须要用二个泛型 T 去职业数据结构的项目,幸免误操作。

  • 暗中认可完结条款标增加和删除方法和getItemCount(State of Qatar;

其一比较容易,等下直接看代码

  • 配合 ButtonKnife,简化 ViewHolder 里面的 findViewbyid 操作

那一个也大致,抽取了贰个 BaseViewHolder,在布局方法里面绑定的。

  • 接近也没怎么好写的,笔者一向贴小编项目中封装的 BaseAdapter 的代码吧
public abstract class BaseAbstractAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
  protected final String TAG = getClass().getSimpleName();
  protected final Context mContext;
  protected final LayoutInflater mLayoutInflater;

  protected List<T> mDataList = new ArrayList<>();

  public BaseAbstractAdapter(Context context) {
      this.mContext = context;
      this.mLayoutInflater = LayoutInflater.from(mContext);
  }

  public Context getContext() {
      return mContext;
  }

  public List<T> getDataList() {
       return mDataList;
  }

   public T getItemData(int position) {
      return (position >= 0 && position < mDataList.size()) ? mDataList.get(position) : null;
  }

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

  /**
   * 移除某一条记录
   *
   * @param position 移除数据的position
   */
  public void removeItem(int position) {
      if (position >= 0 && position < mDataList.size()) {
          mDataList.remove(position);
          notifyItemRemoved(position);
      }
  }

  /**
  * 添加一条记录
   *
  * @param data     需要加入的数据结构
  * @param position 插入位置
  */
  public void addItem(T data, int position) {
      if (position >= 0 && position <= mDataList.size()) {
          mDataList.add(position, data);
          notifyItemInserted(position);
      }
  }

  /**
   * 添加一条记录
   *
   * @param data 需要加入的数据结构
   */
  public void addItem(T data) {
      addItem(data, mDataList.size());
  }

  /**
   * 移除所有记录
   */
  public void clearItems() {
      int size = mDataList.size();
      if (size > 0) {
          mDataList.clear();
          notifyItemRangeRemoved(0, size);
      }
  }

  /**
   * 批量添加记录
   *
   * @param data     需要加入的数据结构
   * @param position 插入位置
   */
  public void addItems(List<T> data, int position) {
      if (position >= 0 && position <= mDataList.size() && data != null && data.size() > 0) {
          mDataList.addAll(position, data);
          notifyItemRangeChanged(position, data.size());
      }
  }

  /**
   * 批量添加记录
   *
   * @param data 需要加入的数据结构
   */
  public void addItems(List<T> data) {
      addItems(data, mDataList.size());
  }

  @Override
  public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
      if (holder instanceof BaseViewHolder) {
          ((BaseViewHolder) holder).bindViewData(getItemData(position));
      }
  }

  }    
  //不是内部类哦
  public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {

  public BaseViewHolder(View itemView) {
      super(itemView);
      ButterKnife.bind(this, itemView);
  }

  public abstract void bindViewData(T data);
  }

好了,代码贴完了,应该未有何难懂的代码吧,这一套封装基本上能够满足98%以上的单Item 列表了,至于点击事件,实际不是颇有的列别都急需,依据实际需求本人定义接口回调就能够了。

到此地或然部分同学会问,那多**** Item ****的**** rv ****怎么做,在事实上开辟中,多**** Item ****的**** rv ****现象也不算少,极其是闲聊列表,动辄八九种**** Item****。别急,我们稳步来****~****

rv 的章程中有个抽象方法onCreateViewHolder(ViewGroup parent, int viewType),这么些办法是用来创立ViewHolder 的,ViewHolder 大家得以把它驾驭成RecycleView 二个 ItemView 的卷入类,也正是说二个 ViewHolder 正是多少个条款,假如我们需求多条约,那么直接在那重回差别的条目款项就能够了,方法参数里面恰好有个 viewType可以用来支配条目款项类型。

那就是说难点来了,那么些viewType值是从哪儿来的吧,想明白这几个,那就只好去看源码了,大家通过产看 RecyclerView.Adapter 的源码发掘,onCreateViewHolder方法是在createViewHolder里面调用

public final VH createViewHolder(ViewGroup parent, int viewType) {
        TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
        final VH holder = onCreateViewHolder(parent, viewType);
        holder.mItemViewType = viewType;
        TraceCompat.endSection();
        return holder;
    }

总的来看这里,大家只可以接二连三追createViewHolder的调用。然后经过全局搜索,在getViewForPosition方法里面找到了viewType这一个参数的根源,里面有一行代码 final int type = mAdapter.getItemViewType(offsetPosition);于是再持续追getItemViewType。

 public int getItemViewType(int position) {
        return 0;
    }

好了,追到这里作者也不再赘言了,本来大家都精通重写getItemViewType方法就能够了。
回去正题,怎么封装多 ItemAdapter。多 Item 用到的景色常常都是内需给 奥迪Q7V 增添贰个头照旧加上三个尾,由此,思虑到通用性,笔者就只做了三种类型条约标扩大,上边直接贴代码:

 public abstract class BaseAbstractMultipleItemAdapter<T> extends BaseAbstractAdapter<T> {
 private static final int ITEM_TYPE_HEADER = 1;
 private static final int ITEM_TYPE_BOTTOM = 2;
 private static final int ITEM_TYPE_CONTENT = 3;

 @IntDef({ITEM_TYPE_HEADER, ITEM_TYPE_BOTTOM})
 @interface ItemType {

 }

 protected int mHeaderCount;//头部View个数
 protected int mBottomCount;//底部View个数

 public BaseAbstractMultipleItemAdapter(Context context) {
     super(context);
 }

 public void setHeaderCount(int headerCount) {
     this.mHeaderCount = headerCount;
 }

 public void setBottomCount(int bottomCount) {
     this.mBottomCount = bottomCount;
 }

 public int getHeaderCount() {
     return mHeaderCount;
 }

 public int getBottomCount() {
     return mBottomCount;
 }

 public boolean isHeaderView(int position) {
     return mHeaderCount != 0 && position < mHeaderCount;
 }

 public boolean isBottomView(int position) {
     return mBottomCount != 0 && position >= (mHeaderCount   super.getItemCount());
 }

 @Override
 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     if (viewType == ITEM_TYPE_HEADER) {
         return onCreateHeaderView(parent);
     } else if (viewType == ITEM_TYPE_BOTTOM) {
         return onCreateBottomView(parent);
     } else {
         return onCreateContentView(parent, viewType);
     }
 }

 @Override
 public int getItemViewType(int position) {
     if (isHeaderView(position)) {//头部View
         return ITEM_TYPE_HEADER;
     } else if (isBottomView(position)) {//底部View
         return ITEM_TYPE_BOTTOM;
     } else {
         return getContentViewType(position);
     }
 }

 @Override
 public int getItemCount() {
     return mHeaderCount   super.getItemCount()   mBottomCount;
 }

 @Override
 public T getItemData(int position) {
     int index = position - mHeaderCount;
     if (index >= super.getItemCount()) {
         return null;
     }
     return super.getItemData(index);
 }

 /**
  * 移除某一条记录
  *
  * @param position 移除数据的position 如果有Header需要减去Header数量
  */
 public void removeItem(int position) {
     if (position < mDataList.size()) {
         mDataList.remove(position);
         notifyItemRemoved(mHeaderCount   position);
     }
 }

 /**
  * 添加一条记录
  *
  * @param data     需要加入的数据结构
  * @param position 插入数据的位置 如果有Header需要减去Header数量
  */
 public void addItem(T data, int position) {
     if (position <= mDataList.size()) {
         mDataList.add(position, data);
         notifyItemInserted(mHeaderCount   position);
     }
 }


 /**
  * 移除所有记录
  */
 public void clearItems() {
     int size = mDataList.size();
     if (size > 0) {
         mDataList.clear();
         notifyItemRangeRemoved(mHeaderCount, size);
     }
 }


 /**
  * 批量添加记录
  * @param data     需要加入的数据结构
  * @param position 插入数据的位置 如果有Header需要减去Header数量
  */
 public void addItems(List<T> data, int position) {
     if (position <= mDataList.size() && data != null && data.size() > 0) {
         mDataList.addAll(position, data);
         notifyItemRangeChanged(mHeaderCount   position, data.size());
     }
 }

 public int getContentViewType(int position) {
     return ITEM_TYPE_CONTENT;
 }

 public RecyclerView.ViewHolder onCreateHeaderView(ViewGroup parent) {//创建头部View
     return null;
 }

 public abstract RecyclerView.ViewHolder onCreateContentView(ViewGroup parent, int viewType);//创建中间内容View

 public abstract RecyclerView.ViewHolder onCreateBottomView(ViewGroup parent);//创建底部View

}

代码都有注释,应该没有怎么看不懂多看五遍不能够领会的经过mHeaderCount和mBottomCount分别调整头尾条款数,然后要求什么样条目款项就重写对应的 CreateViewHolder 方法就能够,借使 head 或许 bottom 须求绑定数据就在onBindViewHolder里面依据holder 和 position自行绑定。

  • 配置build.gradle

笔者们都精晓,RecyclerView 的产出,是为了代替 ListView、GridView 而产出的。记得有次面试的时候,面试官问我为何要利用 RecyclerView,你 RecyclerView 能达成的列表,作者 ListView 相像可以完结,小编及时是那般回应的:整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,这段话我随意在英特网复制的,轮廓大概。好了,扯远了。

图片 2

六、LayoutManger

LayoutManger:布局管理
LayoutManger是 RecyclerView 用来管理子 view 布局的叁个构件(另二个零件是 Recycler,担任回笼看电视图),它至关心注重要负责四个专门的工作:

1.布公安部视图
2.在滚动的进度中依照子视图在构造中所处的岗位,决定何时加多子视图和回笼看电视机图
3.滚动子视图

其间只有滚动子视图才需求对子视图回笼或抬高,而增多子视图则肯定伴随着所增多对象的结构管理,在滚动进度中,增多一遍子视图只会潜濡默化到被加上对象,原有子视图的相对地点不会转移。

LayoutManger 是 RecyclerView 的叁个虚幻内部类,平时大家选择它都以行使它的子类:

  • LinearLayoutManager
  • GridLayoutManager
  • StaggeredGridLayoutManager

那多个类的用法作者就只是多的废话了,相信大家都用过,平时景观下,那多少个LayoutManger 也能够满意大家99%的需要了。自定义LayoutManger 是一件相比有难度的工程,并且动用意况少之又少(反正小编是没遭受过这么的须要)。可是网络有无数炫丽的自定义 LayoutManger 效果,最优良的当属防探探的卡牌式布局,在英特网也看过非常多自定义 LayoutManger 的篇章,但现行反革命依然半瓶醋。

感兴趣的同室能够看看那些库,里面有 bolg 链接。当然,必要的时候再去看也行。传送门:https://github.com/mcxtzhang/ZLayoutManager

好了,RecyclerView 到此地就讲罢了,只怕有个别地点深度非常不足,然则基本能满足超越1/2的须求了,假若万分得以留言咨询,前者直接私信作者。

image.png

五、ItemTouchHelper

ItemTouchHelper 条目款项触摸帮手,看名称就能够想到其意义,这一个类正是用来援救大家处理 翼虎V 条款触摸事件的,如广大的滑动删除,长按拖拽。效果图如下:

图片 3

ItemTouchHelper.gif

图片 4

ItemTouchHelper2.gif

未曾吗非常的,作者平素贴代码吧:

 ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
     @Override
     public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
         int from = viewHolder.getAdapterPosition();
         int to = target.getAdapterPosition();
         if (from < to) {
             for (int i = from; i < to; i  )
                 Collections.swap(mNewTopsAdapter.getDataList(), i, i   1);
         } else {
             for (int i = from; i > to; i--)
                 Collections.swap(mNewTopsAdapter.getDataList(), i, i - 1);
         }
         mNewTopsAdapter.notifyItemMoved(from, to);
         return false;
     }

     @Override
     public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
         mNewTopsAdapter.removeItem(viewHolder.getAdapterPosition());

     }
 });
itemTouchHelper.attachToRecyclerView(mRecycleView);

福如东海起来很简短,new一个 ItemTouchHelper, 然后调用ItemTouchHelper的 attachToRecyclerView(State of Qatar 依据给 锐界V 就行了。关键点在 ItemTouchHelper 的布局方法里面必传的参数ItemTouchHelper.Callback(卡塔尔。由于此地须要比较简单,作者一直用了曾经做过一遍封装的SimpleCallback。

SimpleCallback:世袭自ItemTouchHelper.Callback,对父类实行了包装,只暴露出八个大致的法门供开荒者去落到实处。

布局方法:

  • SimpleCallback(int dragDirs, int swipeDirs)
  • dragDirs:条约标拖动方向,可配参数有ItemTouchHelper.UP、ItemTouchHelper.DOWN、ItemTouchHelper.LEFT、ItemTouchHelper.汉兰达IGHT,若是要同时安插几个趋势,用运算符号|连接
  • swipeDirs:条款滑动方向,参数类型同上

大家在 new SimpleCallback()的时候把拖拽的参数配置好,然后再落到实处如下多少个抽象方法

  • public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
  • public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)

里头 onMove方法会在 Item 拖动的时候不断调用,那时我们必要在条目款项拖动的时候调用 adapter 的notifyItemMoved()方法刷新条约地方,具体代码如下:

 int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
if (from < to) {
    for (int i = from; i < to; i  )
   Collections.swap(mNewTopsAdapter.getDataList(), i, i   1);
} else {
    for (int i = from; i > to; i--)
        Collections.swap(mNewTopsAdapter.getDataList(), i, i - 1);
}
mNewTopsAdapter.notifyItemMoved(from, to);
return true;
首先获取当前条目和目标条目position,这里需要注意getAdapterPosition()和getLayoutPosition(),前者是在adapter 调用界面刷新的时候就给 position 赋值了,而后者是在界面刷新结束之后才能获取到正确的赋值。我们都知道,RV 的界面刷新是异步的,大概会有一个16毫秒左右的延时,因此使用getLayoutPosition()获取 position 可能会出错哦。

onSwiped方准则是用来决定条款滑动删除之后的逻辑管理。当中direction参数是滑动的可行性。比方说滑动删除:我们直接在方法体里面调用 adapter 的 notifyItemRemoved()方法就能够。

好了,ItemTouchHelper 的基本用法就那个,基本也能满足开采进程中的当先1/2要求了,借使还也有越来越高的急需,那么继续跟自个儿去肛一波ItemTouchHelper.Callback的源码。

****ItemTouchHelper.Callback****
泛泛方法有四个:

  • public int getMovementFlags(RecyclerView, RecyclerView.ViewHolder)
  • public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
  • public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)

当中首个第多少个艺术,大家在SimpleCallback已经表明过一遍了,这里不在赘述。我们来说一下率先个方法

  • public abstract int getMovementFlags(RecyclerView recyclerView,ViewHolder viewHolder);

主意求证上,作者用自己三级斯洛伐克语水平加上翻译软件,大约能够读出这些主意是要回去贰个决定 item 移动方向的交集标记,混合标识怎么转移,能够动用方法makeMovementFlags(卡塔尔;好,那么达成getMovementFlags的方法体大致正是return getMovementFlags(dragFlags,swipeFlags卡塔尔国;
而 getMovementFlags 要求我们传三个参数,那多少个参数怎么传呢,大家一连去追getMovementFlags(卡塔尔;

 public static int makeMovementFlags(int dragFlags, int swipeFlags) {
        return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags) |
                makeFlag(ACTION_STATE_SWIPE, swipeFlags) | makeFlag(ACTION_STATE_DRAG,
                dragFlags);
    }

办法求证上,我们得以清楚这一个主意是用来创立移动 flag 的,说白了正是用来支配 Item 的移位/滑动方向,方法中多个参数分别是拖动 flag 和滑动 flag。看见此间,大家来回看一下SimpleCallback的布局方法,是否也要传那多少个参数,而SimpleCallback不需求落到实处getMovementFlags(卡塔尔国方法,是否因为已经帮我们落到实处了,通过查阅源码验证了我们的估量。

然后正是有的公共艺术,可重写定制的:

 //是否可以把拖动的ViewHolder拖动到目标ViewHolder之上
 @Override
 public boolean canDropOver(RecyclerView recyclerView,RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
return true;
 }

 //获取拖动
 @Override
 public RecyclerView.ViewHolder chooseDropTarget(RecyclerView.ViewHolder selected, List<RecyclerView.ViewHolder> dropTargets, int curX, int curY) {
return dropTargets.get(0);
 }

 //调用时与元素的用户交互已经结束,也就是它也完成了它的动画时候
 @Override
 public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
 }

 @Override
 public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
 }

 //设置手指离开后ViewHolder的动画时间
 @Override
 public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
 }

 @Override
 public int getBoundingBoxMargin() {
return super.getBoundingBoxMargin();
 }

 //返回值作为用户视为拖动的距离
 @Override
 public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
return super.getMoveThreshold(viewHolder);
 }

 //返回值滑动消失的距离,滑动小于这个值不消失,大于消失
 @Override
 public float getSwipeEscapeVelocity(float defaultValue) {
return super.getSwipeEscapeVelocity(defaultValue);
 }

 //返回值滑动消失的距离, 这里是相对于RecycleView的宽度,0.5f表示为RecycleView的宽度的一半,取值为0~1f之间
 @Override
 public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
return super.getSwipeThreshold(viewHolder);
 }

 //返回值作为滑动的流程程度,越小越难滑动,越大越好滑动
 @Override
 public float getSwipeVelocityThreshold(float defaultValue) {
return 1f;
 }

 //当用户拖动一个视图出界的ItemTouchHelper调用
 @Override
 public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize, int viewSizeOutOfBounds, int totalSize, long msSinceStartScroll) {
return super.interpolateOutOfBoundsScroll(recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll);
 }

 //返回值决定是否有滑动操作
 @Override
 public boolean isItemViewSwipeEnabled() {
return super.isItemViewSwipeEnabled();
 }

 //返回值决定是否有拖动操作
 @Override
 public boolean isLongPressDragEnabled() {
return super.isLongPressDragEnabled();
 }

 //自定义拖动与滑动交互
 @Override
 public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
 }

 //自定义拖动与滑动交互
 @Override
 public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
 }

 //当onMove return ture的时候调用
 @Override
 public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
 }

 //当拖动或者滑动的ViewHolder改变时调用
 @Override
 public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
 }

图片 5

一、RecyclerView 的主干选拔

先达成二个回顾的列表:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(new RecyclerView.Adapter() {
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            //创建一个 ViewHolder 并且返回
            return null;
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            //在这里给 ViewHolder 绑定数据
        }

        @Override
        public int getItemCount() {
         //控制RecyclerView的条目数
            return 0;
        }
    });

那般大家就接收RecyclerView实现了一个轻便的列表,由于代码比较轻易,我平素一笔带过了。这里相比相当的大家的 Listview,就多了一行代码recyclerView.setLayoutManager(new LinearLayoutManager(this));,至于那行代码具体有怎么样效能吗,大家后边再说。

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private List<String> mListData;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListData=new ArrayList<>();
        for (int i = 0; i <30; i  ) {
            mListData.add(i "");
        }

          /*List<Integer> mHeights=new ArrayList<>();
            for (int i = 0; i < 30; i  ) {

            mHeights.add((int) ((100 Math.random()) 10*i));
        }*/
        mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
        LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);

        mRecyclerView.addItemDecoration(new     
        DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));

        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        //设置item增加和删除的动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        final RecycleViewMyAdapter adapter=new RecycleViewMyAdapter(mListData,MainActivity.this);

        /**
         * 实现RecycleView的item的点击效果
         */
        adapter.setOnItenClickListener(new RecycleViewMyAdapter.OnItenClickListener() {

            //单点击
            @Override
            public void onItenClick(View view, int position) {
                Toast.makeText(MainActivity.this, "点击了第" position "条" "数据" mListData.get(position), Toast.LENGTH_SHORT).show();
            }

            //长按点击
            @Override
            public void onItenLonfClick(View view, final int position) {
                //Toast.makeText(MainActivity.this, "长按了第" position "条" "数据" mListData.get(position), Toast.LENGTH_SHORT).show();
                new AlertDialog.Builder(MainActivity.this).setTitle("确定要删除吗?").
                        setNegativeButton("取消",null).setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                        //Toast.makeText(MainActivity.this, "---" which, Toast.LENGTH_SHORT).show();
                        //Toast.makeText(MainActivity.this, "---------------------" position, Toast.LENGTH_SHORT).show();
                        adapter.removeData(position);

                    }
                }).show();

            }
        });
        mRecyclerView.setAdapter(adapter);
    }
}

本文由澳门威利斯人发布于澳门威利斯人,转载请注明出处:GridView并且实现瀑布流,让我欢喜让我忧的

关键词: 澳门威利斯人 Android... 多点 视图 回调