UITableViewのようなレイアウトを作る際に、UIScrollViewとUIStackViewを使って作る場合もあるかと思います。
UITableViewは選択されたセルをハイライトすることができますが、UIScrollViewとUIStackViewの場合はそのままではハイライトができません。
今回はセルのハイライトを再現する方法を紹介します。
リポジトリはこちら。 StackViewCellHighlight
全体の構成
全体のStoryboardは画像のようになっています。
UIScrollView
の中にUIStackView
を配置して、それぞれのCellに該当するViewを配置しています。
それぞれのCellの中には、カスタムViewのSelectableCellView
を配置しています。このSelectableCellView
が選択時のハイライト処理を実装しています。また、UIScrollView
はUIButton
のイベントをキャンセルできるUIButtonCancelableScrollView
というカスタムクラスにしています。このスクロールビューを使うことで、セルの選択時にスクロールをした場合にスムーズにスクロールすることができます。
SelectableCellViewとSelectableButton
SelectableCellView
は内部にSelectableButton
を配置しています。
SelectableButton
にはsetSelected(_ selected: Bool, animated: Bool)
関数を定義していて、セルの選択状態が変更された時に呼び出します。isSelected
の状態管理と背景色の処理をしています。isHighlight
もオーバーライドしていて、isSelected
と合わせて背景色のハンドリングをしています。
SelectableButton
class SelectableButton: UIButton {
override var isHighlighted: Bool {
get {
return super.isHighlighted
}
set {
backgroundColor = (isSelected || newValue) ? UIColor.opaqueSeparator : UIColor.white
super.isHighlighted = newValue
}
}
func setSelected(_ selected: Bool, animated: Bool) {
func update() {
isSelected = selected
backgroundColor = selected ? UIColor.opaqueSeparator : UIColor.white
}
if animated {
UIView.animate(withDuration: 0.35, animations: update)
} else {
update()
}
}
}
SelectableCellView
では、SelectableButton
のtouchDown
, touchCancel
, touchUpInside
にハンドラを設定しています。それぞれのイベントで選択状態をセットします。
class SelectableCellView: UIView {
private lazy var button: SelectableButton = {
let button = SelectableButton()
return button
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
button.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0).isActive = true
button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0).isActive = true
button.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0).isActive = true
button.addTarget(self, action: #selector(touchDown(button:)), for: .touchDown)
button.addTarget(self, action: #selector(cancel(button:)), for: .touchCancel)
button.addTarget(self, action: #selector(handleTap(button:)), for: .touchUpInside)
}
var didTap: (() -> Void)?
@objc private func handleTap(button: SelectableButton) {
setSelected(true, animated: false)
didTap?()
}
@objc private func touchDown(button: SelectableButton) {
setSelected(true, animated: false)
}
@objc private func cancel(button: SelectableButton) {
setSelected(false, animated: false)
}
func setSelected(_ selected: Bool, animated: Bool) {
button.setSelected(selected, animated: animated)
}
}
これでUIStackView
に配置したViewがタップされた時に背景がハイライトされるようになります。
NavigationControllerのスワイプバックに対応する
UITableViewController
には、セルをタップした時にセルを選択してプッシュ遷移した後、画面に戻ってきたらハイライトを消すclearsSelectionOnViewWillAppear
という設定があります。
これを実現するには、選択されたセルを保持して、ViewControllerのviewWillAppear
で適切に選択状態をハンドリングする必要があります。
class ViewController: UIViewController {
....
var selectedCell: SelectableCellView?
var clearsSelectionOnViewWillAppear: Bool = true
....
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let selectedCell = selectedCell, clearsSelectionOnViewWillAppear {
transitionCoordinator?.animate(alongsideTransition: { _ in
selectedCell.setSelected(false, animated: animated)
}, completion: { context in
if context.isCancelled {
selectedCell.setSelected(true, animated: false)
} else {
self.selectedCell = nil
}
})
}
}
}
これで、UITableView
のハイライトをUIScrollView
とUIStackView
で実現することができました。
こちらにサンプルコードを置いてあります。
エンジニアリング UIStackView UIScrollView UITableView ハイライト
関連記事
-
2024/3/24
try! Swift Tokyo 2024
try! Swift Tokyo 2024の参加メモ
Swift
-
2023/1/31
SwiftUIでTabBarを非表示にする
SwiftUI TabBar
-
2023/1/14
Bootstrap5.3で追加されたダークモードに対応してみました
Bootstrap DarkMode
-
2021/2/17
brew upgradeで Your CLT does not support macOS 11というエラーがでた
homebrew macOS Big Sur
-
2020/12/1
Apple Silicon搭載 MacBook Pro M1で Homebrewとrbenvをインストールする
先日購入したApple Silicon搭載 MacBook Pro M1にこのブログをビルドするためにHomebrewとrbenvをインストールしたのでメモ。
Apple Silicon Homebrew rbenv
-
2020/11/27
Apple Silicon搭載のMacBook Pro M1が危うく文鎮化するところだったので記録
Apple Silicon搭載のMacBook Pro 13インチを仕事用に購入したのですが、クリーンインストールしたところ文鎮化しかけたので記録しておきます。
MacBook Pro Apple Apple Silicon M1
-
2020/6/23
Platform State of the Unionまとめ
Platform State of the Unioまとめ
WWDC2020 Apple アップル iOS macOS watchOS tvOS
-
2020/6/23
WWDC2020キーノートまとめ
WWDC2020 キーノートまとめ
WWDC2020 Apple アップル iOS macOS watchOS tvOS
-
2020/5/31
GitHub Pagesで無料ブログを作成する - Part4 自分のオリジナルのテーマを作る
Jekyllでは既存のテーマを使うこともできるのですが、さらに一歩踏み込んで、自分で既存のテーマをカスタマイズしたり、テーマを作ることもできます。
GitHub Pages ブログ
-
2020/5/28
GitHub Pagesで無料ブログを作成する - Part3 Jekyllの設定をカスタマイズする
前回の記事では、Jekyllのテーマを利用する方法と記事を追加する方法を紹介しました。今回はさらにJekyllをカスタマイズしていきますが、確認を簡単にするためにまずJekyllをローカル環境で実行する方法を紹介します。
GitHub Pages ブログ