zoomimage icon indicating copy to clipboard operation
zoomimage copied to clipboard

CoilZoomAsyncImage自定义下滑关闭手势跟缩放手势冲突,加了下滑关闭后,缩放不灵敏

Open JohnAstra opened this issue 9 months ago • 6 comments

JohnAstra avatar Apr 05 '25 12:04 JohnAstra

补充一下,因为图片浏览器通常都带有进入的动画,比如从消息流的图片cell原始rect,慢慢放大到全屏。这个时候zoomState.zoomable.transform.scaleX会从原始rect的1慢慢变大,所以当处于图片预览页的时候,这个scaleX就已经不是1了。如果根据finalRect.width/startRect.width去计算,确实也能解决这个问题。不过不太优雅,建议在动画期间不要改这个zoomState.zoomable.transform.scaleX

JohnAstra avatar Apr 05 '25 13:04 JohnAstra

zoomState.zoomable.transform 是当前总的缩放信息,zoomState.zoomable.baseTransform 是基础缩放信息,由 scaleType 决定,zoomState.zoomable.userTransform 是由用户产生的缩放信息,所以你判断 userTransform 即可

panpf avatar Apr 05 '25 13:04 panpf

zoomState.zoomable.transform 是当前总的缩放信息,zoomState.zoomable.baseTransform 是基础缩放信息,由 scaleType 决定,zoomState.zoomable.userTransform 是由用户产生的缩放信息,所以你判断 userTransform 即可

多谢,是否处于scaling状态的问题是解决了。但是遇到了新的问题,就是没有处于缩放状态的时候下滑手势跟缩放手势出现了冲突。导致缩放不灵敏

JohnAstra avatar Apr 09 '25 06:04 JohnAstra

  val dragGesture = rememberDraggableState { delta ->
    // 仅在非多点触控时处理拖拽
    if (!isMultiTouch) {
      val canDrag =
        when {
          // up
          delta < 0 -> offsetY > -boundaryThreshold
          // down
          delta > 0 -> offsetY < boundaryThreshold
          else -> false
        }

      if (canDrag) {
        offsetY += delta
        isDragging = true
      }
      onOffsetChange(offsetY)
    }
  }

  val onDragEnd = { velocity: Float ->
    isDragging = false

    val velocityThreshold = 1000f
    val shouldDismiss =
      when {
        abs(velocity) > velocityThreshold -> true
        abs(offsetY) > screenHeight * maxFactor -> true
        else -> false
      }

    if (shouldDismiss) {
      wrappedOnDismiss()
    } else {
      offsetY = 0f
      // Reset opacity to 1 when drag is cancelled
      alpha = 1f
      onOpacityChange(alpha)
    }
    onDragEnd(shouldDismiss)
  }

  // Calculate the parallax translation
  // As the page moves away from center, shift the image in the opposite direction
  // This creates the parallax effect where background moves slower than foreground
  //  val imageTranslation = pageOffset * screenWidth.value * parallaxFactor

  val zoomState = rememberCoilZoomState()

  debug(TAG, "zoomState:${zoomState.zoomable.userTransform.scaleX}")

  isZooming = zoomState.zoomable.userTransform.scaleX != 1.0f

//  LaunchedEffect(zoomState.zoomable) {
//    zoomState.zoomable.disabledGestureTypes =
//      zoomState.zoomable.disabledGestureTypes or
//        GestureType.ONE_FINGER_SCALE or
//        GestureType.MOUSE_WHEEL_SCALE or
//        GestureType.KEYBOARD_SCALE
//  }

  Card(
    modifier = Modifier.fillMaxSize(),
    shape = RectangleShape,
    colors = CardDefaults.cardColors(containerColor = Color.Transparent),
  ) {
    Box(modifier = Modifier.fillMaxSize()) {
      CoilZoomAsyncImage(
        model = ImageRequest.Builder(LocalContext.current).data(imageUrl).crossfade(true).build(),
        contentDescription = null,
        zoomState = zoomState,
        scrollBar = null,
        onTap = { onTap() },
        modifier =
          Modifier.fillMaxSize()
            .graphicsLayer { translationX = pageOffset }
            .then(
              if (isZooming) {
                Modifier
              } else {
                Modifier
                  // 添加触摸事件检测器,优先于draggable,在触摸开始时检测是单指还是多指
                  .pointerInput(Unit) {
                    awaitPointerEventScope {
                      while (true) {
                        val event = awaitPointerEvent()
                        // 检测多点触控
                        isMultiTouch = event.changes.size > 1
                        debug(
                          TAG,
                          "Touch event: ${event.changes.size} fingers, isMultiTouch=$isMultiTouch",
                        )
                      }
                    }
                  }
                  .offset { IntOffset(0, animatedOffsetY.value.roundToInt()) }
                  .draggable(
                    state = dragGesture,
                    orientation = Orientation.Vertical,
                    onDragStarted = {
                      // 仅在非多点触控时启动拖拽
                      if (!isMultiTouch) {
                        isDragging = true
                        onDragStart()
                      }
                    },
                    onDragStopped = { velocity ->
                      // 仅在非多点触控时处理拖拽结束
                      if (!isMultiTouch) {
                        onDragEnd(velocity)
                      }
                    },
                  )
              }
            ),
      )
    }
  }

大佬帮忙看下这个下滑拖拽手势怎么跟缩放手势并存,目前只要加了draggable缩放就很不灵敏。试过禁用掉ONE_FINGER_SCALE依然不好使

JohnAstra avatar Apr 09 '25 06:04 JohnAstra

这个我没有实践过,没法指导你,只能说一下整体的思路

首先从 Down 开始你就要拦截全部事件,然后判断当前是否处于可以关闭的状态,以及手势是否要是关闭手势,是的话继续自己消费后续事件处理关闭,不是的话就释放后续事件让 ZoomImage 消费,这其中会涉及到很多细节,需要你一个个解决

panpf avatar Apr 09 '25 06:04 panpf

这个我没有实践过,没法指导你,只能说一下整体的思路

首先从 Down 开始你就要拦截全部事件,然后判断当前是否处于可以关闭的状态,以及手势是否要是关闭手势,是的话继续自己消费后续事件处理关闭,不是的话就释放后续事件让 ZoomImage 消费,这其中会涉及到很多细节,需要你一个个解决

按照你的思路,我应该修改源码的哪一部分。我尝试过直接在awaitPointerEventScope拦截事件,但是事件依然会先被CoilZoomAsyncImage消费掉

JohnAstra avatar Apr 09 '25 14:04 JohnAstra