在 UIPageViewController 中可靠地跟踪页面索引 (Swift)
Reliably track Page Index in a UIPageViewController (Swift)
问题:
我有一个母版 UIPageViewController
(MainPageVC
),其中包含三个嵌入式页面视图(A
、B
和 C
),它们都可以访问使用滑动手势并按下 MainPageVC
中自定义页面指示器*中的适当位置(*不是真正的 UIPageControl
但由三个 ToggleButton
组成 - [=20 的简单重新实现=] 成为切换按钮)。我的设置如下:
往期阅读:
, , and UIPageViewController: return the current visible view
表示最好的方法是使用 didFinishAnimating
调用,并手动跟踪当前页面索引,但我发现这不能处理某些边缘情况。
我一直在尝试提供一种安全的方式来跟踪当前页面索引(使用 didFinishAnimating
和 willTransitionTo
方法)但是我在处理用户处于的边缘情况时遇到了问题查看 A
,然后一直滑动到 C
(没有抬起手指),然后超过 C
,然后松开手指...在这种情况下 didFinishAnimating
没有被调用,应用程序仍然认为它在 A
中(即 A
切换按钮仍然被按下并且 pageIndex 没有被 viewControllerBefore
和 viewControllerAfter
方法)。
我的代码:
@IBOutlet weak var pagerView: UIView!
@IBOutlet weak var aButton: ToggleButton!
@IBOutlet weak var bButton: ToggleButton!
@IBOutlet weak var cButton: ToggleButton!
let viewControllerNames = ["aVC", "bVC", "cVC"]
lazy var buttonsArray = {
[aButton, bButton, cButton]
}()
var previousPage = "aVC"
var pageVC: UIPageViewController?
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
print("TESTING - will transition to")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder);
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass);
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
print("TESTING - did finish animating")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder)
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass)
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! - 1
if(newViewControllerIndex < 0) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! + 1
if(newViewControllerIndex > viewControllerNames.count - 1) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
我不知道如何处理这种边缘情况,问题是如果用户随后尝试在 C
中按下一些应该否则保证存在,并抛出意外的 nil
或 indexOutOfBounds
错误。
问题写得很好。特别是对于一个新手。 (已投票。)您清楚地说明了您遇到的问题,包括插图和您当前的代码。
我在另一个线程中提出的解决方案是 subclass UIPageControl
并让它在其 currentPage
属性 上实现一个 didSet。然后,您可以让页面控件将当前页面索引通知给视图控制器。 (通过给你的自定义 subclass 一个委托 属性,通过发送通知中心消息,或者任何最适合你需要的方法。)
(我对这种方法做了一个简单的测试,它奏效了。但是我没有进行详尽的测试。)
UIPageViewController 可靠地更新页面控件,但没有可靠、明显的方法来确定当前页面索引这一事实似乎是此 class.
设计中的疏忽
自己的解决方案
我找到了解决方法:不要使用UIPageView(Controller)
,使用CollectionView(Controller)
反而。跟踪集合视图的位置比尝试手动跟踪 [=13] 中的当前页面要容易 MUCH =].
解决方法如下:
方法
- 将
MainPagerVC
重构为 CollectionView(Controller)(或作为符合 UICollectionViewDelegate
UICollectionViewDataSource
协议的常规 VC)。
- 将每个页面(
aVC
、bVC
和 cVC
)设置为 UICollectionViewCell
个子类(MainCell
)。
- 设置每个页面以填充屏幕边界内的
MainPagerVC.collectionView
- CGSize(width: view.frame.width, height: collectionView.bounds.height)
。
- 将顶部的切换按钮(
A
、B
和 C
)重构为三个 UICollectionViewCell
子类(MenuCell
) MenuController
(本身就是一个 UICollectionViewController
.
- 由于集合视图继承自
UIScrollView
,您可以实现 scrollViewDidScroll
、scrollViewDidEndScrollingAnimation
和 scrollViewWillEndDragging
方法,以及委托(使用 didSelectItemAt indexPath
)来耦合MainPagerVC
和 MenuController
集合视图。
代码
class MainPagerVC: UIViewController, UICollectionViewDelegateFlowLayout {
fileprivate let menuController = MenuVC(collectionViewLayout: UICollectionViewFlowLayout())
fileprivate let cellId = "cellId"
fileprivate let pages = ["aVC", "bVC", "cVC"]
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.showsVerticalScrollIndicator = false
cv.showsHorizontalScrollIndicator = false
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
menuController.delegate = self
setupLayout()
}
fileprivate func setupLayout() {
guard let menuView = menuController.view else { return }
view.addSubview(menuView)
view.addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
//Setup constraints (placing the menuView above the collectionView
collectionView.register(MainCell.self, forCellWithReuseIdentifier: cellId)
//Make the collection view behave like a pager view (no overscroll, paging enabled)
collectionView.isPagingEnabled = true
collectionView.bounces = false
collectionView.allowsSelection = true
menuController.collectionView.selectItem(at: [0, 0], animated: true, scrollPosition: .centeredHorizontally)
}
}
extension MainPagerVC: MenuVCDelegate {
// Delegate method implementation (scroll to the right page when the corresponding Menu "Button"(Item) is pressed
func didTapMenuItem(indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
extension MainPagerVC: UICollectionViewDelegate, UICollectionViewDataSource {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let x = scrollView.contentOffset.x
let offset = x / pages.count
menuController.menuBar.transform = CGAffineTransform(translationX: offset, y: 0)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
let item = Int(scrollView.contentOffset.x / view.frame.width)
let indexPath = IndexPath(item: item, section: 0)
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .bottom)
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let x = targetContentOffset.pointee.x
let item = Int(x / view.frame.width)
let indexPath = IndexPath(item: item, section: 0)
menuController.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MainCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: view.frame.width, height: collectionView.bounds.height)
}
}
class MainCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
// Custom UIColor extension to return a random colour (to check that everything is working)
backgroundColor = UIColor().random()
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
protocol MenuVCDelegate {
func didTapMenuItem(indexPath: IndexPath)
}
class MenuVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate let cellId = "cellId"
fileprivate let menuItems = ["A", "B", "C"]
var delegate: MenuVCDelegate?
//Sliding bar indicator (slightly different from original question - like Reddit)
let menuBar: UIView = {
let v = UIView()
v.backgroundColor = .red
return v
}()
//1px view to visually separate MenuBar region from "pager"-views
let menuSeparator: UIView = {
let v = UIView()
v.backgroundColor = .gray
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .white
collectionView.allowsSelection = true
collectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
}
//Add views and setup constraints for collection view, separator view and "selection indicator" view - the menuBar
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.didTapMenuItem(indexPath: indexPath)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return menuItems.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell
cell.label.text = menuItems[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = view.frame.width
return .init(width: width/CGFloat(menuItems.count), height: view.frame.height)
}
}
class MenuCell: UICollectionViewCell {
let label: UILabel = {
let l = UILabel()
l.text = "Menu Item"
l.textAlignment = .center
l.textColor = .gray
return l
}()
override var isSelected: Bool {
didSet {
label.textColor = isSelected ? .black : .gray
}
}
override init(frame: CGRect) {
super.init(frame: frame)
//Add label to view and setup constraints to fill Cell
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
参考资料
- A "Lets Build That App" YouTube 视频:"We Made It on /r/iosprogramming! Live coding swiping pages feature"
问题:
我有一个母版 UIPageViewController
(MainPageVC
),其中包含三个嵌入式页面视图(A
、B
和 C
),它们都可以访问使用滑动手势并按下 MainPageVC
中自定义页面指示器*中的适当位置(*不是真正的 UIPageControl
但由三个 ToggleButton
组成 - [=20 的简单重新实现=] 成为切换按钮)。我的设置如下:
往期阅读:
didFinishAnimating
调用,并手动跟踪当前页面索引,但我发现这不能处理某些边缘情况。
我一直在尝试提供一种安全的方式来跟踪当前页面索引(使用 didFinishAnimating
和 willTransitionTo
方法)但是我在处理用户处于的边缘情况时遇到了问题查看 A
,然后一直滑动到 C
(没有抬起手指),然后超过 C
,然后松开手指...在这种情况下 didFinishAnimating
没有被调用,应用程序仍然认为它在 A
中(即 A
切换按钮仍然被按下并且 pageIndex 没有被 viewControllerBefore
和 viewControllerAfter
方法)。
我的代码:
@IBOutlet weak var pagerView: UIView!
@IBOutlet weak var aButton: ToggleButton!
@IBOutlet weak var bButton: ToggleButton!
@IBOutlet weak var cButton: ToggleButton!
let viewControllerNames = ["aVC", "bVC", "cVC"]
lazy var buttonsArray = {
[aButton, bButton, cButton]
}()
var previousPage = "aVC"
var pageVC: UIPageViewController?
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
print("TESTING - will transition to")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder);
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass);
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
print("TESTING - did finish animating")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder)
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass)
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! - 1
if(newViewControllerIndex < 0) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! + 1
if(newViewControllerIndex > viewControllerNames.count - 1) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
我不知道如何处理这种边缘情况,问题是如果用户随后尝试在 C
中按下一些应该否则保证存在,并抛出意外的 nil
或 indexOutOfBounds
错误。
问题写得很好。特别是对于一个新手。 (已投票。)您清楚地说明了您遇到的问题,包括插图和您当前的代码。
我在另一个线程中提出的解决方案是 subclass UIPageControl
并让它在其 currentPage
属性 上实现一个 didSet。然后,您可以让页面控件将当前页面索引通知给视图控制器。 (通过给你的自定义 subclass 一个委托 属性,通过发送通知中心消息,或者任何最适合你需要的方法。)
(我对这种方法做了一个简单的测试,它奏效了。但是我没有进行详尽的测试。)
UIPageViewController 可靠地更新页面控件,但没有可靠、明显的方法来确定当前页面索引这一事实似乎是此 class.
设计中的疏忽自己的解决方案
我找到了解决方法:不要使用UIPageView(Controller)
,使用CollectionView(Controller)
反而。跟踪集合视图的位置比尝试手动跟踪 [=13] 中的当前页面要容易 MUCH =].
解决方法如下:
方法
- 将
MainPagerVC
重构为 CollectionView(Controller)(或作为符合UICollectionViewDelegate
UICollectionViewDataSource
协议的常规 VC)。 - 将每个页面(
aVC
、bVC
和cVC
)设置为UICollectionViewCell
个子类(MainCell
)。 - 设置每个页面以填充屏幕边界内的
MainPagerVC.collectionView
-CGSize(width: view.frame.width, height: collectionView.bounds.height)
。 - 将顶部的切换按钮(
A
、B
和C
)重构为三个UICollectionViewCell
子类(MenuCell
)MenuController
(本身就是一个UICollectionViewController
. - 由于集合视图继承自
UIScrollView
,您可以实现scrollViewDidScroll
、scrollViewDidEndScrollingAnimation
和scrollViewWillEndDragging
方法,以及委托(使用didSelectItemAt indexPath
)来耦合MainPagerVC
和MenuController
集合视图。
代码
class MainPagerVC: UIViewController, UICollectionViewDelegateFlowLayout {
fileprivate let menuController = MenuVC(collectionViewLayout: UICollectionViewFlowLayout())
fileprivate let cellId = "cellId"
fileprivate let pages = ["aVC", "bVC", "cVC"]
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.showsVerticalScrollIndicator = false
cv.showsHorizontalScrollIndicator = false
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
menuController.delegate = self
setupLayout()
}
fileprivate func setupLayout() {
guard let menuView = menuController.view else { return }
view.addSubview(menuView)
view.addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
//Setup constraints (placing the menuView above the collectionView
collectionView.register(MainCell.self, forCellWithReuseIdentifier: cellId)
//Make the collection view behave like a pager view (no overscroll, paging enabled)
collectionView.isPagingEnabled = true
collectionView.bounces = false
collectionView.allowsSelection = true
menuController.collectionView.selectItem(at: [0, 0], animated: true, scrollPosition: .centeredHorizontally)
}
}
extension MainPagerVC: MenuVCDelegate {
// Delegate method implementation (scroll to the right page when the corresponding Menu "Button"(Item) is pressed
func didTapMenuItem(indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
extension MainPagerVC: UICollectionViewDelegate, UICollectionViewDataSource {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let x = scrollView.contentOffset.x
let offset = x / pages.count
menuController.menuBar.transform = CGAffineTransform(translationX: offset, y: 0)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
let item = Int(scrollView.contentOffset.x / view.frame.width)
let indexPath = IndexPath(item: item, section: 0)
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .bottom)
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let x = targetContentOffset.pointee.x
let item = Int(x / view.frame.width)
let indexPath = IndexPath(item: item, section: 0)
menuController.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MainCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: view.frame.width, height: collectionView.bounds.height)
}
}
class MainCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
// Custom UIColor extension to return a random colour (to check that everything is working)
backgroundColor = UIColor().random()
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
protocol MenuVCDelegate {
func didTapMenuItem(indexPath: IndexPath)
}
class MenuVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate let cellId = "cellId"
fileprivate let menuItems = ["A", "B", "C"]
var delegate: MenuVCDelegate?
//Sliding bar indicator (slightly different from original question - like Reddit)
let menuBar: UIView = {
let v = UIView()
v.backgroundColor = .red
return v
}()
//1px view to visually separate MenuBar region from "pager"-views
let menuSeparator: UIView = {
let v = UIView()
v.backgroundColor = .gray
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .white
collectionView.allowsSelection = true
collectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
}
//Add views and setup constraints for collection view, separator view and "selection indicator" view - the menuBar
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.didTapMenuItem(indexPath: indexPath)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return menuItems.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell
cell.label.text = menuItems[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = view.frame.width
return .init(width: width/CGFloat(menuItems.count), height: view.frame.height)
}
}
class MenuCell: UICollectionViewCell {
let label: UILabel = {
let l = UILabel()
l.text = "Menu Item"
l.textAlignment = .center
l.textColor = .gray
return l
}()
override var isSelected: Bool {
didSet {
label.textColor = isSelected ? .black : .gray
}
}
override init(frame: CGRect) {
super.init(frame: frame)
//Add label to view and setup constraints to fill Cell
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
参考资料
- A "Lets Build That App" YouTube 视频:"We Made It on /r/iosprogramming! Live coding swiping pages feature"