mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Various improvements
This commit is contained in:
@@ -248,8 +248,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
compositingFilter = nil
|
||||
}
|
||||
|
||||
shimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(alpha), gradientSize: 70.0, duration: 2.4, horizontal: true)
|
||||
borderShimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(borderAlpha), gradientSize: 70.0, duration: 2.4, horizontal: true)
|
||||
shimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(alpha), gradientSize: 70.0, duration: 3.0, horizontal: true)
|
||||
borderShimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(borderAlpha), gradientSize: 70.0, duration: 3.0, horizontal: true)
|
||||
|
||||
shimmerView.layer.compositingFilter = compositingFilter
|
||||
borderShimmerView.layer.compositingFilter = compositingFilter
|
||||
@@ -259,15 +259,42 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
guard theme !== self.theme else {
|
||||
return
|
||||
}
|
||||
let previousTheme = self.theme
|
||||
self.theme = theme
|
||||
|
||||
if animated {
|
||||
let animateTransition = previousTheme.backgroundColors.count != theme.backgroundColors.count
|
||||
|
||||
if animated && animateTransition {
|
||||
if let snapshotView = self.buttonBackgroundNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
self.view.insertSubview(snapshotView, aboveSubview: self.buttonBackgroundNode.view)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
if let snapshotView = self.titleNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = self.titleNode.frame
|
||||
|
||||
self.view.insertSubview(snapshotView, aboveSubview: self.titleNode.view)
|
||||
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: 15.0), duration: 0.2, removeOnCompletion: false, additive: true)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
self.titleNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -15.0), to: CGPoint(), duration: 0.2, additive: true)
|
||||
self.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
if let snapshotView = self.iconNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = self.iconNode.frame
|
||||
|
||||
self.view.insertSubview(snapshotView, aboveSubview: self.iconNode.view)
|
||||
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: 15.0), duration: 0.2, removeOnCompletion: false, additive: true)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
self.iconNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -15.0), to: CGPoint(), duration: 0.2, additive: true)
|
||||
self.iconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
if theme.backgroundColors.count > 1 {
|
||||
self.buttonBackgroundNode.backgroundColor = nil
|
||||
@@ -317,8 +344,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
transition.updateFrame(view: borderMaskView, frame: buttonFrame)
|
||||
transition.updateFrame(view: borderShimmerView, frame: buttonFrame)
|
||||
|
||||
shimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 3.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 7.0, height: buttonHeight))
|
||||
borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 3.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 7.0, height: buttonHeight))
|
||||
shimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight))
|
||||
borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
@@ -435,7 +462,12 @@ public final class SolidRoundedButtonView: UIView {
|
||||
|
||||
private let buttonBackgroundNode: UIImageView
|
||||
private var buttonBackgroundAnimationView: UIImageView?
|
||||
private let buttonGlossView: SolidRoundedButtonGlossView?
|
||||
|
||||
private var shimmerView: ShimmerEffectForegroundView?
|
||||
private var borderView: UIView?
|
||||
private var borderMaskView: UIView?
|
||||
private var borderShimmerView: ShimmerEffectForegroundView?
|
||||
|
||||
private let buttonNode: HighlightTrackingButton
|
||||
private let titleNode: ImmediateTextView
|
||||
private let subtitleNode: ImmediateTextView
|
||||
@@ -515,13 +547,7 @@ public final class SolidRoundedButtonView: UIView {
|
||||
} else {
|
||||
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
|
||||
}
|
||||
|
||||
if gloss {
|
||||
self.buttonGlossView = SolidRoundedButtonGlossView(color: theme.foregroundColor, cornerRadius: cornerRadius)
|
||||
} else {
|
||||
self.buttonGlossView = nil
|
||||
}
|
||||
|
||||
|
||||
self.buttonNode = HighlightTrackingButton()
|
||||
|
||||
self.titleNode = ImmediateTextView()
|
||||
@@ -536,9 +562,6 @@ public final class SolidRoundedButtonView: UIView {
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.addSubview(self.buttonBackgroundNode)
|
||||
if let buttonGlossView = self.buttonGlossView {
|
||||
self.addSubview(buttonGlossView)
|
||||
}
|
||||
self.addSubview(self.buttonNode)
|
||||
self.addSubview(self.titleNode)
|
||||
self.addSubview(self.subtitleNode)
|
||||
@@ -575,6 +598,36 @@ public final class SolidRoundedButtonView: UIView {
|
||||
if #available(iOS 13.0, *) {
|
||||
self.buttonBackgroundNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
|
||||
if gloss {
|
||||
let shimmerView = ShimmerEffectForegroundView()
|
||||
self.shimmerView = shimmerView
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
shimmerView.layer.cornerCurve = .continuous
|
||||
shimmerView.layer.cornerRadius = self.buttonCornerRadius
|
||||
}
|
||||
|
||||
let borderView = UIView()
|
||||
borderView.isUserInteractionEnabled = false
|
||||
self.borderView = borderView
|
||||
|
||||
let borderMaskView = UIView()
|
||||
borderMaskView.layer.borderWidth = 1.0 + UIScreenPixel
|
||||
borderMaskView.layer.borderColor = UIColor.white.cgColor
|
||||
borderMaskView.layer.cornerRadius = self.buttonCornerRadius
|
||||
borderView.mask = borderMaskView
|
||||
self.borderMaskView = borderMaskView
|
||||
|
||||
let borderShimmerView = ShimmerEffectForegroundView()
|
||||
self.borderShimmerView = borderShimmerView
|
||||
borderView.addSubview(borderShimmerView)
|
||||
|
||||
self.insertSubview(shimmerView, belowSubview: self.buttonNode)
|
||||
self.insertSubview(borderView, belowSubview: self.buttonNode)
|
||||
|
||||
self.updateShimmerParameters()
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder: NSCoder) {
|
||||
@@ -601,7 +654,7 @@ public final class SolidRoundedButtonView: UIView {
|
||||
CATransaction.begin()
|
||||
|
||||
let animation = CABasicAnimation(keyPath: "position.x")
|
||||
animation.duration = Double.random(in: 1.8 ..< 2.3)
|
||||
animation.duration = 4.5
|
||||
animation.fromValue = previousValue
|
||||
animation.toValue = newValue
|
||||
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
|
||||
@@ -660,6 +713,33 @@ public final class SolidRoundedButtonView: UIView {
|
||||
self.subtitleNode.layer.animateAlpha(from: 0.55, to: 0.0, duration: 0.2)
|
||||
}
|
||||
|
||||
func updateShimmerParameters() {
|
||||
guard let shimmerView = self.shimmerView, let borderShimmerView = self.borderShimmerView else {
|
||||
return
|
||||
}
|
||||
|
||||
let color = self.theme.foregroundColor
|
||||
let alpha: CGFloat
|
||||
let borderAlpha: CGFloat
|
||||
let compositingFilter: String?
|
||||
if color.lightness > 0.5 {
|
||||
alpha = 0.5
|
||||
borderAlpha = 0.75
|
||||
compositingFilter = "overlayBlendMode"
|
||||
} else {
|
||||
alpha = 0.2
|
||||
borderAlpha = 0.3
|
||||
compositingFilter = nil
|
||||
}
|
||||
|
||||
shimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(alpha), gradientSize: 70.0, duration: 3.0, horizontal: true)
|
||||
borderShimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(borderAlpha), gradientSize: 70.0, duration: 3.0, horizontal: true)
|
||||
|
||||
shimmerView.layer.compositingFilter = compositingFilter
|
||||
borderShimmerView.layer.compositingFilter = compositingFilter
|
||||
}
|
||||
|
||||
|
||||
public func updateTheme(_ theme: SolidRoundedButtonTheme) {
|
||||
guard theme !== self.theme else {
|
||||
return
|
||||
@@ -680,7 +760,6 @@ public final class SolidRoundedButtonView: UIView {
|
||||
self.buttonBackgroundNode.image = nil
|
||||
}
|
||||
|
||||
self.buttonGlossView?.color = theme.foregroundColor
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: theme.foregroundColor)
|
||||
|
||||
@@ -689,6 +768,8 @@ public final class SolidRoundedButtonView: UIView {
|
||||
if let width = self.validLayout {
|
||||
_ = self.updateLayout(width: width, transition: .immediate)
|
||||
}
|
||||
|
||||
self.updateShimmerParameters()
|
||||
}
|
||||
|
||||
public func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
@@ -702,14 +783,21 @@ public final class SolidRoundedButtonView: UIView {
|
||||
let buttonFrame = CGRect(origin: CGPoint(), size: buttonSize)
|
||||
transition.updateFrame(view: self.buttonBackgroundNode, frame: buttonFrame)
|
||||
|
||||
if let shimmerView = self.shimmerView, let borderView = self.borderView, let borderMaskView = self.borderMaskView, let borderShimmerView = self.borderShimmerView {
|
||||
transition.updateFrame(view: shimmerView, frame: buttonFrame)
|
||||
transition.updateFrame(view: borderView, frame: buttonFrame)
|
||||
transition.updateFrame(view: borderMaskView, frame: buttonFrame)
|
||||
transition.updateFrame(view: borderShimmerView, frame: buttonFrame)
|
||||
|
||||
shimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight))
|
||||
borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight))
|
||||
}
|
||||
|
||||
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
|
||||
transition.updateFrame(view: buttonBackgroundAnimationView, frame: CGRect(origin: CGPoint(), size: CGSize(width: buttonSize.width * 2.4, height: buttonSize.height)))
|
||||
self.setupGradientAnimations()
|
||||
}
|
||||
|
||||
if let buttonGlossView = self.buttonGlossView {
|
||||
transition.updateFrame(view: buttonGlossView, frame: buttonFrame)
|
||||
}
|
||||
|
||||
transition.updateFrame(view: self.buttonNode, frame: buttonFrame)
|
||||
|
||||
if self.title != self.titleNode.attributedText?.string {
|
||||
@@ -770,112 +858,3 @@ public final class SolidRoundedButtonView: UIView {
|
||||
self.pressed?()
|
||||
}
|
||||
}
|
||||
|
||||
private final class SolidRoundedButtonGlossViewParameters: NSObject {
|
||||
let gradientColors: NSArray?
|
||||
let cornerRadius: CGFloat
|
||||
let progress: CGFloat
|
||||
|
||||
init(gradientColors: NSArray?, cornerRadius: CGFloat, progress: CGFloat) {
|
||||
self.gradientColors = gradientColors
|
||||
self.cornerRadius = cornerRadius
|
||||
self.progress = progress
|
||||
}
|
||||
}
|
||||
|
||||
public final class SolidRoundedButtonGlossView: UIView {
|
||||
public var color: UIColor {
|
||||
didSet {
|
||||
self.updateGradientColors()
|
||||
self.setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
private var progress: CGFloat = 0.0
|
||||
private var animator: ConstantDisplayLinkAnimator?
|
||||
private let buttonCornerRadius: CGFloat
|
||||
private var gradientColors: NSArray?
|
||||
|
||||
private let trackingLayer: HierarchyTrackingLayer
|
||||
|
||||
public init(color: UIColor, cornerRadius: CGFloat) {
|
||||
self.color = color
|
||||
self.buttonCornerRadius = cornerRadius
|
||||
|
||||
self.trackingLayer = HierarchyTrackingLayer()
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.layer.addSublayer(self.trackingLayer)
|
||||
|
||||
self.isOpaque = false
|
||||
|
||||
var previousTime: CFAbsoluteTime?
|
||||
self.animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
if let previousTime = previousTime {
|
||||
var delta: CGFloat
|
||||
if strongSelf.progress < 0.05 || strongSelf.progress > 0.95 {
|
||||
delta = 0.001
|
||||
} else {
|
||||
delta = 0.009
|
||||
}
|
||||
delta *= CGFloat(currentTime - previousTime) * 60.0
|
||||
var newProgress = strongSelf.progress + delta
|
||||
if newProgress > 1.0 {
|
||||
newProgress = 0.0
|
||||
}
|
||||
strongSelf.progress = newProgress
|
||||
strongSelf.setNeedsDisplay()
|
||||
}
|
||||
previousTime = currentTime
|
||||
})
|
||||
|
||||
self.updateGradientColors()
|
||||
|
||||
self.trackingLayer.didEnterHierarchy = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.animator?.isPaused = false
|
||||
}
|
||||
|
||||
self.trackingLayer.didExitHierarchy = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.animator?.isPaused = true
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func updateGradientColors() {
|
||||
let transparentColor = self.color.withAlphaComponent(0.0).cgColor
|
||||
self.gradientColors = [transparentColor, transparentColor, self.color.withAlphaComponent(0.12).cgColor, transparentColor, transparentColor]
|
||||
}
|
||||
|
||||
override public func draw(_ rect: CGRect) {
|
||||
let parameters = SolidRoundedButtonGlossViewParameters(gradientColors: self.gradientColors, cornerRadius: self.buttonCornerRadius, progress: self.progress)
|
||||
guard let gradientColors = parameters.gradientColors else {
|
||||
return
|
||||
}
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()!
|
||||
|
||||
let path = UIBezierPath(roundedRect: bounds, cornerRadius: parameters.cornerRadius)
|
||||
context.addPath(path.cgPath)
|
||||
context.clip()
|
||||
|
||||
var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0]
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
let x = -4.0 * bounds.size.width + 8.0 * bounds.size.width * parameters.progress
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: x, y: 0.0), end: CGPoint(x: x + bounds.size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user