UIPageViewControllerにUIButtonを置くと横スクロールできない問題

# 環境
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を使用すれば横スクロールもいい感じ🌟

```swift
// タップイベントを処理したい場合は以下の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
                })
            }
        }
    }
}
```