热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android开发中RecyclerView模仿探探左右滑动布局功能

本文给大家分享android开发中RecyclerView模仿探探左右滑动布局功能,非常不错,具有参考借鉴价值,需要的朋友参考下

我在此基础上优化了部分代码, 添加了滑动回调, 可自定义性更强. 并且添加了点击按钮左右滑动的功能.

据说无图都不敢发文章了.

看图:

这里写图片描述

1:这种功能, 首先需要自己管理布局

继承 RecyclerView.LayoutManager , 显示自己管理布局, 比如最多显示4个view, 并且都是居中显示.

底部的View还需要进行缩放,平移操作.

public class OverLayCardLayoutManager extends RecyclerView.LayoutManager {
 private static final String TAG = "swipecard";
 public static int MAX_SHOW_COUNT = 4;
 public static float SCALE_GAP = 0.05f;
 public static int TRANS_Y_GAP;
 public OverLayCardLayoutManager(Context context) {
  //平移时, 需要用到的参考值
  TRANS_Y_GAP = (int) (20 * context.getResources().getDisplayMetrics().density);
 }
 @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) {
  //在这个方法中进行View的布局操作.此方法会被调用多次.
  detachAndScrapAttachedViews(recycler);
  int itemCount = getItemCount();
  if (itemCount <1) {
   return;
  }
  //top-3View的position
  int bottomPosition;
  //边界处理
  if (itemCount  0 /*&& level 

2:布局好了之后, 就需要监听鼠标事件了

谷歌官方提供了一个ItemTouchHelper工具类, 对滑动进行了惨无人道的优越封装, 傻x都能用…

使用方法: new ItemTouchHelper(callback).attachToRecyclerView(recyclerView);就这么简单,

接下来的操作, 都在回调callback里面进行.

public class RenRenCallback extends ItemTouchHelper.SimpleCallback {
 private static final String TAG = "RenRen";
 private static final int MAX_ROTATION = 15;
 OnSwipeListener mSwipeListener;
 boolean isSwipeAnim = false;
 public RenRenCallback() {
  //第一个参数决定可以拖动排序的方向, 这里由于不需要拖动排序,所以传0
  //第二个参数决定可以支持滑动的方向,这里设置了上下左右都可以滑动.
  super(0, ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
 }
 public void setSwipeListener(OnSwipeListener swipeListener) {
  mSwipeListener = swipeListener;
 }
 //水平方向是否可以被回收掉的阈值
 public float getThreshold(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
  //2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片,这里参照源码写死0.5f
  return recyclerView.getWidth() * /*getSwipeThreshold(viewHolder)*/ 0.5f;
 }
 @Override
 public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
  //由于不支持滑动排序, 所以不需要处理此方法
  return false;
 }
 @Override
 public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
  //当view需要滑动的时候,会回调此方法
  //但是这个方法只是告诉你View需要滑动, 并不是对View和Adapter进行额外的操作,
  //所以, 如果你需要实现滑动删除, 那么需要在此方法中remove item等.
  //我们这里需要对滑动过后的View,进行恢复操作. 
  viewHolder.itemView.setRotation(0);//恢复最后一次的旋转状态
  if (mSwipeListener != null) {
   mSwipeListener.onSwipeTo(viewHolder, 0);
  }
  notifyListener(viewHolder.getAdapterPosition(), direction);
 }
 private void notifyListener(int position, int direction) {
  Log.w(TAG, "onSwiped: " + position + " " + direction);
  if (mSwipeListener != null) {
   mSwipeListener.onSwiped(position, direction);
  }
 }
 @Override
 public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
  //滑动的比例达到多少之后, 视为滑动
  return 0.3f;
 }
 @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);
  //当你在滑动的过程中, 此方法一直会被回调, 就跟onTouch事件一样...
  //先根据滑动的dx dy 算出现在动画的比例系数fraction
  float swipeValue = (float) Math.sqrt(dX * dX + dY * dY);
  final float threshold = getThreshold(recyclerView, viewHolder);
  float fraction = swipeValue / threshold;
  //边界修正 最大为1
  if (fraction > 1) {
   fraction = 1;
  } else if (fraction <-1) {
   fraction = -1;
  }
  //对每个ChildView进行缩放 位移
  int childCount = recyclerView.getChildCount();
  for (int i = 0; i  0) {
    child.setScaleX(1 - SCALE_GAP * level + fraction * SCALE_GAP);
    if (level  50) {
     child.setRotation(fraction * MAX_ROTATION);
    } else {
     child.setRotation(0);
    }
    if (mSwipeListener != null) {
     RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
     final int adapterPosition = params.getViewAdapterPosition();
     mSwipeListener.onSwipeTo(recyclerView.findViewHolderForAdapterPosition(adapterPosition), dX);
    }
   }
  }
 }
 //扩展实现:点击按钮实现左滑效果
 public void toLeft(RecyclerView recyclerView) {
  if (check(recyclerView)) {
   animTo(recyclerView, false);
  }
 }
 //扩展实现:点击按钮实现右滑效果
 public void toRight(RecyclerView recyclerView) {
  if (check(recyclerView)) {
   animTo(recyclerView, true);
  }
 }
 private void animTo(final RecyclerView recyclerView, boolean right) {
  final int position = recyclerView.getAdapter().getItemCount() - 1;
  final View view = recyclerView.findViewHolderForAdapterPosition(position).itemView;
  TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
    Animation.RELATIVE_TO_SELF, right &#63; 1f : -1f,
    Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1.3f);
  translateAnimation.setFillAfter(true);
  translateAnimation.setDuration(300);
  translateAnimation.setInterpolator(new DecelerateInterpolator());
  translateAnimation.setAnimationListener(new Animation.AnimationListener() {
   @Override
   public void onAnimationStart(Animation animation) {
   }
   @Override
   public void onAnimationEnd(Animation animation) {
    isSwipeAnim = false;
    recyclerView.removeView(view);
    notifyListener(position,
      x > view.getMeasuredWidth() / 2
        &#63;
        ItemTouchHelper.RIGHT : ItemTouchHelper.LEFT);
   }
   @Override
   public void onAnimationRepeat(Animation animation) {
   }
  });
  view.startAnimation(translateAnimation);
 }
 private boolean check(RecyclerView recyclerView) {
  if (isSwipeAnim) {
   return false;
  }
  if (recyclerView == null || recyclerView.getAdapter() == null) {
   return false;
  }
  if (recyclerView.getAdapter().getItemCount() == 0) {
   return false;
  }
  isSwipeAnim = true;
  return true;
 }
 public interface OnSwipeListener {
  /**
   * @param direction {@link ItemTouchHelper#LEFT} / {@link ItemTouchHelper#RIGHT}
   *     {@link ItemTouchHelper#UP} or {@link ItemTouchHelper#DOWN}).
   */
  void onSwiped(int adapterPosition, int direction);
  /**
   * 最上层View滑动时回调.
   *
   * @param viewHolder 最上层的ViewHolder
   * @param offset  距离原始位置的偏移量
   */
  void onSwipeTo(RecyclerView.ViewHolder viewHolder, float offset);
 }
 public static class SimpleSwipeCallback implements OnSwipeListener {
  /**
   * {@inheritDoc}
   */
  @Override
  public void onSwiped(int adapterPosition, int direction) {
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void onSwipeTo(RecyclerView.ViewHolder viewHolder, float offset) {
  }
 }
}

