#33 利用 notification center 在 controller 間傳資料
Published in
8 min readAug 17, 2023
在設定視圖中調整其他視圖內Label的字型大小
本次作業會使用到以下技術
- 用來傳遞異動訊息的notification center
- 用來存取字型大小數值的UserDefault
- 以Singleton Design Pattern來統一處理字型大小變更的Extension型別
- 用IBOutletCollection統一變更視圖內的Label大小
佈局
先設置字型大小與Slider拉桿異動後的位置數值存取,分別做成set與get方法用來存取UserDefault內的值,因為UIFont只吃CGFloat,所以回傳值要做轉型。
class UserDefaultsManager {
// Singleton
static let shared = UserDefaultsManager()
private init() {}
// UserDefault的Key,避免使用Hardcode
private let fontSizekey = "fontSizekey"
private let sliderValuekey = "sliderValuekey"
// 存取各視圖內Label所需的字型大小
func getFontSize() -> CGFloat {
let savedFontSize = UserDefaults.standard.float(forKey: fontSizekey)
return CGFloat(savedFontSize > 0 ? savedFontSize : 17)
}
func setFontSize(_ size: Float) {
UserDefaults.standard.set(size, forKey: fontSizekey)
}
// 存取設定視圖內Slider拉桿的位置
func getSliderValue() -> Float? {
let savedSliderValue = UserDefaults.standard.float(forKey: sliderValuekey)
return savedSliderValue
}
func setSliderValue(_ value: Float) {
UserDefaults.standard.set(value, forKey: sliderValuekey)
}
}
接著在設定ViewController內新增notification center的延伸型別,主要是避免發送訊息時打錯字。
// 程式的通知中心
extension Notification.Name {
static let doRefreshNotification = Notification.Name("doRefreshNotification")
}
在Slider的IBAction中寫一段程式碼,用來存放拉桿的值,然後透過notification center發送廣播訊息到其他視圖。
@IBAction func adjustFontSize(_ sender: UISlider) {
sender.value.round() // 捨棄小數點值
UserDefaultsManager.shared.setFontSize(sender.value + 17)
UserDefaultsManager.shared.setSliderValue(sender.value)
let fontSize = UserDefaultsManager.shared.getFontSize()
self.customLabelFont(size: fontSize)
NotificationCenter.default.post(name: .doRefreshNotification, object: nil) // 程式的通知中心
}
設定視圖內統一用一個function來處理不同的Lable大小,然後用forloop處理IBOutletCollection的FontSize。
func customLabelFont(size fontSize: CGFloat) {
for label in cloudLabels {
label.font = UIFont.systemFont(ofSize: fontSize)
}
sampleFontLabel.font = UIFont.systemFont(ofSize: fontSize)
codeLabel.font = UIFont.systemFont(ofSize: fontSize)
}
IBOutletCollection連接如下圖,注意是Array型別。
然後要在設定控制器的ViewDidLoad配置好每次進入時更新Label大小與Slider拉桿值,其他控制器只需要更新Label大小,用UserDefaultsManager讀取資料然後改變元件Font Size。
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
func updateUI() {
if let sliderValue = UserDefaultsManager.shared.getSliderValue() {
fontSize.value = sliderValue // 設定拉桿值
let fontSize = UserDefaultsManager.shared.getFontSize()
self.customLabelFont(size: fontSize)
}
}
func customLabelFont(size fontSize: CGFloat) {
for label in cloudLabels {
label.font = UIFont.systemFont(ofSize: fontSize)
}
sampleFontLabel.font = UIFont.systemFont(ofSize: fontSize)
codeLabel.font = UIFont.systemFont(ofSize: fontSize)
}
其他視圖控制器則要搭配notification center接收異動通知並更新元件Font Size,下面是TableView的設定範例。
class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var fontSize: CGFloat = 17 // 用來接收UserDefault的回傳值
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
updateUI()
// 觸發通知中心時自動刷新新的訊息
NotificationCenter.default.addObserver(self,
selector: #selector(updateUI),
name: .doRefreshNotification,
object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updateUI()
}
@objc
func updateUI() {
self.fontSize = UserDefaultsManager.shared.getFontSize()
self.tableView.setCustomCellLabelFont(size: fontSize)
}
}
extension UITableView {
func setCustomCellLabelFont(size: CGFloat) {
let labelAppearanceProxy = UILabel.appearance(whenContainedInInstancesOf: [UITableViewCell.self])
labelAppearanceProxy.font = UIFont.systemFont(ofSize: size)
}
}
成果