環境
Swift 4
Xcode 10
問題
UIPageViewControllerにUIButtonを置くと横スクロールできない
UIPageViewControllerの横スクロールのイベントがUIButtonに取られちゃって、ボタンの上からスクロールを始めると横スクロールできない。結果、画面に大きめのボタンがあるとすごくスクロールしにくい。
func touchesShouldCancel(in view: UIView) -> Bool
でtrueを返せばいいのでは?
func touchesShouldCancel(in view: UIView) -> Bool
でtrueを返すと、UIScrollView上にUIButtonをおいてもいい感じになる。(Tapできるし、スクロールしたらTapがキャンセルされてそのままスクロールできる)
touchesShouldCancel(in:) - UIScrollView | Apple Developer Documentation
https://developer.apple.com/documentation/uikit/uiscrollview/1619387-touchesshouldcancel
UIPageViewControllerではできない😂
func touchesShouldCancel(in view: UIView) -> Bool
でtrueを返すためにはoverrideしないといけないのだが、UIPageViewControllerの中にあるUIScrollViewってどうやったらoverrideできるの😂
※UIScrollView, UITableView, UICollectionViewはoverrideしたサブクラスを作成することでいい感じにできます👍
解決法
UIButtonをUIPageViewController上で使わない!
func touchesShouldCancel(in view: UIView) -> Bool
のDocumentに書いてあるんですが、UIControlを継承しているクラスだとfalseを返して、それ以外だったらtrueを返すらしいんですよ。
なので、UIButtonじゃなくてUIViewにTapイベントとか設定すればいい感じに動く👍
まとめ
Document読もう!
touchesShouldCancel(in:) - UIScrollView | Apple Developer Documentation
https://developer.apple.com/documentation/uikit/uiscrollview/1619387-touchesshouldcancel
おまけ
以前の記事でUIButtonのサブクラスで、Highlight時に白っぽくなるボタンを作ったのですが、それのUIView版のコードを張っておきます。以下のUIViewを使用すれば横スクロールもいい感じ🌟
// タップイベントを処理したい場合は以下のdelegateを使用してください
protocol HighlightViewDelegate: class {
func didTapHighlightView()
}
/// 以下参照
/// https://developer.apple.com/documentation/uikit/uiscrollview/1619387-touchesshouldcancel
class HighlightView: UIView {
// MARK: Parameter
weak var delegate: HighlightViewDelegate?
private let highlightedAlpha: CGFloat = 0.4
private lazy var normalBgColor: UIColor = .clear
private lazy var highlightedBgColor: UIColor = {
return UIColor.white.withAlphaComponent(CGFloat(1) - self.highlightedAlpha)
}()
private var isShowAnimation: Bool = false
private var isHideAnimation: Bool = false
private var isHighlighted: Bool = false {
willSet {
self.doAnimation(isShow: newValue) {
self.backgroundColor = newValue ? self.highlightedBgColor : self.normalBgColor
}
}
}
// MARK: Init
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
func commonInit() {
let tap = UITapGestureRecognizer(target: self, action: #selector(self.didTapSelf))
self.addGestureRecognizer(tap)
}
// MARK: Func
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.isHighlighted = true
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.isHighlighted = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
self.isHighlighted = false
}
@objc
private func didTapSelf() {
self.delegate?.didTapHighlightView()
}
}
extension HighlightView {
private func doAnimation(isShow: Bool, animation: @escaping () -> Void) {
if isShow {
if !self.isShowAnimation {
self.isShowAnimation = true
UIView.animate(withDuration: 0.1, animations: {
animation()
}, completion: { _ in
self.isShowAnimation = false
})
}
} else {
if !self.isHideAnimation {
self.isHideAnimation = true
UIView.animate(withDuration: 0.3, animations: {
animation()
}, completion: { _ in
self.isHideAnimation = false
})
}
}
}
}