// // LNOnlineView.swift // Lanu // // Created by OneeChan on 2026/1/4. // import Foundation import UIKit import SnapKit class LNOnlineView: UIView { var borderColor: UIColor = .primary_3 { didSet { reset() } } var borderWidth: CGFloat = 1 { didSet { reset() } } var duration: Double = 1.2 { didSet { reset() } } var offset = 5.0 { didSet { reset() } } private let borderLayer = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) layer.borderWidth = borderWidth layer.borderColor = borderColor.cgColor clipsToBounds = false isUserInteractionEnabled = false borderLayer.borderWidth = borderWidth borderLayer.borderColor = borderColor.cgColor layer.addSublayer(borderLayer) startAnimate() } private func startAnimate() { let scaleAnim = CABasicAnimation(keyPath: "transform.scale") scaleAnim.fromValue = 1.0 scaleAnim.toValue = 1.0 + offset / CGFloat(bounds.width / 2) scaleAnim.duration = duration let opacityAnim = CABasicAnimation(keyPath: "opacity") opacityAnim.fromValue = 1.0 opacityAnim.toValue = 0.0 opacityAnim.duration = duration let animGroup = CAAnimationGroup() animGroup.animations = [scaleAnim, opacityAnim] animGroup.duration = duration animGroup.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) animGroup.isRemovedOnCompletion = false animGroup.fillMode = .forwards animGroup.repeatCount = .infinity borderLayer.add(animGroup, forKey: "scaleAndFadeGroup") } override func layoutSubviews() { super.layoutSubviews() layer.cornerRadius = bounds.height * 0.5 if borderLayer.frame.height != bounds.height { reset() } } private func reset() { borderLayer.frame = bounds borderLayer.cornerRadius = bounds.height * 0.5 borderLayer.removeAllAnimations() startAnimate() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } #if DEBUG import SwiftUI struct LNOnlineViewPreview: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let container = UIView() container.backgroundColor = .lightGray let view = LNOnlineView() container.addSubview(view) view.snp.makeConstraints { make in make.center.equalToSuperview() make.width.height.equalTo(50) } return container } func updateUIView(_ uiView: UIViewType, context: Context) { } } #Preview(body: { LNOnlineViewPreview() }) #endif