iOSのタブページャーOSSはXLPagerTabStripというライブラリが有名ですが、カスタマイズが効きにくくメンテナンスが最近されていていないので、Parchmentというライブラリを使ってみました。
ただ、普通にやるとSelf-Sizingに対応していないので、いくつか工夫をして解決しました。
案件で使っているコードを雰囲気コードとして抽象化して取り出したので、基本的にはアイデアの参考になるコードとして見て貰えると嬉しいですが、動かなかったら教えて下さい。
要件
テキストと画像の混じったタブアイテムをセルフサイジングさせたい。
コード
Self-SizingサイズはPagingViewControllerDelegate
を設定することで実現可能です
ViewDidLoad.swift
let pagingViewController = PagingViewController<TabItem>()
pagingViewController.delegate = self
delegateのpagingItem
がHashableで帰ってくる関係上、hashValue
でアイテムを引っ掛けてサイズを返すしか方法が思いつかなかったので、そのアイデアで実現しました。
enum TabItem: Int, PagingItem, Hashable, Comparable, CaseIterable {
case first
case second
case third
case fourth
case fifth
enum TabType {
case label(String)
case icon(UIImage)
}
var tabType: TabType {
switch self {
case .first:
return .icon(UIIImage(named: "yourImage")!)
case .second:
return .label("second")
case .third:
return .label("third")
case .forth:
return .label("forth")
case .fifth:
return .label("fifth")
}
}
static func < (lhs: NewsTabItem, rhs: NewsTabItem) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
private extension TabItem {
private var sideMargin: CGFloat { return 15 }
func estimatedWidth(font: UIFont) -> CGFloat? {
switch tabType {
case .label:
let textWidth = (text as NSString).size(withAttributes: [.font: font]).width
return sideMargin + textWidth + sideMargin
case .icon:
let imageWidth: CGFloat = 15
return sideMargine + imageWidth + sideMargine
}
}
}
extension MyPagingViewController: PagingViewControllerDelegate {
func pagingViewController<T>(_ pagingViewController: PagingViewController<T>, widthForPagingItem pagingItem: T, isSelected: Bool) -> CGFloat? where T: PagingItem, T: Comparable, T: Hashable {
guard let tabItem = TabItem.allCases.first(where: { $0.hashValue == pagingItem.hashValue }) else {
return nil
}
return tabItem.estimatedWidth(font: .descriptionBold)
}
}