UITableViewの上にUIButtonをスクロールせず固定して表示する方法!
こんにちわ!
Railsエンジニアの @hbd225 です。
最近は仕事のあとswift書いてたりですので、swiftネタです!
初めてAirbnbのアプリを見たときは細かいところまでUIが作り込まれててすごいなーと感動したものですが、Airbnbの検索アイコンやメルカリの出品ボタンなど、UITableViewの上にボタンがスクロールされず固定されて表示されてる感じの素敵なUIをよく見かけますので、実装方法について調べてみました!
先に結論
UITableView のセル上に直接ボタンを追加しても、スクロールすると画面外に消えてしまいますので、ContainerView を配置して Embed segue で UITableView を繋いで実装することで、ContainerView の上に固定されてスクロールしない UIButton を追加することができるようになります。
画面のスクロールに合わせて UIButton の表示/非表示を切り替える際には、プロトコルを定義して UITableView のスクロールイベントを ContainerView 側の ViewController に通知する実装にしてみてます!
プロジェクト作成
今回は SingleViewApplication を使ってプロジェクト作成しますー。
Storyboard から ContainerView を ViewController に追加
ContainerView は他の ViewController からも再利用が可能なViewを作るときに重宝するViewで、 こちらの記事 が分かりやすいです!
UITableView を実装
ContainerView を追加すると自動的に ViewController も追加されて繋がれていますが、そちらは一旦削除して、UITableView を好きなように実装し、Embed segue で繋ぎます。
UIButton を 追加
Storyboard から ContainerView の上に UIButton を追加し、Constraints を設定してボタンの位置など調整します。
実機で見てみる
UIButton がスクロールしても固定されて表示されました!
スクロールの際に UIButton の表示/非表示を切り替える
スクロールダウン時はユーザーはコンテンツを見たいと思いますので UIButton を非表示にし、
スクロールアップの時に UIButton を表示するようにしましょう!
まずは UITableView 側の ViewController にプロトコルを定義して delegate 変数を用意します。
// スクロールの発生を検知してUIButtonの表示を切り替えるためのプロトコル
protocol ArticleViewControllerDelegate: class {
func viewDidscrolledUp()
func viewDidscrolledDown()
}
class ArticleViewController: UIViewController {
weak var delegate: ArticleViewControllerDelegate?
// スクロールの開始点
var scrollBeginingPoint: CGPoint!
// ドラッグしてスクロールが発生する直前に呼び出される
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
scrollBeginingPoint = scrollView.contentOffset
}
// スクロールが発生している間常に呼び出される
func scrollViewDidScroll(scrollView: UIScrollView) {
let currentPoint = scrollView.contentOffset
if scrollBeginingPoint.y < currentPoint.y {
print("scroll to bottom")
delegate?.viewDidscrolledDown()
} else {
print("scroll to top")
delegate?.viewDidscrolledUp()
}
}
// 以下にUITableViewのための実装などなど...
}
extension ArticleViewController: UITableViewDelegate {
}
extension ArticleViewController: UITableViewDataSource {
}
続いて ContainerView 側の ViewController にプロトコルを実装します。
class ViewController: UIViewController {
// UIButton の表示/非表示を管理
private var isButtonDisplayed: Bool = true
@IBOutlet weak var addPictureButton: UIButton!
// 先ほど実装した UITableView 側の ViewController の delegate に self を設定
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ArticleViewControllerSegue" {
let vc = segue.destinationViewController as! ArticleViewController
vc.delegate = self
}
}
// 以下にviewDidLoad などの処理...
}
// スクロール発生時に通知されるプロトコルを実装
extension ViewController: ArticleViewControllerDelegate {
// スクロールアップ時に UIButton を表示する
func viewDidscrolledUp() {
if !isButtonDisplayed {
addPictureButton.hidden = false
isButtonDisplayed = true
}
}
// スクロールダウン時に UIButton を非表示にする
func viewDidscrolledDown() {
if isButtonDisplayed {
addPictureButton.hidden = true
isButtonDisplayed = false
}
}
}
もう一度実機で見てみる
スクロールの発生によって UIButton の表示/非表示が切り替わりました!
Spring を使ってきれいにアニメーションをつけてあげるとなお良しですね!
エンジニア募集中!
ビジネスバンクグループではエンジニアを募集中しています。
弊社が採用しているテクノロジや開発環境に興味を持った方は、 ここから是非エントリー を!