実現方法としては2つあります。
###1. AutoLayout を活用する方法
メニューとして利用する UITableView の位置を変更するということは、言い換えると StoryBoard で設定した TableView への制約を動的に変更する、ということになります。
おそらく、TableView の左側制約(一般的には Leading Constraint
)を 0
で配置されていると思いますが、これを必要に応じてコードで変更する、という方法です。
つまり、メニューを隠したい場合には制約を -tableView.bounds.frame
にし、表示するときには 0
にする、ということです。
コードとしてはこんな感じになります。
Swift
1class AutolayoutBasedViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
2 @IBOutlet weak var tableView: UITableView!
3 // tableView の leading 側の制約に対するアウトレット(1)
4 @IBOutlet weak var tableViewLedingConstraint: NSLayoutConstraint!
5
6 override func viewDidLoad() {
7 super.viewDidLoad()
8
9 tableView.dataSource = self
10 tableView.delegate = self
11
12 // tableView の左側の制約を変更する (0 -> -tableView.bounds.width)
13 tableViewLedingConstraint.constant = -tableView.bounds.width
14 }
15
16 @IBAction func sideMenuButton(_ sender: Any) {
17 // tableViewが画面外なら
18 if tableViewLedingConstraint.constant < 0{
19 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
20 // tableViewが左から画面内へ出てくる
21
22 // leading 側の制約を 0 にしつつ、必要に応じてレイアウトを更新する
23 self.tableViewLedingConstraint.constant = 0
24 self.view.layoutIfNeeded()
25 }, completion: nil)
26 } else{// tableViewが画面内なら
27 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
28 // tableViewが画面外へ移動
29
30 // leading 側の制約を -tableView.bounds.width にしつつ、必要に応じてレイアウトを更新する
31 self.tableViewLedingConstraint.constant = -self.tableView.bounds.width
32 self.view.layoutIfNeeded()
33 }, completion: nil)
34 }
35 }
36
37 // 以下略(DataSource の設定など)
38}
ここで、上記コードの(1)
の部分で設定した UITableView の leading の IBOutlet
を設定する必要があります。
古い記事ですが、基本的な操作は下記の記事の方法で実現できます。
この方法を使って、UITableViewの Leading の制約をコード側から操作できるようにします。
あとは、
Swift
1 tableViewLedingConstraint.constant = -tableView.bounds.width
2 view.layoutIfNeeded()
のような感じで AutoLayout を逐一変更することになります(viewDidLoad()
内部ではview.layoutIfNeeded()
は呼び出していませんが、それはその次の段階でレイアウトが更新されることが自明だからです)。
ちなみに、AutoLayout で設定した部品の frame
などは、基本的にはコードで変更しない方がいいかと思います(もちろん、変更した場合には AutoLayout のエンジンが再計算してくれると思いますが、見通しが悪くなると思います)。
また、メニューが少し移動するたびに逐一 AutoLayout エンジンが再計算を行うことになるので、パフォーマンスが悪くなりますし、万が一他の部品の制約をメニューに対して行っているとなると、画面全体の構成もかしくなってしまいます。
###2. TableView だけ全てコードベースで実現する
これは、TableView そのものをコードベースで作成し、配置し、座標管理もすべてコードで実現する、という方法です。
Swift
1class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
2 // tableView をコードベースで作る
3 lazy var tableView: UITableView = {
4 let tv = UITableView(frame: .zero)
5 tv.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
6
7 return tv
8 }()
9
10 override func viewDidLoad() {
11 super.viewDidLoad()
12
13 // view に追加する
14 view.addSubview(tableView)
15
16 tableView.dataSource = self
17 tableView.delegate = self
18 }
19
20 override func viewWillLayoutSubviews() {
21 super.viewWillLayoutSubviews()
22
23 // ここで tableView の高さや位置を決定する
24 let topMargin = view.safeAreaInsets.top
25 let bottomMargin = view.safeAreaInsets.bottom
26 let tableViewHeight = view.bounds.height - (topMargin + bottomMargin)
27 let tableViewWidth = view.bounds.width / 2
28
29 tableView.frame.origin = CGPoint(x: -tableViewWidth, y: topMargin)
30 tableView.frame.size = CGSize(width: tableViewWidth, height: tableViewHeight)
31 }
32
33
34 @IBAction func sidemenuButton(_ sender: Any) {
35 // tableViewが画面外なら
36 if tableView.frame.origin.x < 0{
37 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
38 // tableViewが左から画面内へ出てくる
39 self.tableView.frame.origin.x = 0
40
41 }, completion: nil)
42 } else{// tableViewが画面内なら
43 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
44 // tableViewが画面外へ移動
45 self.tableView.frame.origin.x = -self.view.bounds.width / 2
46 }, completion: nil)
47 }
48 }
49
50 // 以下略
51}
TableView の配置は viewDidLoad()
で行いますが、座標の設定はviewWillLayoutSubviews()
で行います。これは、画面のサイズ、つまり親Viewのサイズは viewWillLayoutSubviews()
が実行されるまで確定されないためです。
コードベースで配置するとなると実装が難しくなるように見えますが、実はそれほど難しい話ではないと思います。
座標の計算は自分で行う必要がありますが、その一方、メニューだけを独立して管理することが可能となるので、その後の変更もやりやすいのではないでしょうか。
唯一面倒となるのは、TableView に配置するセルを基本的に自分で作る(.xib を作る)必要がある、という点です。Basic なセルと同じで良いのであれば、上記の様なコードで大丈夫だと思いますが、それ以外になると xib を作る必要が出てくると思います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/23 00:57