Help us understand the problem. What is going on with this article?

小ネタ:UITabBarControllerに「モーダル表示するボタン」を追加する(Swift)

More than 3 years have passed since last update.

tabbar.gif

iOSアプリで、「タブバーにタブバーっぽくないアイコンを置いて、それをタップしたら画面がモーダル出てくる」というのを見かけます。それをSwiftでやってみたという小ネタです。

ポイント:
- UITabBarControllerを継承したクラスを作る
- 押したらモーダル表示する、というボタンをself.tabBarにaddSubviewしておく
- UITabBarの中のボタンは、subviewsの中で、クラスが"UITabBarButton"のものなので、ボタンの表示位置はこれを使って調整する
- UITabBarButtonは非公開クラスなので、クラス名を文字列でチェックしている。

class MyTabBarController:UITabBarController{
    let button:UIButton = UIButton()

    override func viewDidLoad() {
        // タブバーに重ねるボタンを作成
        // ここではサイズとか位置は気にしない。
        let image = UIImage(named: "button")
        self.button.setBackgroundImage(image, forState: .Normal)
        self.button.addTarget(self, action: "openModal",
            forControlEvents: UIControlEvents.TouchUpInside)

        // self.view ではなくて、self.tabBar にaddSubviewする
        self.tabBar.addSubview(self.button)
     }

    // 表示される直前にここが呼ばれるので
    // ここでself.buttonの位置を調整する
    override func viewDidLayoutSubviews() {
        // タブバーのn番目にあるUIViewを取得してくる。
        // self.tabBarButtons()は、下のextensionで追加してるメソッド
//        let v = self.tabBarButtons().first // 左端タブのUIViewn
        let v = self.tabBarButtons().last  // 右端タブのUIView
//        let v = self.tabBarButtons()[1]   // 2番目のタブの位置
        if let v = v {
            button.frame = v.frame
        }
    }

    // ボタンおされたらモーダル表示
    func openModal(){
        // モーダル表示するViewControllerは、Storyboardから拾ってくる。
        let vc = self.storyboard?.instantiateViewControllerWithIdentifier("ModalViewController") as? UIViewController
        if let vc = vc {
            self.presentViewController(vc, animated: true, completion: nil)
        }
    }
}

// UITabBarControllerを拡張
extension UITabBarController{
    // タブバーを構成している、内部クラスの「UITabBarButton」を探してきて、UIViewの配列として返す。
    // OSのバージョンアップで使えなくなる可能性がある。
    func tabBarButtons()->[UIView]{
    // reduce関数は知らなければ損。
        return self.tabBar.subviews.reduce([], combine: { (ret:[UIView], item:AnyObject) -> [UIView] in
            if let v = item as? UIView  {
                // ここ、クラス判定を「文字列」でやってるから、裏技ちっく。
                if v.isKindOfClass(NSClassFromString("UITabBarButton")) {
                    return ret + [v]
                }
            }
            return ret
        })
    }
}

ちゃんと作るなら、
- 画像をちゃんと作らないと、タブバーから浮いて見えたり、背景文字が見えてしまったりする(特にサイズ違いの実機で要テスト)
- ボタンを重ねたTabBarItemは死にアイテムになるので、意味のある画面は配置しないようにする
- OSのバージョンアップ時にはテスト厚く
等など、気をつけましょう。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away