mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Improve spoiler reveal
This commit is contained in:
parent
b3eb582c22
commit
a217e4c1aa
@ -17,11 +17,28 @@ private func createEmitterBehavior(type: String) -> NSObject {
|
|||||||
public class InvisibleInkDustNode: ASDisplayNode {
|
public class InvisibleInkDustNode: ASDisplayNode {
|
||||||
private var currentParams: (size: CGSize, color: UIColor, rects: [CGRect])?
|
private var currentParams: (size: CGSize, color: UIColor, rects: [CGRect])?
|
||||||
|
|
||||||
|
private weak var textNode: TextNode?
|
||||||
|
|
||||||
|
private let maskNode: ASDisplayNode
|
||||||
|
private let spotNode: ASImageNode
|
||||||
|
|
||||||
private var emitter: CAEmitterCell?
|
private var emitter: CAEmitterCell?
|
||||||
private var emitterLayer: CAEmitterLayer?
|
private var emitterLayer: CAEmitterLayer?
|
||||||
|
|
||||||
public var isRevealedUpdated: (Bool) -> Void = { _ in }
|
public var isRevealedUpdated: (Bool) -> Void = { _ in }
|
||||||
|
|
||||||
|
public init(textNode: TextNode) {
|
||||||
|
self.textNode = textNode
|
||||||
|
|
||||||
|
self.maskNode = ASDisplayNode()
|
||||||
|
self.spotNode = ASImageNode()
|
||||||
|
self.spotNode.image = UIImage(bundleImageName: "Components/TextSpot")
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.maskNode.addSubnode(self.spotNode)
|
||||||
|
}
|
||||||
|
|
||||||
public override func didLoad() {
|
public override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
@ -77,23 +94,48 @@ public class InvisibleInkDustNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var revealed = false
|
private var revealed = false
|
||||||
@objc private func tap(_ gestureRecognizer: UITapGestureRecognizer) {
|
@objc private func tap(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||||
guard !self.revealed else {
|
guard let (size, _, _) = self.currentParams, !self.revealed else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.revealed = true
|
self.revealed = true
|
||||||
|
|
||||||
let position = gestureRecognizer.location(in: self.view)
|
let position = gestureRecognizer.location(in: self.view)
|
||||||
self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
|
self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
|
||||||
self.emitterLayer?.setValue(position, forKeyPath: "emitterBehaviors.fingerAttractor.position")
|
self.emitterLayer?.setValue(position, forKeyPath: "emitterBehaviors.fingerAttractor.position")
|
||||||
|
|
||||||
|
self.textNode?.view.mask = self.maskNode.view
|
||||||
|
self.textNode?.alpha = 1.0
|
||||||
|
|
||||||
|
let radius = max(size.width, size.height)
|
||||||
|
self.spotNode.frame = CGRect(x: position.x - radius / 2.0, y: position.y - radius / 2.0, width: radius, height: radius)
|
||||||
|
|
||||||
|
self.spotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||||
|
self.spotNode.layer.animateScale(from: 0.0, to: 3.5, duration: 0.61, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
|
self?.textNode?.view.mask = nil
|
||||||
|
})
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2) {
|
Queue.mainQueue().after(0.2) {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .linear)
|
||||||
|
transition.updateAlpha(node: self, alpha: 0.0)
|
||||||
|
|
||||||
self.isRevealedUpdated(true)
|
self.isRevealedUpdated(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.7) {
|
||||||
|
self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
|
||||||
|
self.spotNode.layer.removeAllAnimations()
|
||||||
|
}
|
||||||
|
|
||||||
Queue.mainQueue().after(4.0) {
|
Queue.mainQueue().after(4.0) {
|
||||||
self.revealed = false
|
self.revealed = false
|
||||||
self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
|
|
||||||
self.isRevealedUpdated(false)
|
self.isRevealedUpdated(false)
|
||||||
|
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .linear)
|
||||||
|
transition.updateAlpha(node: self, alpha: 1.0)
|
||||||
|
if let textNode = self.textNode {
|
||||||
|
transition.updateAlpha(node: textNode, alpha: 0.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +162,8 @@ public class InvisibleInkDustNode: ASDisplayNode {
|
|||||||
|
|
||||||
public func update(size: CGSize, color: UIColor, rects: [CGRect]) {
|
public func update(size: CGSize, color: UIColor, rects: [CGRect]) {
|
||||||
self.currentParams = (size, color, rects)
|
self.currentParams = (size, color, rects)
|
||||||
|
|
||||||
|
self.maskNode.frame = CGRect(origin: CGPoint(x: 3.0, y: 3.0), size: size)
|
||||||
|
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
self.updateEmitter()
|
self.updateEmitter()
|
||||||
|
21
submodules/TelegramUI/Images.xcassets/Components/TextSpot.imageset/Contents.json
vendored
Normal file
21
submodules/TelegramUI/Images.xcassets/Components/TextSpot.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "blurSmall_Normal@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
submodules/TelegramUI/Images.xcassets/Components/TextSpot.imageset/blurSmall_Normal@3x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Components/TextSpot.imageset/blurSmall_Normal@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
@ -387,18 +387,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if let current = strongSelf.dustNode {
|
if let current = strongSelf.dustNode {
|
||||||
dustNode = current
|
dustNode = current
|
||||||
} else {
|
} else {
|
||||||
dustNode = InvisibleInkDustNode()
|
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode)
|
||||||
dustNode.isRevealedUpdated = { [weak self] revealed in
|
|
||||||
if let strongSelf = self {
|
|
||||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .linear)
|
|
||||||
if let dustNode = strongSelf.dustNode {
|
|
||||||
transition.updateAlpha(node: dustNode, alpha: revealed ? 0.0 : 1.0)
|
|
||||||
}
|
|
||||||
if let spoilerTextNode = strongSelf.spoilerTextNode {
|
|
||||||
transition.updateAlpha(node: spoilerTextNode, alpha: revealed ? 1.0 : 0.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strongSelf.dustNode = dustNode
|
strongSelf.dustNode = dustNode
|
||||||
strongSelf.insertSubnode(dustNode, aboveSubnode: spoilerTextNode)
|
strongSelf.insertSubnode(dustNode, aboveSubnode: spoilerTextNode)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user