jsdw_ios/QuickLocation/Section/Group/GroupChat/VoiceRecordView.swift

263 lines
7.5 KiB
Swift

//
// VoiceRecordView.swift
// QuickLocation
//
// Created by on 2026/6/6.
//
import UIKit
import Lottie
final class VoiceRecordView: UIView {
enum State {
case recording
case canceling
}
var state: State = .recording {
didSet {
updateUI()
}
}
private func updateUI() {
switch state {
case .recording:
tipsLab.text = "松开发送"
startRotating()
case .canceling:
tipsLab.text = "松开取消"
}
}
lazy var bgView: UIView = {
let v = UIView()
v.backgroundColor = .clear
v.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.1).cgColor
v.layer.shadowOffset = CGSize(width: 0, height: 0)
v.layer.shadowOpacity = 1
v.layer.shadowRadius = 8
return v
}()
lazy var topContainer: UIView = {
let v = UIView()
v.backgroundColor = .white
return v
}()
lazy var keyboardBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "IM/keyboard"), for: .normal)
return btn
}()
lazy var titleView: UIView = {
let v = UIView()
v.layer.shadowColor = UIColor(red: 0.06, green: 0.16, blue: 0.27, alpha: 0.1).cgColor
v.layer.shadowOffset = CGSize(width: 0, height: 0)
v.layer.shadowOpacity = 1
v.layer.shadowRadius = 9
let cornerView = UIView()
cornerView.backgroundColor = .white
cornerView.cornerRadius = 19
let label = UILabel()
label.text = "正在录入语音..."
label.font = .systemFont(ofSize: 12)
label.textColor = ThemeManager.shared.color.subTitleColor
label.textAlignment = .center
v.addSubview(cornerView)
v.addSubview(label)
cornerView.layoutChain.edges()
label.layoutChain.centerX().centerY()
return v
}()
lazy var emojiBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "IM/emoji_off"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 0)
return btn
}()
lazy var addBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "IM/add_off"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 15)
return btn
}()
lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .white
return view
}()
lazy var tipsLab: UILabel = {
let label = UILabel()
label.text = " "
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textColor = ThemeManager.shared.color.titleAuxColor
label.textAlignment = .center
return label
}()
lazy var speakingImgView: UIImageView = {
let view = UIImageView(image: UIImage(named: "IM/speaking"))
view.isHidden = true
return view
}()
lazy var speakBtn: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#E7F7FF")
view.cornerRadius = 48
let icon = UIImageView(image: UIImage(named: "IM/speak"))
view.addSubview(icon)
icon.layoutChain
.centerX()
.centerY()
return view
}()
lazy var cancelLab: UILabel = {
let label = UILabel()
label.text = "左滑取消"
label.font = .systemFont(ofSize: 12, weight: .regular)
label.textColor = ThemeManager.shared.color.contentColor
return label
}()
lazy var cancelBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "IM/cancel_off"), for: .normal)
btn.setImage(UIImage(named: "IM/cancel"), for: .selected)
btn.isUserInteractionEnabled = false
return btn
}()
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
addSubview(bgView)
bgView.addSubview(topContainer)
topContainer.addSubview(keyboardBtn)
topContainer.addSubview(titleView)
topContainer.addSubview(emojiBtn)
topContainer.addSubview(addBtn)
bgView.addSubview(containerView)
containerView.addSubview(tipsLab)
containerView.addSubview(speakBtn)
containerView.addSubview(speakingImgView)
containerView.addSubview(cancelLab)
containerView.addSubview(cancelBtn)
bgView.layoutChain.edges()
topContainer.layoutChain
.edges(excludingEdge: .bottom)
.height(58)
keyboardBtn.layoutChain
.left(22)
.centerY()
.width(36)
.height(36)
addBtn.layoutChain
.right(22)
.centerY()
.width(24)
.height(24)
emojiBtn.layoutChain
.rightToLeftOfView(addBtn, offset: -8)
.centerY()
.width(24)
.height(24)
titleView.layoutChain
.top(10)
.leftToRightOfView(keyboardBtn, offset: 7)
.rightToLeftOfView(emojiBtn, offset: -12)
.bottom(10)
containerView.layoutChain
.topToBottomOfView(topContainer, offset: 0)
.edges(excludingEdge: .top)
tipsLab.layoutChain
.top(18)
.centerX()
speakBtn.layoutChain
.height(96)
.widthToHeight(1)
.centerY()
.centerX()
speakingImgView.layoutChain
.topToView(speakBtn, offset: -6)
.leftToView(speakBtn, offset: -6)
.rightToView(speakBtn, offset: 6)
.bottomToView(speakBtn, offset: 6)
cancelBtn.layoutChain
.rightToLeftOfView(speakBtn, offset: -47)
.centerY(speakBtn)
.width(41)
.heightToWidth(1)
cancelLab.layoutChain
.bottomToTopOfView(cancelBtn, offset: -7)
.centerX(cancelBtn)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
topContainer.setNeedsLayout()
topContainer.layoutIfNeeded()
topContainer.setCornerRadius(corners: [.topRight, .topLeft], withCornerRadii: CGSize(width: 20, height: 20))
}
}
extension VoiceRecordView {
func startRotating() {
guard speakingImgView.isHidden == true else { return }
speakingImgView.isHidden = false
//
speakingImgView.layer.removeAnimation(forKey: "rotationAnimation")
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.fromValue = 0
rotationAnimation.toValue = Double.pi * 2 // 360°
rotationAnimation.duration = 1.0
rotationAnimation.repeatCount = .infinity //
rotationAnimation.isRemovedOnCompletion = false
rotationAnimation.fillMode = .forwards
speakingImgView.layer.add(rotationAnimation, forKey: "rotationAnimation")
}
func stopRotating() {
tipsLab.text = " "
speakingImgView.isHidden = true
speakingImgView.layer.removeAnimation(forKey: "rotationAnimation")
}
}