看起来不难, 但是真正做的时候, 要处理的地方很多,

并且有些地方要思考很久, 才能实现效果.

总之,做了你才会发现1+1=2的魅力, just do it.

开源地址: https://github.com/angcyo/RecyclerLayoutManager

好了,以上所示是小编给大家分享的Android开发中RecyclerView模仿探探左右滑动布局功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言。


推荐阅读
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 解决微信电脑版无法刷朋友圈问题:使用安卓远程投屏方案
    在工作期间想要浏览微信和朋友圈却不太方便?虽然微信电脑版目前不支持直接刷朋友圈,但通过远程投屏技术,可以轻松实现在电脑上操作安卓设备的功能。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 资源推荐 | TensorFlow官方中文教程助力英语非母语者学习
    来源:机器之心。本文详细介绍了TensorFlow官方提供的中文版教程和指南,帮助开发者更好地理解和应用这一强大的开源机器学习平台。 ... [详细]
  • 构建基于BERT的中文NL2SQL模型:一个简明的基准
    本文探讨了将自然语言转换为SQL语句(NL2SQL)的任务,这是人工智能领域中一项非常实用的研究方向。文章介绍了笔者在公司举办的首届中文NL2SQL挑战赛中的实践,该比赛提供了金融和通用领域的表格数据,并标注了对应的自然语言与SQL语句对,旨在训练准确的NL2SQL模型。 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • 本文介绍如何使用 Sortable.js 库实现元素的拖拽和位置交换功能。Sortable.js 是一个轻量级、无依赖的 JavaScript 库,支持拖拽排序、动画效果和多种插件扩展。通过简单的配置和事件处理,可以轻松实现复杂的功能。 ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本文详细介绍了如何在 Spring Boot 应用中通过 @PropertySource 注解读取非默认配置文件,包括配置文件的创建、映射类的设计以及确保 Spring 容器能够正确加载这些配置的方法。 ... [详细]
  • 网络运维工程师负责确保企业IT基础设施的稳定运行,保障业务连续性和数据安全。他们需要具备多种技能,包括搭建和维护网络环境、监控系统性能、处理突发事件等。本文将探讨网络运维工程师的职业前景及其平均薪酬水平。 ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
author-avatar
邵世以_806
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有