feat: support flick up to pop the media. resolve #464

This commit is contained in:
CMK 2022-07-13 19:23:32 +08:00
parent 206fe8d3bd
commit fec7b92d38
1 changed files with 19 additions and 15 deletions

View File

@ -329,13 +329,10 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning {
return return
case .began, .changed: case .began, .changed:
let translation = sender.translation(in: transitionContext.containerView) let translation = sender.translation(in: transitionContext.containerView)
let percent = popInteractiveTransitionAnimator.fractionComplete + progressStep(for: translation) let percent = progressStep(for: translation)
popInteractiveTransitionAnimator.fractionComplete = percent popInteractiveTransitionAnimator.fractionComplete = percent
transitionContext.updateInteractiveTransition(percent) transitionContext.updateInteractiveTransition(percent)
updateTransitionItemPosition(of: translation) updateTransitionItemPosition(of: translation)
// Reset translation to zero
sender.setTranslation(CGPoint.zero, in: transitionContext.containerView)
case .ended, .cancelled: case .ended, .cancelled:
let targetPosition = completionPosition() let targetPosition = completionPosition()
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: target position: %s", ((#file as NSString).lastPathComponent), #line, #function, targetPosition == .end ? "end" : "start") os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: target position: %s", ((#file as NSString).lastPathComponent), #line, #function, targetPosition == .end ? "end" : "start")
@ -379,9 +376,9 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning {
let isFlickDown = isFlick && (velocity.dy > 0.0) let isFlickDown = isFlick && (velocity.dy > 0.0)
let isFlickUp = isFlick && (velocity.dy < 0.0) let isFlickUp = isFlick && (velocity.dy < 0.0)
if (operation == .push && isFlickUp) || (operation == .pop && isFlickDown) { if (operation == .push && isFlickUp) || (operation == .pop && (isFlickDown || isFlickUp)) {
return .end return .end
} else if (operation == .push && isFlickDown) || (operation == .pop && isFlickUp) { } else if (operation == .push && isFlickDown) {
return .start return .start
} else if popInteractiveTransitionAnimator.fractionComplete > completionThreshold { } else if popInteractiveTransitionAnimator.fractionComplete > completionThreshold {
return .end return .end
@ -490,7 +487,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning {
} }
private func progressStep(for translation: CGPoint) -> CGFloat { private func progressStep(for translation: CGPoint) -> CGFloat {
return (operation == .push ? -1.0 : 1.0) * translation.y / transitionContext.containerView.bounds.midY let progress = abs(translation.y) / (transitionContext.containerView.bounds.height / 2)
return progress
} }
private func updateTransitionItemPosition(of translation: CGPoint) { private func updateTransitionItemPosition(of translation: CGPoint) {
@ -500,26 +498,32 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning {
guard initialSize != .zero else { return } guard initialSize != .zero else { return }
// assert(initialSize != .zero) // assert(initialSize != .zero)
guard let snapshot = transitionItem.snapshotTransitioning, guard let transitionView = transitionItem.transitionView,
let finalSize = transitionItem.targetFrame?.size else { let snapshot = transitionItem.snapshotTransitioning,
let finalSize = transitionItem.targetFrame?.size
else {
return return
} }
if snapshot.frame.size == .zero { if snapshot.frame.size == .zero {
assertionFailure("divide 0 error")
snapshot.frame.size = initialSize snapshot.frame.size = initialSize
} }
let currentSize = snapshot.frame.size let size = transitionView.frame.size
if size.width == .zero || size.height == .zero {
assertionFailure("divide 0 error")
transitionView.frame.size = initialSize
}
let itemPercentComplete = clip(-0.05, 1.05, (currentSize.width - initialSize.width) / (finalSize.width - initialSize.width) + progress) let itemPercentComplete = clip(-0.05, 1.05, (size.width - initialSize.width) / (finalSize.width - initialSize.width) + progress)
let itemWidth = lerp(initialSize.width, finalSize.width, itemPercentComplete) let itemWidth = lerp(initialSize.width, finalSize.width, itemPercentComplete)
let itemHeight = lerp(initialSize.height, finalSize.height, itemPercentComplete) let itemHeight = lerp(initialSize.height, finalSize.height, itemPercentComplete)
assert(currentSize.width != 0.0) let scaleTransform = CGAffineTransform(scaleX: (itemWidth / size.width), y: (itemHeight / size.height))
assert(currentSize.height != 0.0)
let scaleTransform = CGAffineTransform(scaleX: (itemWidth / currentSize.width), y: (itemHeight / currentSize.height))
let scaledOffset = transitionItem.touchOffset.apply(transform: scaleTransform) let scaledOffset = transitionItem.touchOffset.apply(transform: scaleTransform)
snapshot.center = (snapshot.center + (translation + (transitionItem.touchOffset - scaledOffset))).point let center = transitionView.convert(transitionView.center, to: nil)
snapshot.center = (center + (translation + (transitionItem.touchOffset - scaledOffset))).point
snapshot.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: itemWidth, height: itemHeight)) snapshot.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: itemWidth, height: itemHeight))
transitionItem.touchOffset = scaledOffset transitionItem.touchOffset = scaledOffset
} }