a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統(tǒng) > Android > 正文

RecyclerView實現(xiàn)探探卡片滑動效果

2019-10-21 21:27:02
字體:
供稿:網(wǎng)友

這里是一個通過自定義view和自定義RecyclerView的:layoutManager,再結(jié)合ItemTouchHelper實現(xiàn)的一個仿探探的卡片滑動的效果:

RecyclerView,探探,卡片滑動

效果圖已經(jīng)奉上,接下來是代碼:

首先是每張圖片的布局:item

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://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/互聯(lián)網(wǎng)"   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" />

一個常量參數(shù)類:CardConfig

/** * 常量參數(shù) */ public final class CardConfig { /**  * 顯示可見的卡片數(shù)量  */ 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的回調(diào)類: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; }   /**  * 設(shè)置滑動類型標(biāo)記  *  * @param recyclerView  * @param viewHolder  * @return  *   返回一個整數(shù)類型的標(biāo)識,用于判斷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的回調(diào)  *  * @param recyclerView  * @param viewHolder  * @param target  * @return  *   如果Item切換了位置,返回true;反之,返回false  */  @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {  return false; }  /**  *  * 劃出時會執(zhí)行  * @param viewHolder  * @param direction:左側(cè)劃出為:4,右側(cè)劃出為: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);  }  // 當(dāng)沒有數(shù)據(jù)時回調(diào) mListener  if (adapter.getItemCount() == 0) {   if (mListener != null) {    mListener.onSwipedClear();   }  } } /**  * Item是否支持滑動  *  * @return  *   true 支持滑動操作  *   false 不支持滑動操作  */  @Override public boolean isItemViewSwipeEnabled() {  return false; }  /**  * 拖動時會執(zhí)行的方法  * @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();   // 當(dāng)數(shù)據(jù)源個數(shù)大于最大顯示數(shù)時   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 {    // 當(dāng)數(shù)據(jù)源個數(shù)小于或等于最大顯示數(shù)時    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();  // 當(dāng)數(shù)據(jù)源個數(shù)大于最大顯示數(shù)時  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 {   // 當(dāng)數(shù)據(jù)源個數(shù)小于或等于最大顯示數(shù)時   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;  } }; }

狀態(tài)回調(diào)接口:OnSwipeListener

/** * @author 狀態(tài)回調(diào)接口 */ public interface OnSwipeListener<T> {  /**  * 卡片還在滑動時回調(diào)  *  * @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);  /**  * 卡片完全滑出時回調(diào)  *  * @param viewHolder 該滑出卡片的viewHolder  * @param t   該滑出卡片的數(shù)據(jù)  * @param direction 卡片滑出的方向,CardConfig.SWIPED_LEFT 為左邊滑出;CardConfig.SWIPED_RIGHT 為右邊滑出  */ void onSwiped(RecyclerView.ViewHolder viewHolder, T t, int direction);  /**  * 所有的卡片全部滑出時回調(diào)  */ 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);  //關(guān)閉硬件加速,同時其他地方依然享受硬件加速  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();  //該方法不支持硬件加速,如果開啟會導(dǎo)致效果出不來,所以之前設(shè)置關(guān)閉硬件加速  //Clip(剪切)的時機:通常理解的clip(剪切),是對已經(jīng)存在的圖形進行clip的。  // 但是,在android上是對canvas(畫布)上進行clip的,要在畫圖之前對canvas進行clip,  // 如果畫圖之后再對canvas進行clip不會影響到已經(jīng)畫好的圖形。一定要記住clip是針對canvas而非圖形  //開始根據(jù)path裁剪  canvas.clipPath(mPath);  super.onDraw(canvas);  canvas.restore(); }  int a,b; //執(zhí)行在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>

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 麻豆freexxxx性91精品 | 韩国精品主播一区二区在线观看 | 欧美高清免费 | 国产精品多久久久久久情趣酒店 | 中文字幕欧美日韩 | 亚洲黄色成人网 | 狠狠色综合网站久久久久久久 | 97电影在线观看 | 国产午夜精品一区二区三区 | 玖玖精品| av成人一区二区 | 日韩欧美综合 | 日韩精品免费一区二区在线观看 | 欧美日韩国产一区二区三区 | 在线播放亚洲 | 成人在线免费视频 | 国产区日韩区欧美区 | 97精品国产 | 国产一区二区三区久久久 | 日韩精品免费在线观看 | 欧美激情性国产欧美无遮挡 | 国产精品成人一区二区三区夜夜夜 | 乱操视频 | 国产精品一区免费观看 | 成人欧美一区二区三区在线播放 | 精品三级在线观看 | 精品一区二区久久久久久久网站 | 国产精品1区2区在线观看 | 国产在线一级片 | 国产一区二区精品 | 精品日韩一区 | 毛片毛片毛片毛片毛片毛片 | 五月激情六月婷婷 | 99久久99久久精品国产片果冻 | 免费 视频 1级 | 国产精品成人一区二区三区夜夜夜 | 久久人妖| 国产精品视频久久久 | 日本久久精品视频 | 国产痴汉av久久精品 | 九九久久精品 |