chat setting font size
This commit is contained in:
parent
4c4c578d0b
commit
1cedc98838
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SnapKit
|
||||||
|
|
||||||
// font
|
// font
|
||||||
struct FontRow: RowModel {
|
struct FontRow: RowModel {
|
||||||
|
|
@ -13,57 +14,129 @@ struct FontRow: RowModel {
|
||||||
let icon: String
|
let icon: String
|
||||||
let title: String
|
let title: String
|
||||||
var cellReuseID: String { "ChatFontCell" }
|
var cellReuseID: String { "ChatFontCell" }
|
||||||
func cellHeight(tableWidth: CGFloat) -> CGFloat { 50 }
|
func cellHeight(tableWidth: CGFloat) -> CGFloat { 80 }
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatFontCell: ChatSettingBaseCell, CellConfigurable {
|
class ChatFontCell: ChatSettingBaseCell, CellConfigurable {
|
||||||
|
|
||||||
|
private var currentFontSize: Int = 20
|
||||||
|
private let minFontSize: Int = 10
|
||||||
|
private let maxFontSize: Int = 30
|
||||||
|
|
||||||
lazy var iconImgView: UIImageView = {
|
lazy var iconImgView: UIImageView = {
|
||||||
let imgView = UIImageView(image: UIImage(named: "role_exchange_mode"))
|
let imgView = UIImageView(image: UIImage(named: "role_font"))
|
||||||
return imgView
|
return imgView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var titleLab: UILabel = {
|
lazy var titleLab: UILabel = {
|
||||||
let lab = UILabel()
|
let lab = UILabel()
|
||||||
lab.text = "XL-0826-32K"
|
lab.text = "Font size"
|
||||||
lab.font = UIFont.boldSystemFont(ofSize: 14)
|
lab.font = UIFont.systemFont(ofSize: 14)
|
||||||
lab.textColor = UIColor(hex: "#666666")
|
lab.textColor = UIColor(hex: "#666666")
|
||||||
return lab
|
return lab
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var fontSub: UIButton = {
|
lazy var fontSizeLab: UILabel = {
|
||||||
let btn = UIButton()
|
|
||||||
btn.setImage(UIImage(named: "role_setting_font_sub"), for: .normal)
|
|
||||||
btn.addTarget(self, action: #selector(fontSubTap), for: .touchUpInside)
|
|
||||||
return btn
|
|
||||||
}()
|
|
||||||
|
|
||||||
lazy var fontAdd: UIButton = {
|
|
||||||
let btn = UIButton()
|
|
||||||
btn.setImage(UIImage(named: "role_setting_font_add"), for: .normal)
|
|
||||||
btn.addTarget(self, action: #selector(fontAddTap), for: .touchUpInside)
|
|
||||||
return btn
|
|
||||||
}()
|
|
||||||
|
|
||||||
lazy var fontLab: UILabel = {
|
|
||||||
let lab = UILabel()
|
let lab = UILabel()
|
||||||
lab.text = "20"
|
lab.text = "20"
|
||||||
lab.font = UIFont.systemFont(ofSize: 14)
|
lab.font = UIFont.systemFont(ofSize: 14)
|
||||||
lab.textColor = UIColor(hex: "#999999")
|
lab.textColor = UIColor(hex: "#999999")
|
||||||
lab.textAlignment = .center
|
lab.textAlignment = .right
|
||||||
return lab
|
return lab
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
lazy var sliderContainer: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var minusButton: UIButton = {
|
||||||
|
let btn = UIButton(type: .custom)
|
||||||
|
// 优先使用图片,否则显示蓝色文字
|
||||||
|
if let image = UIImage(named: "role_setting_font_sub") {
|
||||||
|
btn.setImage(image, for: .normal)
|
||||||
|
} else {
|
||||||
|
btn.setTitle("A-", for: .normal)
|
||||||
|
btn.setTitleColor(UIColor(hex: "#0066FF"), for: .normal)
|
||||||
|
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
|
||||||
|
}
|
||||||
|
btn.addTarget(self, action: #selector(decreaseFontSize), for: .touchUpInside)
|
||||||
|
return btn
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var plusButton: UIButton = {
|
||||||
|
let btn = UIButton(type: .custom)
|
||||||
|
// 优先使用图片,否则显示蓝色文字
|
||||||
|
if let image = UIImage(named: "role_setting_font_add") {
|
||||||
|
btn.setImage(image, for: .normal)
|
||||||
|
} else {
|
||||||
|
btn.setTitle("A+", for: .normal)
|
||||||
|
btn.setTitleColor(UIColor(hex: "#0066FF"), for: .normal)
|
||||||
|
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
|
||||||
|
}
|
||||||
|
btn.addTarget(self, action: #selector(increaseFontSize), for: .touchUpInside)
|
||||||
|
return btn
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var slider: UISlider = {
|
||||||
|
let slider = UISlider()
|
||||||
|
slider.minimumValue = Float(minFontSize)
|
||||||
|
slider.maximumValue = Float(maxFontSize)
|
||||||
|
slider.value = Float(currentFontSize)
|
||||||
|
|
||||||
|
// 设置灰色 track(根据图片描述)
|
||||||
|
slider.minimumTrackTintColor = UIColor(hex: "#E0E0E0")
|
||||||
|
slider.maximumTrackTintColor = UIColor(hex: "#E0E0E0")
|
||||||
|
|
||||||
|
// 自定义白色圆形 thumb
|
||||||
|
let thumbSize: CGFloat = 24
|
||||||
|
UIGraphicsBeginImageContextWithOptions(CGSize(width: thumbSize, height: thumbSize), false, 0.0)
|
||||||
|
if let context = UIGraphicsGetCurrentContext() {
|
||||||
|
context.setFillColor(UIColor.white.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(x: 0, y: 0, width: thumbSize, height: thumbSize))
|
||||||
|
// 添加阴影效果使thumb更突出
|
||||||
|
context.setShadow(offset: CGSize(width: 0, height: 1), blur: 2, color: UIColor.black.withAlphaComponent(0.2).cgColor)
|
||||||
|
}
|
||||||
|
let thumbImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
slider.setThumbImage(thumbImage, for: .normal)
|
||||||
|
slider.setThumbImage(thumbImage, for: .highlighted)
|
||||||
|
|
||||||
|
// 添加所有相关的事件监听,确保拖动流畅
|
||||||
|
slider.addTarget(self, action: #selector(sliderValueChanged(_:)), for: .valueChanged)
|
||||||
|
slider.addTarget(self, action: #selector(sliderTouchDown(_:)), for: .touchDown)
|
||||||
|
slider.addTarget(self, action: #selector(sliderTouchUp(_:)), for: [.touchUpInside, .touchUpOutside])
|
||||||
|
|
||||||
|
return slider
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tickMarksContainer: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .clear
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var tickMarks: [UIView] = []
|
||||||
|
|
||||||
func configure(with row: RowModel) {
|
func configure(with row: RowModel) {
|
||||||
guard let row = row as? FontRow else { return }
|
guard let row = row as? FontRow else { return }
|
||||||
titleLab.text = row.title
|
titleLab.text = row.title
|
||||||
iconImgView.image = UIImage(named: row.icon)
|
iconImgView.image = UIImage(named: row.icon)
|
||||||
|
|
||||||
|
// 更新容器高度
|
||||||
|
updateContainerHeight(80)
|
||||||
|
|
||||||
|
if let size = Int(row.count) {
|
||||||
|
currentFontSize = max(minFontSize, min(maxFontSize, size))
|
||||||
|
updateFontSize(currentFontSize, updateSlider: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
configureViews()
|
configureViews()
|
||||||
|
setupTickMarks()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
|
|
@ -71,48 +144,156 @@ class ChatFontCell: ChatSettingBaseCell, CellConfigurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureViews() {
|
func configureViews() {
|
||||||
|
|
||||||
containerView.addSubview(iconImgView)
|
containerView.addSubview(iconImgView)
|
||||||
containerView.addSubview(titleLab)
|
containerView.addSubview(titleLab)
|
||||||
containerView.addSubview(fontSub)
|
containerView.addSubview(fontSizeLab)
|
||||||
containerView.addSubview(fontAdd)
|
containerView.addSubview(sliderContainer)
|
||||||
containerView.addSubview(fontLab)
|
|
||||||
|
// 添加顺序很重要:先添加 slider,再添加 tick marks 覆盖在上面
|
||||||
|
sliderContainer.addSubview(minusButton)
|
||||||
|
sliderContainer.addSubview(plusButton)
|
||||||
|
sliderContainer.addSubview(slider)
|
||||||
|
sliderContainer.addSubview(tickMarksContainer)
|
||||||
|
|
||||||
|
// 确保 tick marks 在最上层,但不拦截触摸事件
|
||||||
|
sliderContainer.bringSubviewToFront(tickMarksContainer)
|
||||||
|
|
||||||
iconImgView.snp.makeConstraints { make in
|
iconImgView.snp.makeConstraints { make in
|
||||||
make.centerY.equalToSuperview()
|
make.top.equalToSuperview().offset(12)
|
||||||
make.left.equalToSuperview().offset(12)
|
make.left.equalToSuperview().offset(12)
|
||||||
make.width.height.equalTo(21)
|
make.width.height.equalTo(21)
|
||||||
}
|
}
|
||||||
|
|
||||||
titleLab.snp.makeConstraints { make in
|
titleLab.snp.makeConstraints { make in
|
||||||
make.centerY.equalToSuperview()
|
make.centerY.equalTo(iconImgView)
|
||||||
make.left.equalTo(iconImgView.snp.right).offset(9)
|
make.left.equalTo(iconImgView.snp.right).offset(9)
|
||||||
make.right.equalTo(fontSub.snp.left).offset(-5)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fontAdd.snp.makeConstraints { make in
|
fontSizeLab.snp.makeConstraints { make in
|
||||||
make.centerY.equalToSuperview()
|
make.centerY.equalTo(iconImgView)
|
||||||
make.right.equalToSuperview().inset(20)
|
make.right.equalToSuperview().inset(20)
|
||||||
make.width.height.equalTo(40)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fontLab.snp.makeConstraints { make in
|
sliderContainer.snp.makeConstraints { make in
|
||||||
make.centerY.equalToSuperview()
|
make.top.equalTo(iconImgView.snp.bottom).offset(12)
|
||||||
make.right.equalTo(fontAdd.snp.left).offset(-10)
|
make.left.right.equalToSuperview().inset(12)
|
||||||
|
make.bottom.equalToSuperview().inset(12)
|
||||||
|
make.height.equalTo(30)
|
||||||
}
|
}
|
||||||
|
|
||||||
fontSub.snp.makeConstraints { make in
|
minusButton.snp.makeConstraints { make in
|
||||||
|
make.left.centerY.equalToSuperview()
|
||||||
|
make.width.equalTo(30)
|
||||||
|
}
|
||||||
|
|
||||||
|
plusButton.snp.makeConstraints { make in
|
||||||
|
make.right.centerY.equalToSuperview()
|
||||||
|
make.width.equalTo(30)
|
||||||
|
}
|
||||||
|
|
||||||
|
slider.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(minusButton.snp.right).offset(8)
|
||||||
|
make.right.equalTo(plusButton.snp.left).offset(-8)
|
||||||
make.centerY.equalToSuperview()
|
make.centerY.equalToSuperview()
|
||||||
make.right.equalTo(fontLab.snp.left).offset(-10)
|
make.height.equalTo(30)
|
||||||
make.width.height.equalTo(40)
|
}
|
||||||
|
|
||||||
|
// tick marks 覆盖在 slider 上,但允许触摸穿透到 slider
|
||||||
|
tickMarksContainer.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalTo(slider)
|
||||||
|
make.centerY.equalTo(slider)
|
||||||
|
make.height.equalTo(slider).offset(4) // 稍微高一点以包含 tick marks
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保 tick marks 不拦截触摸事件
|
||||||
|
tickMarksContainer.isUserInteractionEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupTickMarks() {
|
||||||
|
// 创建5个小点作为tick marks(均匀分布)
|
||||||
|
let tickCount = 5
|
||||||
|
for _ in 0..<tickCount {
|
||||||
|
let tick = UIView()
|
||||||
|
tick.backgroundColor = UIColor(hex: "#CCCCCC")
|
||||||
|
tick.layer.cornerRadius = 2
|
||||||
|
tick.isUserInteractionEnabled = false // 不拦截触摸
|
||||||
|
tickMarksContainer.addSubview(tick)
|
||||||
|
tickMarks.append(tick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func fontSubTap() {
|
override func layoutSubviews() {
|
||||||
print("sub sub sub")
|
super.layoutSubviews()
|
||||||
|
// 重新布局tick marks(在layout完成后)
|
||||||
|
updateTickMarksLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func fontAddTap() {
|
private func updateTickMarksLayout() {
|
||||||
print("add add add")
|
guard tickMarks.count == 5, tickMarksContainer.bounds.width > 0 else { return }
|
||||||
|
let totalWidth = tickMarksContainer.bounds.width
|
||||||
|
// 5个点,4个间隔,均匀分布
|
||||||
|
let spacing = totalWidth / 4.0
|
||||||
|
let tickSize: CGFloat = 4
|
||||||
|
let centerY = tickMarksContainer.bounds.height / 2.0
|
||||||
|
|
||||||
|
for (index, tick) in tickMarks.enumerated() {
|
||||||
|
let centerX = CGFloat(index) * spacing
|
||||||
|
tick.frame = CGRect(
|
||||||
|
x: centerX - tickSize / 2.0,
|
||||||
|
y: centerY - tickSize / 2.0,
|
||||||
|
width: tickSize,
|
||||||
|
height: tickSize
|
||||||
|
)
|
||||||
|
tick.layer.cornerRadius = tickSize / 2.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func decreaseFontSize() {
|
||||||
|
if currentFontSize > minFontSize {
|
||||||
|
currentFontSize -= 1
|
||||||
|
updateFontSize(currentFontSize, updateSlider: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func increaseFontSize() {
|
||||||
|
if currentFontSize < maxFontSize {
|
||||||
|
currentFontSize += 1
|
||||||
|
updateFontSize(currentFontSize, updateSlider: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func sliderValueChanged(_ slider: UISlider) {
|
||||||
|
// 连续拖动时实时更新
|
||||||
|
let newValue = Int(round(slider.value))
|
||||||
|
if newValue != currentFontSize {
|
||||||
|
currentFontSize = newValue
|
||||||
|
updateFontSize(currentFontSize, updateSlider: false) // 不更新slider避免循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func sliderTouchDown(_ slider: UISlider) {
|
||||||
|
// 开始拖动
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func sliderTouchUp(_ slider: UISlider) {
|
||||||
|
// 结束拖动,确保值对齐到整数
|
||||||
|
let newValue = Int(round(slider.value))
|
||||||
|
currentFontSize = newValue
|
||||||
|
updateFontSize(currentFontSize, updateSlider: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateFontSize(_ size: Int, updateSlider: Bool = true) {
|
||||||
|
fontSizeLab.text = "\(size)"
|
||||||
|
|
||||||
|
if updateSlider {
|
||||||
|
slider.setValue(Float(size), animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新按钮状态(可选:根据需求决定是否禁用)
|
||||||
|
// minusButton.isEnabled = size > minFontSize
|
||||||
|
// plusButton.isEnabled = size < maxFontSize
|
||||||
|
|
||||||
|
// 这里可以添加字体大小改变的回调
|
||||||
|
// delegate?.fontSizeChanged(to: size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue