//一:先定義一個recyclerview的adapter,holder,以及接口 public interface OnItemClickListener<T> { void onItemClick(ViewGroup var1, View var2, T var3, int var4); boolean onItemLongClick(ViewGroup var1, View var2, T var3, int var4); }
public abstract class UniversalAdapter<T> extends Adapter<ViewHolder> { protected Context mContext; protected int mLayoutId; protected List<T> mDatas; protected LayoutInflater mInflater; protected ViewGroup mRv; private OnItemClickListener mOnItemClickListener; public UniversalAdapter setOnItemClickListener(OnItemClickListener onItemClickListener) { this.mOnItemClickListener = onItemClickListener; return this; } public OnItemClickListener getmOnItemClickListener() { return this.mOnItemClickListener; } public UniversalAdapter(Context context, List<T> datas, int layoutId) { this.mContext = context; this.mInflater = LayoutInflater.from(context); this.mLayoutId = layoutId; this.mDatas = datas; } public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewHolder viewHolder = ViewHolder.get(this.mContext, (View)null, parent, this.mLayoutId); if(null == this.mRv) { this.mRv = parent; } return viewHolder; } protected int getPosition(android.support.v7.widget.RecyclerView.ViewHolder viewHolder) { return viewHolder.getAdapterPosition(); } protected boolean isEnabled(int viewType) { return true; } /** @deprecated */ @Deprecated protected void setListener(final ViewGroup parent, final ViewHolder viewHolder, int viewType) { if(this.isEnabled(viewType)) { viewHolder.itemView.setOnClickListener(new OnClickListener() { public void onClick(View v) { if(UniversalAdapter.this.mOnItemClickListener != null) { int position = UniversalAdapter.this.getPosition(viewHolder); UniversalAdapter.this.mOnItemClickListener.onItemClick(parent, v, UniversalAdapter.this.mDatas.get(position), position); } } }); viewHolder.itemView.setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View v) { if(UniversalAdapter.this.mOnItemClickListener != null) { int position = UniversalAdapter.this.getPosition(viewHolder); return UniversalAdapter.this.mOnItemClickListener.onItemLongClick(parent, v, UniversalAdapter.this.mDatas.get(position), position); } else { return false; } } }); } } public void onBindViewHolder(ViewHolder holder, int position) { this.setListener(position, holder); this.convert(holder, this.mDatas.get(position)); } protected void setListener(final int position, final ViewHolder viewHolder) { if(this.isEnabled(this.getItemViewType(position))) { viewHolder.itemView.setOnClickListener(new OnClickListener() { public void onClick(View v) { if(UniversalAdapter.this.mOnItemClickListener != null) { UniversalAdapter.this.mOnItemClickListener.onItemClick(UniversalAdapter.this.mRv, v, UniversalAdapter.this.mDatas.get(position), position); } } }); viewHolder.itemView.setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View v) { if(UniversalAdapter.this.mOnItemClickListener != null) { int position = UniversalAdapter.this.getPosition(viewHolder); return UniversalAdapter.this.mOnItemClickListener.onItemLongClick(UniversalAdapter.this.mRv, v, UniversalAdapter.this.mDatas.get(position), position); } else { return false; } } }); } } // 將 var2的數據 顯示在ViewHolder 的對應 View 中 public abstract void convert(ViewHolder var1, T var2); public int getItemCount() { return this.mDatas != null?this.mDatas.size():0; } public void setDatas(List<T> list) { if(this.mDatas != null) { if(null != list) { ArrayList temp = new ArrayList(); temp.addAll(list); this.mDatas.clear(); this.mDatas.addAll(temp); } else { this.mDatas.clear(); } } else { this.mDatas = list; } this.notifyDataSetChanged(); } public void remove(int i) { if(null != this.mDatas && this.mDatas.size() > i && i > -1) { this.mDatas.remove(i); this.notifyDataSetChanged(); } } public void addDatas(List<T> list) { if(null != list) { ArrayList temp = new ArrayList(); temp.addAll(list); if(this.mDatas != null) { this.mDatas.addAll(temp); } else { this.mDatas = temp; } this.notifyDataSetChanged(); } } public List<T> getDatas() { return this.mDatas; } public T getItem(int position) { return position > -1 && null != this.mDatas && this.mDatas.size() > position?this.mDatas.get(position):null; } }
public class ViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViews = new SparseArray(); private int mLayoutId; public ViewHolder(View itemView) { super(itemView); } public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId) { if (convertView == null) { View holder2 = LayoutInflater.from(context).inflate(layoutId, parent, false); ViewHolder holder1 = new ViewHolder(holder2); holder1.mLayoutId = layoutId; return holder1; } else { ViewHolder holder = (ViewHolder) convertView.getTag(); return holder; } } public int getLayoutId() { return this.mLayoutId; } public <T extends View> T getView(int viewId) { View view = (View) this.mViews.get(viewId); if (view == null) { view = this.itemView.findViewById(viewId); this.mViews.put(viewId, view); } return (T) view; } public ViewHolder setText(int viewId, CharSequence text) { TextView tv = (TextView) this.getView(viewId); tv.setText(text); return this; } public ViewHolder setSelected(int viewId, boolean selected) { View v = this.getView(viewId); v.setSelected(selected); return this; } public ViewHolder setImageResource(int viewId, int resId) { ImageView view = (ImageView) this.getView(viewId); view.setImageResource(resId); return this; } public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) { ImageView view = (ImageView) this.getView(viewId); view.setImageBitmap(bitmap); return this; } public ViewHolder setImageDrawable(int viewId, Drawable drawable) { ImageView view = (ImageView) this.getView(viewId); view.setImageDrawable(drawable); return this; } public ViewHolder setBackgroundColor(int viewId, int color) { View view = this.getView(viewId); view.setBackgroundColor(color); return this; } public ViewHolder setBackgroundRes(int viewId, int backgroundRes) { View view = this.getView(viewId); view.setBackgroundResource(backgroundRes); return this; } public ViewHolder setTextColor(int viewId, int textColor) { TextView view = (TextView) this.getView(viewId); view.setTextColor(textColor); return this; } public ViewHolder setTextColorRes(int viewId, int textColorRes) { TextView view = (TextView) this.getView(viewId); view.setTextColor(this.itemView.getContext().getResources().getColor(textColorRes)); return this; } @SuppressLint({"NewApi"}) public ViewHolder setAlpha(int viewId, float value) { if (VERSION.SDK_INT >= 11) { this.getView(viewId).setAlpha(value); } else { AlphaAnimation alpha = new AlphaAnimation(value, value); alpha.setDuration(0L); alpha.setFillAfter(true); this.getView(viewId).startAnimation(alpha); } return this; } public ViewHolder setVisible(int viewId, boolean visible) { View view = this.getView(viewId); view.setVisibility(visible ? View.VISIBLE : View.GONE); return this; } public ViewHolder linkify(int viewId) { TextView view = (TextView) this.getView(viewId); Linkify.addLinks(view, Linkify.ALL); return this; } public ViewHolder setTypeface(Typeface typeface, int... viewIds) { int[] var3 = viewIds; int var4 = viewIds.length; for (int var5 = 0; var5 < var4; ++var5) { int viewId = var3[var5]; TextView view = (TextView) this.getView(viewId); view.setTypeface(typeface); view.setPaintFlags(view.getPaintFlags() | 128); } return this; } public ViewHolder setProgress(int viewId, int progress) { ProgressBar view = (ProgressBar) this.getView(viewId); view.setProgress(progress); return this; } public ViewHolder setProgress(int viewId, int progress, int max) { ProgressBar view = (ProgressBar) this.getView(viewId); view.setMax(max); view.setProgress(progress); return this; } public ViewHolder setMax(int viewId, int max) { ProgressBar view = (ProgressBar) this.getView(viewId); view.setMax(max); return this; } public ViewHolder setRating(int viewId, float rating) { RatingBar view = (RatingBar) this.getView(viewId); view.setRating(rating); return this; } public ViewHolder setRating(int viewId, float rating, int max) { RatingBar view = (RatingBar) this.getView(viewId); view.setMax(max); view.setRating(rating); return this; } public ViewHolder setTag(int viewId, Object tag) { View view = this.getView(viewId); view.setTag(tag); return this; } public ViewHolder setTag(int viewId, int key, Object tag) { View view = this.getView(viewId); view.setTag(key, tag); return this; } public ViewHolder setChecked(int viewId, boolean checked) { Checkable view = (Checkable) this.getView(viewId); view.setChecked(checked); return this; } public ViewHolder setOnClickListener(int viewId, OnClickListener listener) { View view = this.getView(viewId); view.setOnClickListener(listener); return this; } public ViewHolder setOnTouchListener(int viewId, OnTouchListener listener) { View view = this.getView(viewId); view.setOnTouchListener(listener); return this; } public ViewHolder setOnLongClickListener(int viewId, OnLongClickListener listener) { View view = this.getView(viewId); view.setOnLongClickListener(listener); return this; } public void setItemVisible(boolean visible) { if (null != this.itemView) { if (visible) { if (null != this.itemView.getLayoutParams()) { this.itemView.getLayoutParams().width = -1; this.itemView.getLayoutParams().height = -2; } else { this.itemView.setLayoutParams(new LayoutParams(-1, -2)); } this.itemView.setVisibility(View.VISIBLE); } else { if (null != this.itemView.getLayoutParams()) { this.itemView.getLayoutParams().width = -1; this.itemView.getLayoutParams().height = 1; } else { this.itemView.setLayoutParams(new LayoutParams(-1, 1)); } this.itemView.setVisibility(View.GONE); } } } public void setHItemVisible(boolean visible) { if (null != this.itemView) { if (visible) { if (null != this.itemView.getLayoutParams()) { this.itemView.getLayoutParams().width = -2; this.itemView.getLayoutParams().height = -2; } else { this.itemView.setLayoutParams(new LayoutParams(-1, -2)); } this.itemView.setVisibility(View.VISIBLE); } else { if (null != this.itemView.getLayoutParams()) { this.itemView.getLayoutParams().width = -1; this.itemView.getLayoutParams().height = 1; } else { this.itemView.setLayoutParams(new LayoutParams(-1, 1)); } this.itemView.setVisibility(View.GONE); } } } }
//二: 常量類
public class CardConfig { //屏幕上最多同時顯示幾個Item public static int MAX_SHOW_COUNT; //每一級Scale相差0.05f,translationY相差7dp左右 public static float SCALE_GAP; public static int TRANS_Y_GAP; public static void initConfig(Context context) { MAX_SHOW_COUNT = 4; SCALE_GAP = 0.05f; TRANS_Y_GAP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, context.getResources().getDisplayMetrics()); } }
//三:數據bean
package com.enjoy.leo_swipecardview; import java.util.ArrayList; import java.util.List; public class SwipeCardBean { private int postition; private String url; private String name; public SwipeCardBean(int postition, String url, String name) { this.postition = postition; this.url = url; this.name = name; } public int getPostition() { return postition; } public SwipeCardBean setPostition(int postition) { this.postition = postition; return this; } public String getUrl() { return url; } public SwipeCardBean setUrl(String url) { this.url = url; return this; } public String getName() { return name; } public SwipeCardBean setName(String name) { this.name = name; return this; } public static List<SwipeCardBean> initDatas() { List<SwipeCardBean> datas = new ArrayList<>(); int i = 1; datas.add(new SwipeCardBean(i++, "http://img5q.duitang.com/uploads/item/201505/04/20150504155117_8i4Rk.thumb.700_0.jpeg", "美女1")); datas.add(new SwipeCardBean(i++, "http://cdnq.duitang.com/uploads/item/201505/04/20150504155014_irFvu.thumb.700_0.jpeg", "美女2")); datas.add(new SwipeCardBean(i++, "http://img5q.duitang.com/uploads/item/201309/17/20130917032356_hdGjF.thumb.700_0.jpeg", "美女3")); datas.add(new SwipeCardBean(i++, "http://img5q.duitang.com/uploads/item/201505/04/20150504155137_JWcRK.thumb.700_0.jpeg", "美女4")); datas.add(new SwipeCardBean(i++, "http://img5q.duitang.com/uploads/item/201505/04/20150504155036_zNrPT.thumb.700_0.jpeg", "美女5")); datas.add(new SwipeCardBean(i++, "http://img5q.duitang.com/uploads/item/201504/26/201504262026_weMcT.thumb.700_0.jpeg", "美女6")); datas.add(new SwipeCardBean(i++, "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1560164210849&di=c6ea3fdd3ec938600ddde9022f46033c&imgtype=0&src=http%3A%2F%2Fbbs-fd.zol-img.com.cn%2Ft_s800x5000%2Fg4%2FM09%2F00%2F07%2FCg-4WlJA9zCIPZ8PAAQWAhRW0ssAAMA8wD2hYAABBYa996.jpg", "美女7")); datas.add(new SwipeCardBean(i++, "http://imgq.duitang.com/uploads/item/201504/21/20150421H2323_uwdEs.jpeg","美女8")); return datas; } }
//四: 實現ItemTouchHelper
public class SwipeCardCallback extends ItemTouchHelper.SimpleCallback { private RecyclerView mRv; private UniversalAdapter<SwipeCardBean> adapter; private List<SwipeCardBean> mDatas; public SwipeCardCallback(RecyclerView mRv, UniversalAdapter<SwipeCardBean> adapter, List<SwipeCardBean> mDatas) { //方向 super(0, 15);//1111 this.mRv = mRv; this.adapter = adapter; this.mDatas = mDatas; } //drag @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) { return false; } // item 滑出去後回調 @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) { SwipeCardBean remove = mDatas.remove(viewHolder.getLayoutPosition());//第八個 mDatas.add(0, remove);//放到第一個 adapter.notifyDataSetChanged(); } // onDraw @Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); double maxDistance = recyclerView.getWidth() * 0.5f; double distance = Math.sqrt(dX * dX + dY * dY); double fraction = distance / maxDistance; if (fraction > 1) { fraction = 1; } // 顯示的個數 4個 int itemCount = recyclerView.getChildCount(); for (int i = 0; i < itemCount; i++) { View view = recyclerView.getChildAt(i); int level = itemCount - i - 1; if (level > 0) { if (level < CardConfig.MAX_SHOW_COUNT - 1) { view.setTranslationY((float) (CardConfig.TRANS_Y_GAP * level - fraction * CardConfig.TRANS_Y_GAP)); view.setScaleX((float) (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP)); view.setScaleY((float) (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP)); } } } } @Override public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) { return 1000; } @Override public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { return 0.2f; } }
五:自定義LayoutManager
public class SwipeCardLayoutManager extends RecyclerView.LayoutManager { @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { // super.onLayoutChildren(recycler, state); // 回收 複用 detachAndScrapAttachedViews(recycler); // 8個 int itemCount = getItemCount(); int bottomPosition; // 0,1,2,3,4,5,6,7 if (itemCount < CardConfig.MAX_SHOW_COUNT) { bottomPosition = 0; } else { bottomPosition = itemCount - CardConfig.MAX_SHOW_COUNT; } for (int i = bottomPosition; i < itemCount; i++) { //複用 View view = recycler.getViewForPosition(i); addView(view); measureChildWithMargins(view, 0, 0); // 求padding的總大小 int widthSpace = getWidth() - getDecoratedMeasuredWidth(view); int heightSpace = getHeight() - getDecoratedMeasuredHeight(view); // 佈局 layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2, widthSpace / 2 + getDecoratedMeasuredWidth(view), heightSpace / 2 + getDecoratedMeasuredHeight(view)); int level = itemCount - i - 1; if(level > 0) { if(level < CardConfig.MAX_SHOW_COUNT - 1) { view.setTranslationY(CardConfig.TRANS_Y_GAP * level); view.setScaleX(1 - CardConfig.SCALE_GAP * level); view.setScaleY(1 - CardConfig.SCALE_GAP * level); } else { view.setTranslationY(CardConfig.TRANS_Y_GAP * (level-1)); view.setScaleX(1 - CardConfig.SCALE_GAP * (level-1)); view.setScaleY(1 - CardConfig.SCALE_GAP * (level-1)); } } } } }
//六 使用
public class MainActivity extends Activity { private RecyclerView rv; private UniversalAdapter<SwipeCardBean> adapter; private List<SwipeCardBean> mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swipe_card); rv = findViewById(R.id.rv); rv.setLayoutManager(new SwipeCardLayoutManager()); mDatas = SwipeCardBean.initDatas(); adapter = new UniversalAdapter<SwipeCardBean>(MainActivity.this, mDatas, R.layout.item_swipe_card) { @Override public void convert(ViewHolder ViewHolder, SwipeCardBean swipeCardBean) { ViewHolder.setText(R.id.tvName, swipeCardBean.getName()); ViewHolder.setText(R.id.tvPrecent, swipeCardBean.getPostition() + "/" + mDatas.size()); Glide.with(MainActivity.this) .load(swipeCardBean.getUrl()) .into((ImageView) ViewHolder.getView(R.id.iv)); } }; rv.setAdapter(adapter); CardConfig.initConfig(this); Callback callback = new SwipeCardCallback(rv, adapter, mDatas); ItemTouchHelper helper = new ItemTouchHelper(callback); helper.attachToRecyclerView(rv); } }