android开发分享RecyclerView实现探探卡片滑动效果

这里是一个通过自定义view和自定义recyclerview的:layoutmanager,再结合itemtouchhelper实现的一个仿探探的卡片滑动的效果: 效

这里是一个通过自定义view和自定义recyclerview的:layoutmanager,再结合itemtouchhelper实现的一个仿探探的卡片滑动的效果:

上述就是android开发分享RecyclerView实现探探卡片滑动效果的全部内容,如果对大家有所用处且需要了解更多关于Android学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

RecyclerView实现探探卡片滑动效果

效果图已经奉上,接下来是代码:

首先是每张图片的布局:item

  <linearlayout xmlns:android="https://schemas.android.com/apk/res/android"   xmlns:app="https://schemas.android.com/apk/res-auto"   android:layout_width="336dp"   android:layout_height="426dp"   android:background="@drawable/img_card_background"   android:gravity="center"   android:orientation="vertical">      <relativelayout    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="1">       <com.bwie.w.test1121.cardswipelayout.roundimageview     android:id="@+id/iv_avatar"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:scaletype="centercrop"     android:src="@drawable/img_avatar_01"     app:radius="7.5dp" />       <imageview     android:id="@+id/iv_dislike"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignparentright="true"     android:layout_marginright="15dp"     android:layout_margintop="15dp"     android:alpha="0"     android:src="@drawable/img_dislike" />       <imageview     android:id="@+id/iv_like"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_marginleft="15dp"     android:layout_margintop="15dp"     android:alpha="0"     android:src="@drawable/img_like" />      </relativelayout>      <relativelayout    android:layout_width="match_parent"    android:layout_height="100dp"    android:paddingleft="14dp"    android:paddingtop="15dp">       <textview     android:id="@+id/tv_name"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:gravity="center"     android:text="小姐姐"     android:textcolor="@android:color/black"     android:textsize="16sp" />       <textview     android:id="@+id/tv_age"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_below="@id/tv_name"     android:layout_margintop="5dp"     android:background="@drawable/shape_age"     android:gravity="center"     android:text="♀ 23"     android:textcolor="#ffffff"     android:textsize="14sp" />       <textview     android:id="@+id/tv_constellation"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_below="@id/tv_name"     android:layout_marginleft="4dp"     android:layout_margintop="5dp"     android:layout_torightof="@id/tv_age"     android:background="@drawable/shape_constellation"     android:gravity="center"     android:text="狮子座"     android:textcolor="#ffffff"     android:textsize="14sp" />       <textview     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_below="@id/tv_age"     android:layout_margintop="5dp"     android:gravity="center"     android:text="it/互联网"     android:textcolor="#cbcbcb" />      </relativelayout>        </linearlayout>

activity_main:

  <android.support.v7.widget.recyclerview    android:id="@+id/recyclerview"    android:layout_width="match_parent"    android:layout_height="match_parent" />

一个常量参数类:cardconfig

  /**   * 常量参数   */     public final class cardconfig {   /**    * 显示可见的卡片数量    */   public static final int default_show_item = 3;   /**    * 默认缩放的比例    */   public static final float default_scale = 0.1f;   /**    * 卡片y轴偏移量时按照14等分计算    */   public static final int default_translate_y = 14;   /**    * 卡片滑动时默认倾斜的角度    */   public static final float default_rotate_degree = 15f;   /**    * 卡片滑动时不偏左也不偏右    */   public static final int swiping_none = 1;   /**    * 卡片向左滑动时    */   public static final int swiping_left = 1 << 2;   /**    * 卡片向右滑动时    */   public static final int swiping_right = 1 << 3;   /**    * 卡片从左边滑出    */   public static final int swiped_left = 1;   /**    * 卡片从右边滑出    */   public static final int swiped_right = 1 << 2;  }

