自定义手势缩放的Recyclerview

本文介绍了如何在Recyclerview中实现自定义手势缩放功能,以创建类似腾讯动漫的漫画阅读器。通过重写dispatchDraw()方法,结合偏移量计算和缩放中心确定,实现了缩放和平移。文章提供了计算过程和代码实现,并分享了GitHub项目链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义手势缩放的Recyclerview

最近做了一个类似腾讯动漫的漫画的阅读器,用Recyclerview作为基础的控件展示漫画。因为漫画需要支持手势缩放,但是原生Recyclerview并不支持,而且开源的缩放Recyclerview也没有找到,只能自己造一个轮子。这篇文章记录了一些思路。

效果预览图:https://github.com/PortgasAce/ZoomRecyclerView

基本原理

通过重写Recyclerview的dispatchDraw()方法,操作canvas缩放和平移实现手势缩放功能。如果对矩阵熟练的话,可以给canvas设置矩阵实现,但是我不熟练。。所以只能通过最基本的canvas平移和缩放实现。

  protected void dispatchDraw(@NonNull Canvas canvas) {

    canvas.save();
    canvas.translate(mTranX, mTranY);
    canvas.scale(mScaleFactor, mScaleFactor);

    // 所有子view都会缩放和平移
    super.dispatchDraw(canvas);
    canvas.restore();
  }

计算过程

通过上面的代码片段可知,只需要x,y方向的偏移量(mTranx,mTranY)和缩放系数(mScaleFactor)就可以实现缩放。

偏移量的计算

偏移量与另一个值相关,就是缩放中心(双击的触摸点 或者 是双指触摸的中心)。设想一下双击屏幕的的左上角和右下角,缩放系数的值相同,但是偏移量不同,双击左上角的偏移量为(0,0),而右下角的偏移量则为(-MaxTranX,-MaxTranY)。

双击屏幕上一点的示例图如下:

demo


总偏移量:
MaxTranX = X1+X2 = W1(S2-S1)
MaxTranY = Y1+Y2 = H1(S2-S1)
X方向偏移量比总偏移量 等于 缩放中心比屏幕宽度
X1/MaxTranX = X1/W1(S2-S1) = Tx/W1
Y1/MaxTranY = Y1/H1(S2-S1) = Ty/H1

X1 = W1(S2-S1)*(Tx/W1) = (S2-S1)*Tx
Y1 = H1(S2-21)*(Ty/H1) = (S2-S1)*Ty
最终A2点的坐标因为坐标系的原因需要加一个负号:
A2 = (-X1,-Y1) = (-(S2-S1)*Tx,-(S2-S1)*Ty)

缩放中心

双击缩放通过GestureDetector实现,缩放中心在onDoubleTap()方法中直接通过MotionEvent的getX()和getY()获取。

双指缩放通过ScaleDetector实现,缩放中心通过ScaleGestureDetector的getFocusX()和getFocusY()获取。

缩放系数

双击缩放时,如果当前的缩放系数不等于1则缩放系数为1,如果当前缩放系数为1,则缩放系数等于最大缩放系数。

双指缩放时,缩放系数为当前缩放系数 乘 onScale回调中detector.getScaleFactor()。

代码

/**
 * 默认缩放比只能为1
 * 缩放动画时长暂时没有根据缩放比例改动
 */
@SuppressWarnings("UnnecessaryLocalVariable")
@SuppressLint("ClickableViewAccessibility")
public class ZoomRecyclerView extends RecyclerView {
   
   

  private static final String TAG = "999";

  // constant
  private static final int DEFAULT_SCALE_DURATION = 300;
  private static final float DEFAULT_SCALE_FACTOR = 1.f;
  private static final float DEFAULT_MAX_SCALE_FACTOR = 2.0f;
  private static final float DEFAULT_MIN_SCALE_FACTOR = 0.5f;
  private static final String PROPERTY_SCALE = "scale";
  private static final String PROPERTY_TRANX = "tranX";
  private static final String PROPERTY_TRANY = "tranY";
  private static final float INVALID_TOUCH_POSITION = -1;

  // touch detector
  ScaleGestureDetector mScaleDetector;
  GestureDetectorCompat mGestureDetector;

  // draw param
  float mViewWidth;       // 宽度
  float mViewHeight;      // 高度
  float mTranX;           // x偏移量
  float mTranY;           // y偏移量
  float mScaleFactor;     // 缩放系数

  
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值