mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Adjust reaction menu animation
This commit is contained in:
@@ -217,7 +217,8 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
|
|||||||
func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) {
|
func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) {
|
||||||
let springDuration: Double = 0.5
|
let springDuration: Double = 0.5
|
||||||
let springDamping: CGFloat = 104.0
|
let springDamping: CGFloat = 104.0
|
||||||
let springDelay: Double = 0.05
|
let springScaleDelay: Double = 0.1
|
||||||
|
let springDelay: Double = springScaleDelay + 0.01
|
||||||
let shadowInset: CGFloat = 15.0
|
let shadowInset: CGFloat = 15.0
|
||||||
|
|
||||||
let contentBounds = self.backgroundView.frame
|
let contentBounds = self.backgroundView.frame
|
||||||
@@ -225,6 +226,9 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
|
|||||||
let visualSourceBackgroundFrame = sourceBackgroundFrame.offsetBy(dx: -contentBounds.minX, dy: -contentBounds.minY)
|
let visualSourceBackgroundFrame = sourceBackgroundFrame.offsetBy(dx: -contentBounds.minX, dy: -contentBounds.minY)
|
||||||
let sourceShadowFrame = visualSourceBackgroundFrame.insetBy(dx: -shadowInset, dy: -shadowInset)
|
let sourceShadowFrame = visualSourceBackgroundFrame.insetBy(dx: -shadowInset, dy: -shadowInset)
|
||||||
|
|
||||||
|
self.backgroundClippingLayer.animateScale(from: 0.001, to: 1.0, duration: 0.2, delay: springScaleDelay, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||||
|
self.backgroundShadowLayer.animateScale(from: 0.001, to: 1.0, duration: 0.2, delay: springScaleDelay, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||||
|
|
||||||
self.backgroundClippingLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: visualSourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.backgroundClippingLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: visualSourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
self.backgroundClippingLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualSourceBackgroundFrame.size)), to: NSValue(cgRect: self.backgroundClippingLayer.bounds), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
self.backgroundClippingLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualSourceBackgroundFrame.size)), to: NSValue(cgRect: self.backgroundClippingLayer.bounds), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||||
self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceShadowFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceShadowFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
@@ -232,11 +236,12 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOut() {
|
func animateOut() {
|
||||||
self.backgroundClippingLayer.animateAlpha(from: CGFloat(self.backgroundClippingLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
self.maskLayer.allowsGroupOpacity = true
|
||||||
|
self.maskLayer.animateAlpha(from: CGFloat(self.backgroundClippingLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||||
self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
//self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||||
self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
//self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private var horizontalExpandStartLocation: CGPoint?
|
private var horizontalExpandStartLocation: CGPoint?
|
||||||
private var horizontalExpandDistance: CGFloat = 0.0
|
private var horizontalExpandDistance: CGFloat = 0.0
|
||||||
|
|
||||||
|
private var animateInInfo: (centerX: CGFloat, width: CGFloat)?
|
||||||
|
|
||||||
public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void) {
|
public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
@@ -876,14 +878,16 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let animateInFromAnchorRect = animateInFromAnchorRect {
|
if let animateInFromAnchorRect = animateInFromAnchorRect {
|
||||||
let springDuration: Double = 0.5
|
let springDuration: Double = 0.5
|
||||||
let springDamping: CGFloat = 104.0
|
let springDamping: CGFloat = 104.0
|
||||||
let springDelay: Double = 0.05
|
let springScaleDelay: Double = 0.1
|
||||||
|
let springDelay: Double = springScaleDelay + 0.01
|
||||||
|
|
||||||
let sourceBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: backgroundInsets, anchorRect: animateInFromAnchorRect, contentSize: CGSize(width: visualBackgroundFrame.height, height: contentHeight)).0
|
let sourceBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: backgroundInsets, anchorRect: animateInFromAnchorRect, contentSize: CGSize(width: visualBackgroundFrame.height, height: contentHeight)).0
|
||||||
|
|
||||||
self.backgroundNode.animateInFromAnchorRect(size: visualBackgroundFrame.size, sourceBackgroundFrame: sourceBackgroundFrame.offsetBy(dx: -visualBackgroundFrame.minX, dy: -visualBackgroundFrame.minY))
|
self.backgroundNode.animateInFromAnchorRect(size: visualBackgroundFrame.size, sourceBackgroundFrame: sourceBackgroundFrame.offsetBy(dx: -visualBackgroundFrame.minX, dy: -visualBackgroundFrame.minY))
|
||||||
|
|
||||||
|
self.animateInInfo = (visualBackgroundFrame.midX - sourceBackgroundFrame.midX, visualBackgroundFrame.width)
|
||||||
self.contentContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.contentContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
self.contentContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
self.contentContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(x: -(sourceBackgroundFrame.midX - visualBackgroundFrame.midX), y: 0.0), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||||
|
|
||||||
self.contentTintContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
self.contentTintContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||||
self.contentTintContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
self.contentTintContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||||
@@ -1002,7 +1006,6 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, isAnimatingOut: false, transition: .immediate, animateInFromAnchorRect: sourceAnchorRect, animateOutToAnchorRect: nil)
|
self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, isAnimatingOut: false, transition: .immediate, animateInFromAnchorRect: sourceAnchorRect, animateOutToAnchorRect: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
//let mainCircleDuration: Double = 0.5
|
|
||||||
let mainCircleDelay: Double = 0.01
|
let mainCircleDelay: Double = 0.01
|
||||||
|
|
||||||
self.backgroundNode.animateIn()
|
self.backgroundNode.animateIn()
|
||||||
@@ -1014,14 +1017,31 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
guard let itemNode = self.visibleItemNodes[i] else {
|
guard let itemNode = self.visibleItemNodes[i] else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let itemDelay = mainCircleDelay + Double(i) * 0.06
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + itemDelay, execute: { [weak itemNode] in
|
let itemDelay: Double
|
||||||
|
if let animateInInfo = self.animateInInfo {
|
||||||
|
let distance = abs(itemNode.frame.center.x - animateInInfo.centerX)
|
||||||
|
let distanceNorm = distance / animateInInfo.width
|
||||||
|
itemDelay = mainCircleDelay + distanceNorm * 0.4
|
||||||
|
} else {
|
||||||
|
itemDelay = mainCircleDelay + Double(i) * 0.06
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + itemDelay * UIView.animationDurationFactor(), execute: { [weak itemNode] in
|
||||||
itemNode?.appear(animated: true)
|
itemNode?.appear(animated: true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemDelay = mainCircleDelay + Double(self.visibleItemNodes.count) * 0.06
|
|
||||||
if let expandItemView = self.expandItemView {
|
if let expandItemView = self.expandItemView {
|
||||||
|
let itemDelay: Double
|
||||||
|
if let animateInInfo = self.animateInInfo {
|
||||||
|
let distance = abs(expandItemView.frame.center.x - animateInInfo.centerX)
|
||||||
|
let distanceNorm = distance / animateInInfo.width
|
||||||
|
itemDelay = mainCircleDelay + distanceNorm * 0.4
|
||||||
|
} else {
|
||||||
|
itemDelay = mainCircleDelay + Double(8) * 0.06
|
||||||
|
}
|
||||||
|
|
||||||
expandItemView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay)
|
expandItemView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay)
|
||||||
expandItemView.tintView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay)
|
expandItemView.tintView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,11 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
|||||||
|
|
||||||
func appear(animated: Bool) {
|
func appear(animated: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
|
if self.item.isCustom {
|
||||||
|
self.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||||
|
} else {
|
||||||
self.animateInAnimationNode?.visibility = true
|
self.animateInAnimationNode?.visibility = true
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.animateInAnimationNode?.completed(true)
|
self.animateInAnimationNode?.completed(true)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user