iOS开发中如何基于ColorStyle枚举动态切换TextView样式并设置文本
基于ColorStyle枚举动态切换文本样式的实现方案
现有实现的核心堵点
- 原
TextLayout协议使用关联类型associatedtype TextView,属于编译期强类型绑定:一旦把textView的具体类型锁死为BlackTextView,运行时无法替换为同继承链的WhiteTextView实例,类型系统会直接抛出不兼容错误。 - 原
colorStyle只是无观察逻辑的普通存储属性,赋值后没有绑定对应的视图更新流程,传值后没有实际的样式切换效果。 - 原Cell代码存在属性名拼写错误(把
colorStyle错写为colorSytle),赋值链路从一开始就没有打通。 - 原代码把
textView写死为固定初始化的存储属性,预留的WhiteTextView实例完全无法触发替换逻辑。
分步改造实现
1. 调整TextLayout协议约束,解除运行时的类型锁死
既然BlackTextView和WhiteTextView都是UITextView的子类,不需要通过关联类型绑定具体子类,直接把协议约束放宽为基类类型即可:
public protocol TextLayout { // 移除关联类型,直接要求返回UITextView基类实例,支持运行时替换不同子类 var textView: UITextView { get } }
调整逻辑:关联类型适合需要固定子类做专属业务逻辑的场景,在需要动态切换同继承链子类的场景下,用基类做协议约束可以完全放开类型限制。
2. 改造MyView的内部逻辑,支持colorStyle变化触发样式刷新
把textView改为可动态替换的存储属性,给colorStyle加属性观察器,赋值后自动切换对应的文本样式实例:
@IBDesignable public class MyView: View, TextLayout { // 私有存储textView当前实例,设为只读外部访问 public private(set) var textView: UITextView = BlackTextView() // 给colorStyle加属性观察,赋值后立刻触发样式更新 public var colorStyle: ColorStyle = .none { didSet { refreshTextStyle() } } // 视图初始化阶段的公共逻辑 override init(frame: CGRect) { super.init(frame: frame) commonSetup() } required init?(coder: NSCoder) { super.init(coder: coder) commonSetup() } private func commonSetup() { // 第一次加载时就应用当前默认的colorStyle样式 refreshTextStyle() } private func refreshTextStyle() { // 1. 先备份当前textView的文本内容,避免切换样式时内容丢失 let oldText = textView.text let oldAttributedText = textView.attributedText // 2. 把旧的textView从视图层级移除 textView.removeFromSuperview() // 3. 根据colorStyle匹配对应的文本样式实例 switch colorStyle { case .dark: textView = BlackTextView() case .light: textView = WhiteTextView() case .none: // 无样式场景使用基础UITextView,可按业务自定义中性样式 textView = UITextView() } // 4. 把备份的文本内容恢复到新的textView上 textView.text = oldText textView.attributedText = oldAttributedText // 5. 把新textView加回视图层级,重设AutoLayout约束 addSubview(textView) applyTextViewConstraints() } // 抽离公共约束逻辑,避免每次切换实例重复写布局代码 private func applyTextViewConstraints() { textView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ textView.topAnchor.constraint(equalTo: topAnchor), textView.leadingAnchor.constraint(equalTo: leadingAnchor), textView.trailingAnchor.constraint(equalTo: trailingAnchor), textView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } }
3. 修正Cell的赋值逻辑,打通数据链路
修正原Cell里的拼写错误,统一通过textView承载文本内容,避免多套文本控件同步问题:
class TableViewCell: UITableViewCell { @IBOutlet weak var myView: MyView! func setup(viewModel: MyViewModel) { // 移除冗余的titleLabel赋值逻辑,统一用textView设置标题文本 myView.textView.text = viewModel.titleText // 修正原来的拼写错误,赋值colorStyle后会自动触发样式切换 myView.colorStyle = viewModel.colorStyle } }
适配说明:这套实现完全兼容你现有
BlackTextView和WhiteTextView的封装逻辑,只要两个自定义子类的样式、字体、边距等属性是在初始化方法里配置的,不需要额外写样式赋值代码,替换实例就能自动应用对应的色彩方案。
内容的提问来源于stack exchange,提问作者user1162328
相关产品推荐
相关产品推荐