拖动item的回调类:carditemtouchhelpercallback

  public class carditemtouchhelpercallback<t> extends itemtouchhelper.callback {      private final recyclerview.adapter adapter;   private list<t> datalist;   private onswipelistener<t> mlistener;      public carditemtouchhelpercallback(@nonnull recyclerview.adapter adapter, @nonnull list<t> datalist) {    this.adapter = checkisnull(adapter);    this.datalist = checkisnull(datalist);   }      public carditemtouchhelpercallback(@nonnull recyclerview.adapter adapter, @nonnull list<t> datalist, onswipelistener<t> listener) {    this.adapter = checkisnull(adapter);    this.datalist = checkisnull(datalist);    this.mlistener = listener;   }      private <t> t checkisnull(t t) {    if (t == null) {     throw new nullpointerexception();    }    return t;   }      public void setonswipedlistener(onswipelistener<t> mlistener) {    this.mlistener = mlistener;   }         /**    * 设置滑动类型标记    *    * @param recyclerview    * @param viewholder    * @return    *   返回一个整数类型的标识,用于判断item那种移动行为是允许的    */   @override   public int getmovementflags(recyclerview recyclerview, recyclerview.viewholder viewholder) {    int dragflags = 0;    int swipeflags = 0;    recyclerview.layoutmanager layoutmanager = recyclerview.getlayoutmanager();    if (layoutmanager instanceof cardlayoutmanager) {     swipeflags = itemtouchhelper.left | itemtouchhelper.right;    }    return makemovementflags(dragflags, swipeflags);   }   /**    * 拖拽切换item的回调    *    * @param recyclerview    * @param viewholder    * @param target    * @return    *   如果item切换了位置,返回true;反之,返回false    */      @override   public boolean onmove(recyclerview recyclerview, recyclerview.viewholder viewholder, recyclerview.viewholder target) {    return false;   }      /**    *    * 划出时会执行    * @param viewholder    * @param direction:左侧划出为:4,右侧划出为:8    */   @override   public void onswiped(recyclerview.viewholder viewholder, int direction) {    log.d("mylog", "onswiped: " + direction);    // 移除 ontouchlistener,否则触摸滑动会乱了    viewholder.itemview.setontouchlistener(null);    int layoutposition = viewholder.getlayoutposition();    t remove = datalist.remove(layoutposition);    adapter.notifydatasetchanged();    if (mlistener != null) {     mlistener.onswiped(viewholder, remove, direction == itemtouchhelper.left ? cardconfig.swiped_left : cardconfig.swiped_right);    }    // 当没有数据时回调 mlistener    if (adapter.getitemcount() == 0) {     if (mlistener != null) {      mlistener.onswipedclear();     }    }   }   /**    * item是否支持滑动    *    * @return    *   true 支持滑动操作    *   false 不支持滑动操作    */      @override   public boolean isitemviewswipeenabled() {    return false;   }      /**    * 拖动时会执行的方法    * @param c    * @param recyclerview    * @param viewholder    * @param dx    * @param dy    * @param actionstate    * @param iscurrentlyactive    */   @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);    // log.d("mylog", "onchilddraw: 拖动");    view itemview = viewholder.itemview;    if (actionstate == itemtouchhelper.action_state_swipe) {     float ratio = dx / getthreshold(recyclerview, viewholder);     // ratio 最大为 1 或 -1     if (ratio > 1) {      ratio = 1;     } else if (ratio < -1) {      ratio = -1;     }     log.d("mylog", "onchilddraw: " + ratio);     itemview.setrotation(ratio * cardconfig.default_rotate_degree);     int childcount = recyclerview.getchildcount();     // 当数据源个数大于最大显示数时     if (childcount > cardconfig.default_show_item) {      for (int position = 1; position < childcount - 1; position++) {       int index = childcount - position - 1;       view view = recyclerview.getchildat(position);       view.setscalex(1 - index * cardconfig.default_scale + math.abs(ratio) * cardconfig.default_scale);       view.setscaley(1 - index * cardconfig.default_scale + math.abs(ratio) * cardconfig.default_scale);          /* view.setscalex(1 - index * cardconfig.default_scale );       view.setscaley(1 - index * cardconfig.default_scale);*/       view.settranslationy((index - math.abs(ratio)) * itemview.getmeasuredheight() / cardconfig.default_translate_y);      }     } else {      // 当数据源个数小于或等于最大显示数时      for (int position = 0; position < childcount - 1; position++) {       int index = childcount - position - 1;       view view = recyclerview.getchildat(position);       view.setscalex(1 - index * cardconfig.default_scale + math.abs(ratio) * cardconfig.default_scale);       view.setscaley(1 - index * cardconfig.default_scale + math.abs(ratio) * cardconfig.default_scale);       view.settranslationy((index - math.abs(ratio)) * itemview.getmeasuredheight() / cardconfig.default_translate_y);      }     }     if (mlistener != null) {      if (ratio != 0) {       // log.d("mylog", "onchilddraw: 不为零");       mlistener.onswiping(viewholder, ratio, ratio < 0 ? cardconfig.swiping_left : cardconfig.swiping_right);      } else {       // log.d("mylog", "onchilddraw: 为零");       mlistener.onswiping(viewholder, ratio, cardconfig.swiping_none);      }     }    }   }      @override   public void clearview(recyclerview recyclerview, recyclerview.viewholder viewholder) {    super.clearview(recyclerview, viewholder);    viewholder.itemview.setrotation(0f);   }      private float getthreshold(recyclerview recyclerview, recyclerview.viewholder viewholder) {    return recyclerview.getwidth() * getswipethreshold(viewholder);   }     }

自定义布局管理器:cardlayoutmanager:

  /**   * 自定义布局管理器   */     public class cardlayoutmanager extends recyclerview.layoutmanager {      private recyclerview mrecyclerview;   private itemtouchhelper mitemtouchhelper;      public cardlayoutmanager(@nonnull recyclerview recyclerview, @nonnull itemtouchhelper itemtouchhelper) {    this.mrecyclerview = checkisnull(recyclerview);    this.mitemtouchhelper = checkisnull(itemtouchhelper);   }      private <t> t checkisnull(t t) {    if (t == null) {     throw new nullpointerexception();    }    return t;   }      @override   public recyclerview.layoutparams generatedefaultlayoutparams() {    return new recyclerview.layoutparams(viewgroup.layoutparams.wrap_content, viewgroup.layoutparams.wrap_content);   }      @override   public void onlayoutchildren(final recyclerview.recycler recycler, recyclerview.state state) {    detachandscrapattachedviews(recycler);    int itemcount = getitemcount();    // 当数据源个数大于最大显示数时    if (itemcount > cardconfig.default_show_item) {     for (int position = cardconfig.default_show_item; position >= 0; position--) {      final view view = recycler.getviewforposition(position);      addview(view);      measurechildwithmargins(view, 0, 0);      int widthspace = getwidth() - getdecoratedmeasuredwidth(view);      int heightspace = getheight() - getdecoratedmeasuredheight(view);      // recyclerview 布局      layoutdecoratedwithmargins(view, widthspace / 2, heightspace / 2,        widthspace / 2 + getdecoratedmeasuredwidth(view),        heightspace / 2 + getdecoratedmeasuredheight(view));         if (position == cardconfig.default_show_item) {       view.setscalex(1 - (position - 1) * cardconfig.default_scale);       view.setscaley(1 - (position - 1) * cardconfig.default_scale);       view.settranslationy((position - 1) * view.getmeasuredheight() / cardconfig.default_translate_y);      } else if (position > 0) {       view.setscalex(1 - position * cardconfig.default_scale);       view.setscaley(1 - position * cardconfig.default_scale);       view.settranslationy(position * view.getmeasuredheight() / cardconfig.default_translate_y);      } else {       view.setontouchlistener(montouchlistener);      }     }    } else {     // 当数据源个数小于或等于最大显示数时     for (int position = itemcount - 1; position >= 0; position--) {      final view view = recycler.getviewforposition(position);      addview(view);      measurechildwithmargins(view, 0, 0);      int widthspace = getwidth() - getdecoratedmeasuredwidth(view);      int heightspace = getheight() - getdecoratedmeasuredheight(view);      // recyclerview 布局      layoutdecoratedwithmargins(view, widthspace / 2, heightspace / 2,        widthspace / 2 + getdecoratedmeasuredwidth(view),        heightspace / 2 + getdecoratedmeasuredheight(view));         if (position > 0) {       view.setscalex(1 - position * cardconfig.default_scale);       view.setscaley(1 - position * cardconfig.default_scale);       view.settranslationy(position * view.getmeasuredheight() / cardconfig.default_translate_y);      } else {       view.setontouchlistener(montouchlistener);      }     }    }   }      private view.ontouchlistener montouchlistener = new view.ontouchlistener() {       @override    public boolean ontouch(view v, motionevent event) {     recyclerview.viewholder childviewholder = mrecyclerview.getchildviewholder(v);     if (motioneventcompat.getactionmasked(event) == motionevent.action_down) {      mitemtouchhelper.startswipe(childviewholder);     }     return false;    }   };     }

状态回调接口:onswipelistener

  /**   * @author 状态回调接口   */     public interface onswipelistener<t> {      /**    * 卡片还在滑动时回调    *    * @param viewholder 该滑动卡片的viewholder    * @param ratio  滑动进度的比例    * @param direction 卡片滑动的方向,cardconfig.swiping_left 为向左滑,cardconfig.swiping_right 为向右滑,    *     cardconfig.swiping_none 为不偏左也不偏右    */   void onswiping(recyclerview.viewholder viewholder, float ratio, int direction);      /**    * 卡片完全滑出时回调    *    * @param viewholder 该滑出卡片的viewholder    * @param t   该滑出卡片的数据    * @param direction 卡片滑出的方向,cardconfig.swiped_left 为左边滑出;cardconfig.swiped_right 为右边滑出    */   void onswiped(recyclerview.viewholder viewholder, t t, int direction);      /**    * 所有的卡片全部滑出时回调    */   void onswipedclear();     }

自定义条目图片样式:roundimageview:

  /**   * 自定义图片样式,顶部圆角显示   */     public class roundimageview extends imageview {      private path mpath;   private rectf mrectf;   /*圆角的半径,依次为左上角xy半径,右上角,右下角,左下角*/   private float[] rids = new float[8];   private paintflagsdrawfilter paintflagsdrawfilter;      public roundimageview(context context) {    this(context, null);   }      public roundimageview(context context, attributeset attrs) {    this(context, attrs, 0);   }      public roundimageview(context context, attributeset attrs, int defstyleattr) {    super(context, attrs, defstyleattr);    typedarray array = context.obtainstyledattributes(attrs, r.styleable.roundimageview);    float mradius = array.getdimension(r.styleable.roundimageview_radius, 10);    rids[0] = mradius;    rids[1] = mradius;    rids[2] = mradius;    rids[3] = mradius;    rids[4] = 0f;    rids[5] = 0f;    rids[6] = 0f;    rids[7] = 0f;    array.recycle();    //用于绘制的类    mpath = new path();    //抗锯齿    paintflagsdrawfilter = new paintflagsdrawfilter(0, paint.anti_alias_flag | paint.filter_bitmap_flag);    //关闭硬件加速,同时其他地方依然享受硬件加速    setlayertype(view.layer_type_hardware, null);   }      @override   protected void ondraw(canvas canvas) {    // log.d("mylog", "ondraw: ");    //重置path    mpath.reset();    //p1:大小,p2:圆角,p3:cw:顺时针绘制path,ccw:逆时针    mpath.addroundrect(mrectf, rids, path.direction.cw);    //添加抗锯齿    canvas.setdrawfilter(paintflagsdrawfilter);    canvas.save();    //该方法不支持硬件加速,如果开启会导致效果出不来,所以之前设置关闭硬件加速    //clip(剪切)的时机:通常理解的clip(剪切),是对已经存在的图形进行clip的。    // 但是,在android上是对canvas(画布)上进行clip的,要在画图之前对canvas进行clip,    // 如果画图之后再对canvas进行clip不会影响到已经画好的图形。一定要记住clip是针对canvas而非图形    //开始根据path裁剪    canvas.clippath(mpath);    super.ondraw(canvas);    canvas.restore();   }      int a,b;   //执行在ondraw()之前   @override   protected void onsizechanged(int w, int h, int oldw, int oldh) {    super.onsizechanged(w, h, oldw, oldh);    // log.d("mylog", "onsizechanged: ");    a = w;    b = h;    mrectf = new rectf(0, 0, w, h);    log.d("mylog", "onsizechanged: "+w+"-----"+h);   }     }

mainactivity:

  public class mainactivity extends appcompatactivity {   private list<integer> list = new arraylist<>();   @override   protected void oncreate(bundle savedinstancestate) {    super.oncreate(savedinstancestate);    setcontentview(r.layout.activity_main);       initview();    initdata();   }   private void initview() {    final recyclerview recyclerview = findviewbyid(r.id.recyclerview);    recyclerview.setitemanimator(new defaultitemanimator());    recyclerview.setadapter(new myadapter());    carditemtouchhelpercallback cardcallback = new carditemtouchhelpercallback(recyclerview.getadapter(), list);    cardcallback.setonswipedlistener(new onswipelistener<integer>() {        @override     public void onswiping(recyclerview.viewholder viewholder, float ratio, int direction) {      myadapter.myviewholder myholder = (myadapter.myviewholder) viewholder;      viewholder.itemview.setalpha(1 - math.abs(ratio) * 0.2f);      if (direction == cardconfig.swiping_left) {       myholder.dislikeimageview.setalpha(math.abs(ratio));      } else if (direction == cardconfig.swiping_right) {       myholder.likeimageview.setalpha(math.abs(ratio));      } else {       myholder.dislikeimageview.setalpha(0f);       myholder.likeimageview.setalpha(0f);      }     }        @override     public void onswiped(recyclerview.viewholder viewholder, integer o, int direction) {      myadapter.myviewholder myholder = (myadapter.myviewholder) viewholder;      viewholder.itemview.setalpha(1f);      myholder.dislikeimageview.setalpha(0f);      myholder.likeimageview.setalpha(0f);      toast.maketext(mainactivity.this, direction == cardconfig.swiped_left ? "swiped left" : "swiped right", toast.length_short).show();     }        @override     public void onswipedclear() {      toast.maketext(mainactivity.this, "data clear", toast.length_short).show();      recyclerview.postdelayed(new runnable() {       @override       public void run() {        initdata();        recyclerview.getadapter().notifydatasetchanged();       }      }, 3000l);     }       });    final itemtouchhelper touchhelper = new itemtouchhelper(cardcallback);    final cardlayoutmanager cardlayoutmanager = new cardlayoutmanager(recyclerview, touchhelper);    recyclerview.setlayoutmanager(cardlayoutmanager);    touchhelper.attachtorecyclerview(recyclerview);   }         private void initdata() {    list.add(r.drawable.img_avatar_01);    list.add(r.drawable.img_avatar_02);    list.add(r.drawable.img_avatar_03);    list.add(r.drawable.img_avatar_04);    list.add(r.drawable.img_avatar_05);    list.add(r.drawable.img_avatar_06);    list.add(r.drawable.img_avatar_07);   }      private class myadapter extends recyclerview.adapter {    @override    public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) {     view view = layoutinflater.from(parent.getcontext()).inflate(r.layout.item, parent, false);     return new myviewholder(view);    }       @override    public void onbindviewholder(recyclerview.viewholder holder, int position) {     imageview avatarimageview = ((myviewholder) holder).avatarimageview;     avatarimageview.setimageresource(list.get(position));    }       @override    public int getitemcount() {     return list.size();    }       class myviewholder extends recyclerview.viewholder {        imageview avatarimageview;     imageview likeimageview;     imageview dislikeimageview;        myviewholder(view itemview) {      super(itemview);      avatarimageview = (imageview) itemview.findviewbyid(r.id.iv_avatar);      likeimageview = (imageview) itemview.findviewbyid(r.id.iv_like);      dislikeimageview = (imageview) itemview.findviewbyid(r.id.iv_dislike);     }       }   }  }

attrs:

  <resources>   <declare-styleable name="roundimageview">    <attr name="radius" format="reference|dimension" />   </declare-styleable>  </resources>

以上就是android开发分享RecyclerView实现探探卡片滑动效果的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/937709.html

(0)
上一篇 2021年11月12日
下一篇 2021年11月12日

精彩推荐