mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Effect improvements
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import TelegramPresentationData
|
||||
|
||||
final class WarpView: UIView {
|
||||
private final class WarpPartView: UIView {
|
||||
let cloneView: PortalView
|
||||
|
||||
init?(contentView: PortalSourceView) {
|
||||
guard let cloneView = PortalView(matchPosition: false) else {
|
||||
return nil
|
||||
}
|
||||
self.cloneView = cloneView
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.0)
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.addSubview(cloneView.view)
|
||||
contentView.addPortal(view: cloneView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(containerSize: CGSize, rect: CGRect, transition: Transition) {
|
||||
transition.setFrame(view: self.cloneView.view, frame: CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: CGSize(width: containerSize.width, height: containerSize.height)))
|
||||
}
|
||||
}
|
||||
|
||||
let contentView: PortalSourceView
|
||||
|
||||
private let clippingView: UIView
|
||||
|
||||
private var warpViews: [WarpPartView] = []
|
||||
private let warpMaskContainer: UIView
|
||||
private let warpMaskGradientLayer: SimpleGradientLayer
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.contentView = PortalSourceView()
|
||||
self.clippingView = UIView()
|
||||
|
||||
self.warpMaskContainer = UIView()
|
||||
self.warpMaskGradientLayer = SimpleGradientLayer()
|
||||
self.warpMaskContainer.layer.mask = self.warpMaskGradientLayer
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.clippingView.addSubview(self.contentView)
|
||||
|
||||
self.clippingView.clipsToBounds = true
|
||||
self.addSubview(self.clippingView)
|
||||
self.addSubview(self.warpMaskContainer)
|
||||
|
||||
for _ in 0 ..< 8 {
|
||||
if let warpView = WarpPartView(contentView: self.contentView) {
|
||||
self.warpViews.append(warpView)
|
||||
self.warpMaskContainer.addSubview(warpView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(size: CGSize, topInset: CGFloat, warpHeight: CGFloat, theme: PresentationTheme, transition: Transition) {
|
||||
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let allItemsHeight = warpHeight * 0.5
|
||||
for i in 0 ..< self.warpViews.count {
|
||||
let itemHeight = warpHeight / CGFloat(self.warpViews.count)
|
||||
let itemFraction = CGFloat(i + 1) / CGFloat(self.warpViews.count)
|
||||
let _ = itemHeight
|
||||
|
||||
let da = CGFloat.pi * 0.5 / CGFloat(self.warpViews.count)
|
||||
let alpha = CGFloat.pi * 0.5 - itemFraction * CGFloat.pi * 0.5
|
||||
let endPoint = CGPoint(x: cos(alpha), y: sin(alpha))
|
||||
let prevAngle = alpha + da
|
||||
let prevPt = CGPoint(x: cos(prevAngle), y: sin(prevAngle))
|
||||
var angle: CGFloat
|
||||
angle = -atan2(endPoint.y - prevPt.y, endPoint.x - prevPt.x)
|
||||
|
||||
let itemLengthVector = CGPoint(x: endPoint.x - prevPt.x, y: endPoint.y - prevPt.y)
|
||||
let itemLength = sqrt(itemLengthVector.x * itemLengthVector.x + itemLengthVector.y * itemLengthVector.y) * warpHeight * 0.5
|
||||
let _ = itemLength
|
||||
|
||||
var transform: CATransform3D
|
||||
transform = CATransform3DIdentity
|
||||
transform.m34 = 1.0 / 240.0
|
||||
|
||||
transform = CATransform3DTranslate(transform, 0.0, prevPt.x * allItemsHeight, (1.0 - prevPt.y) * allItemsHeight)
|
||||
transform = CATransform3DRotate(transform, angle, 1.0, 0.0, 0.0)
|
||||
|
||||
let positionY = size.height - allItemsHeight + 4.0 + CGFloat(i) * itemLength
|
||||
let rect = CGRect(origin: CGPoint(x: 0.0, y: positionY), size: CGSize(width: size.width, height: itemLength))
|
||||
transition.setPosition(view: self.warpViews[i], position: CGPoint(x: rect.midX, y: 4.0))
|
||||
transition.setBounds(view: self.warpViews[i], bounds: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: itemLength)))
|
||||
transition.setTransform(view: self.warpViews[i], transform: transform)
|
||||
self.warpViews[i].update(containerSize: size, rect: rect, transition: transition)
|
||||
}
|
||||
|
||||
let clippingTopInset: CGFloat = topInset
|
||||
let frame = CGRect(origin: CGPoint(x: 0.0, y: clippingTopInset), size: CGSize(width: size.width, height: -clippingTopInset + size.height - 21.0))
|
||||
transition.setPosition(view: self.clippingView, position: frame.center)
|
||||
transition.setBounds(view: self.clippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: clippingTopInset), size: frame.size))
|
||||
self.clippingView.clipsToBounds = true
|
||||
|
||||
transition.setFrame(view: self.warpMaskContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - allItemsHeight), size: CGSize(width: size.width, height: allItemsHeight)))
|
||||
|
||||
var locations: [NSNumber] = []
|
||||
var colors: [CGColor] = []
|
||||
let numStops = 6
|
||||
for i in 0 ..< numStops {
|
||||
let step = CGFloat(i) / CGFloat(numStops - 1)
|
||||
locations.append(step as NSNumber)
|
||||
colors.append(UIColor.black.withAlphaComponent(1.0 - step * step).cgColor)
|
||||
}
|
||||
|
||||
let gradientHeight: CGFloat = 6.0
|
||||
self.warpMaskGradientLayer.startPoint = CGPoint(x: 0.0, y: (allItemsHeight - gradientHeight) / allItemsHeight)
|
||||
self.warpMaskGradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
|
||||
|
||||
self.warpMaskGradientLayer.locations = locations
|
||||
self.warpMaskGradientLayer.colors = colors
|
||||
self.warpMaskGradientLayer.type = .axial
|
||||
|
||||
transition.setFrame(layer: self.warpMaskGradientLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: allItemsHeight)))
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
return self.contentView.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user