LoginSignup
11
10

More than 5 years have passed since last update.

UIAlertControllerのボタンの文字色を変更する(iOS8,9対応)

Last updated at Posted at 2015-10-22

アプリ内で、アラート(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しておりますが、動作に関しては問題ありません。

参考にさせていただいた記事

→Objective-Cでの同様の対応方法について書かれています。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10