アプリ内で、アラート(UIAlertController)のボタンの文字をUIAppearanceで一括変更していたのですが、
iOS9だと反映されていないことに気づき、その対応をしたときのメモです。
また、
UIView.appearance().tintColor = UIColor.greenColor()
UITextField.appearance().tintColor = UIColor.greenColor()
に近い書き方ができるようにしてみました。
試した環境
- Xcode 7.0
- Swift 2.0
- iOS8,9共に動作
コード
extensionと、Method Swizzlingを用いてます。
UIAlertController+Appearance.swift
import Foundation
import UIKit
extension UIAlertController {
class Appearance {
private static let sharedInstance = Appearance()
var tintColor: UIColor?
private init() {
}
class func appearance() -> Appearance {
return sharedInstance
}
}
class func appearance() -> Appearance {
return Appearance.appearance()
}
public override class func initialize() {
struct Static {
static var onceToken: dispatch_once_t = 0
}
dispatch_once(&Static.onceToken) {
let originalSelector = Selector("viewWillLayoutSubviews")
let swizzledSelector = Selector("swizzle_viewWillLayoutSubviews")
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
func swizzle_viewWillLayoutSubviews() {
swizzle_viewWillLayoutSubviews()
self.view.tintColor = self.dynamicType.appearance().tintColor
}
}
こんな感じで実装すると、以下のように書いて変更ができます。
UIAlertController.appearance().tintColor = UIColor.purpleColor()
途中で色を変えることももちろん可能です。
// 注 : UIViewController内を想定
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
UIAlertController.appearance().tintColor = UIColor.purpleColor()
let alert = UIAlertController(title: "test", message: "test message", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "dismiss", style: .Default, handler: { [unowned self] _ in
UIAlertController.appearance().tintColor = UIColor.greenColor()
let alert = UIAlertController(title: "test2", message: "test message2", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "dismiss", style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
注意書き
注1) 現状、*UIAlertController.appearance()*がないので問題はないですが、将来的に同名の関数が定義されて、標準で変更可能となった場合は衝突する可能性はあります。とりあえず、現状では問題はないということで。
注2) Method Swizzlingを用いているので、あまりそういうのは...という方は、下記参考にさせていただいた記事の方を参照して、
UIAlertControllerを継承する形で対応するほうがよいかもしれません。
Method Swizzlingしておりますが、動作に関しては問題ありません。
参考にさせていただいた記事
- iOS9でUIAlertControllerのテキストカラーを変更する
http://qiita.com/katsuhisaishii/items/2547230452f48f115f3d
→Objective-Cでの同様の対応方法について書かれています。