こんにちは。きんくまです。
Zippy電卓で、ユーザーの方からレビューで投稿がありました。
電卓側と、履歴表示が左右逆の方がもっと使い易い気がします。
iPad版は電卓部分と履歴部分が左右レイアウトになっています。
なので、レイアウトを左右どちらにも変更できる(入れ替える)機能を追加して、アップデートを申請しました。
うまくいけば来週のどこかでアップデートができると思います。
今回はどうやって実装したかを書いてみようかと思います。
デモの完成版
Zippy電卓はiPhone版とiPad版でAutoLayoutをいろいろ変更したりしているので、これの説明するためのデモプロジェクトを作成しました。
完成版はこうなります。
下のボタンを押すと、左右のレイアウトがきりかわります。
AutoLayoutでポイントとなるのは、左右と中央部分のNSConstraintです。
ここに左右のレイアウトが逆になった時のNSConstraintも追加しておきます。ただし、Installedにしません。
だから、6つのConstraintがあります。3つはInstalledで、残りはInstalledのチェックがはずれている状態。
一番下のチェックがはずれていることに注目です。
リスト上では、Installedされていないものはこんな感じに薄く表示されます。
ここまでInsterface Builderで仕込みができたあと、あとはコードで変更する仕組みを作ればOKです。
import UIKit class ViewController: UIViewController { //for Layout 1 @IBOutlet weak var yellowLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var yellowTrailingBlueLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var blueTrailingConstraint: NSLayoutConstraint! //for Layout 2 @IBOutlet weak var blueLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var blueTrailingYellowLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var yellowTrailingConstraint: NSLayoutConstraint! var isLayout1:Bool = true override func viewDidLoad() { super.viewDidLoad() } override func viewWillLayoutSubviews() { updateViewConstraints() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func layoutSegmentValueChanged(sender: AnyObject) { let segment:UISegmentedControl = sender as! UISegmentedControl isLayout1 = segment.selectedSegmentIndex == 0 updateViewConstraints() } override func updateViewConstraints() { if isLayout1 { //At first, deactivate layout2 blueLeadingConstraint.active = false blueTrailingYellowLeadingConstraint.active = false yellowTrailingConstraint.active = false //Second, activate layout1 yellowLeadingConstraint.active = true yellowTrailingBlueLeadingConstraint.active = true blueTrailingConstraint.active = true /** * You can also deactivate and activate constraints, * using NSLayoutConstraint's class methods. */ // NSLayoutConstraint.deactivateConstraints([ // blueLeadingConstraint, // blueTrailingYellowLeadingConstraint, // yellowTrailingConstraint // ]) // NSLayoutConstraint.activateConstraints([xxxx, xxxx, xxx]) }else{ //At first, deactivate layout1 yellowLeadingConstraint.active = false yellowTrailingBlueLeadingConstraint.active = false blueTrailingConstraint.active = false //Second, activate layout2 blueLeadingConstraint.active = true blueTrailingYellowLeadingConstraint.active = true yellowTrailingConstraint.active = true } super.updateViewConstraints() } }
Constraintのvalueを変更する場合は問題ないんですが、今回のように大きくレイアウトを変更する場合は updateViewConstraints でやった方がいいみたいです。
Interface Builder上でのInstalledのチェックのON/OFFは、コードではactiveをtrue/falseにすればいいみたい。
で、いろいろと試してみたところ、先にかかっているConstraintをオフにしたあとに、新しいレイアウトをオンにしないと、エラーを吐いてしまいました。順番が大事。
あと、viewWillAppearでupdateViewConstraintsを呼び出したときは、アプリ起動時だけAutoLayout切り替えがうまくいきませんでした。起動したあとに、画面を回転させたり、別画面に移ったりしたらきちんと動作するんですが、なぜだかわかりません、、。
で、viewWillLayoutSubviewsで呼び出すと、アプリ起動時もうまくいきました。
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