Swift 一定以上スクロールしたらタブの位置を固定する(SwipeMenuViewControllerを使う)
やりたいことはこちらのページに書かれていたようなこと
https://techblog.zozo.com/entry/scroll_tab_page
https://github.com/yysskk/SwipeMenuViewController
SwipeMenuViewControllerというライブラリを使って試してみた

ViewController.swift
import UIKit
import SwipeMenuViewController
class ViewController: UIViewController, SwipeMenuViewDelegate, SwipeMenuViewDataSource, UIScrollViewDelegate, TableViewControllerProtocol {
var menus = ["メニュー1", "メニュー2", "メニュー3"]
var header: UIView!
var scrollView = UIScrollView()
var swipeMenuView: SwipeMenuView!
override func viewDidLoad() {
super.viewDidLoad()
// タブの上のView
header = UIView(frame: CGRect(x: 10, y: 20, width: view.frame.width - 10*2, height: 200))
header.backgroundColor = UIColor.init(red: 157/255, green: 204/255, blue: 224/255, alpha: 1)
scrollView.delegate = self
scrollView.addSubview(header)
// SwipeMenuView
swipeMenuView = SwipeMenuView(frame: CGRect(x: 0, y: header.frame.origin.y + header.frame.height, width: view.frame.width, height: view.frame.height))
swipeMenuView.delegate = self
swipeMenuView.dataSource = self
scrollView.addSubview(swipeMenuView)
var options: SwipeMenuViewOptions = .init()
options.tabView.style = .segmented
self.swipeMenuView.reloadData(options: options, default: nil, isOrientationChange: false)
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height + 100)
view.addSubview(scrollView)
}
// タブの数を返します
func numberOfPages(in swipeMenuView: SwipeMenuView) -> Int {
return menus.count
}
// タブのテキストを返します
func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String {
return menus[index]
}
// タブが選択されたときに表示するViewControllerを返します
func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController {
let viewController = TableViewController()
viewController.delegate = self
addChild(viewController)
return viewController
}
// テーブルをスクロールしたら呼ばれる
// テーブルビューのスクロール位置からヘッダーのスクロール位置をセットする
func receiveTableViewControllerScroll(_ offset: CGFloat) {
let new = header.frame.origin.y + offset - 22
let max = header.frame.origin.y + header.frame.size.height - 22
let now = scrollView.contentOffset.y
if new < max {
scrollView.setContentOffset(CGPoint(x: 0, y: new), animated: false)
} else if now < new {
scrollView.setContentOffset(CGPoint(x: 0, y: max), animated: false)
}
}
}TableViewController.swift
import UIKit
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
weak var delegate: TableViewControllerProtocol?
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: CGRect(x:0, y:0, width:view.frame.width, height:view.frame.height))
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.delegate = self
tableView.dataSource = self
tableView.showsVerticalScrollIndicator = false
tableView.bounces = false
self.view.addSubview(tableView)
}
private func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
cell.textLabel?.text = String(format: "行番号:%d", indexPath.row)
return cell
}
// スクロール位置を親のViewControllerに通知
func scrollViewDidScroll(_ scrollView: UIScrollView) {
delegate?.receiveTableViewControllerScroll(tableView.contentOffset.y)
}
}
protocol TableViewControllerProtocol: class {
func receiveTableViewControllerScroll(_ offset: CGFloat) -> Void
}課題
・行数が少ない場合にバグる
・ヘッダー部分をスクロールした場合に子のスクロール位置も調整するべき
だれか修正してソース共有してください。以上です