首先说一下:大家应该都知道现在面试官太装逼了。我认识一位从360出来的人说:一个alloc你都要让我转成rutime.再成c函数,然后栈空间,叶子函数再去问汇编,太屎了。
前阵子面试的时候也是如此,后来再问到一些苹果官方提供的一些控件时却居然一点都不知道。
比如有一个面试官问:一个业务上要求左右滑动时切换页面,怎么做?
我的回答是:左右滑动的模块有几个就写几个基于UIViewController的类,然后这些模块由一个UIPageViewController去控制。
我说了各种各样的好处之后,面试官还不以为意,说我用一个UIScrollView去控制不行吗?设置他的frame就行了。
我曾经在这篇文章说过时至今日使用frame的缺点太突出了,我个人不建议。另一方面,如此多的代码写在一个VC当中,那么业务代码耦合的就太厉害了。而且我也在这篇文章里说过苹果在UIKit里出来一个Container的概念。
之后面试官又问:如果我要是在之后的需求当中再加上上下滑动呢?类似抖音那种。
我的回答便是:使用UIPageViewController更容易实现。效果如下:
鉴于Xcode自带的"Debug view Hierarchy"不太好用,大家凑合着看这个效果。
抖音的效果是:视频列表页可以上下滑动以切换视频源,同时视频列表往右滑动则到搜索页,往左侧滑动则到up主的用户详情页。
接下来我就说说我的思路(以Swift语言来实现)。
第一步:创建一个新工程,默认rootVC是工程中的ViewController
第二步:基于UIViewController分别创建三个VC,为SearchViewController(搜索页),VideosViewController(视频列表页)和UserInfoViewController(up主的用户信息页)。如下图:
第三步:在ViewController里创建UIPageViewController,并且实现切换三个模块。代码如下:
override func viewDidLoad() {
super.viewDidLoad()
// 创建搜索页,视频列表页和用户详情页
let searchVC : SearchViewController = SearchViewController()
let videosVC : VideosViewController = VideosViewController()
let userInfoVC : UserInfoViewController = UserInfoViewController()
self.viewControllers = [searchVC, videosVC, userInfoVC]
// 创建UIPageViewController
let pageVC : UIPageViewController = UIPageViewController.init(transitionStyle: UIPageViewController.TransitionStyle.scroll, navigationOrientation: UIPageViewController.NavigationOrientation.horizontal, options: nil)
pageVC.setViewControllers([videosVC], direction: UIPageViewController.NavigationDirection.forward, animated: false, completion: nil)
pageVC.dataSource = self
pageVC.delegate = self
// 将pageVC添加到当前VC
self.addChild(pageVC)
self.view.addSubview(pageVC.view)
pageVC.view.frame = self.view.bounds
pageVC.didMove(toParent: self)
}
// UIPageViewController必须的两个代理方法,这两个代理方法控制三个页面的先后顺序
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
var index : Int = self.viewControllers.index(of: viewController) ?? NSNotFound
if (index == 0) || (index == NSNotFound) {
return nil
}
index -= 1
return self.viewControllers[index]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
var index : Int = self.viewControllers.index(of: viewController) ?? NSNotFound
if (index == 0) || (index == NSNotFound) {
return nil
}
index += 1
if index >= self.viewControllers.count {
return nil
}
return self.viewControllers[index]
}
经过以上三步就简单的实现了三个页面的左右切换。那么视频列表的上下切换也是基于UIPageViewController的,步骤如下:
第四步:基于UIViewController创建一个VideoViewController,这个类用来播放视频
第五步:在VideosViewController(视频列表页)里创建UIPageViewController,实现上下滑动,而且是无限滑动。跟第三步类似,但是参数设置不一样。代码如下:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.blue
// 当前类的功能描述
let desLabel : UILabel = UILabel(frame: self.view.bounds)
desLabel.numberOfLines = 0
desLabel.textColor = UIColor.white
desLabel.textAlignment = NSTextAlignment.center
desLabel.text = "抖音视频列表页\n往右滑到搜索页,往左滑到用户详情页\n上下滑切换视频"
self.view.addSubview(desLabel)
// 创建 UIPageViewController
let pageVC : UIPageViewController = UIPageViewController.init(transitionStyle: UIPageViewController.TransitionStyle.scroll, navigationOrientation: UIPageViewController.NavigationOrientation.vertical, options: nil)
let videoVC : VideoViewController = VideoViewController()
videoVC.videoIndex = self.currentIndex
pageVC.setViewControllers([videoVC], direction: UIPageViewController.NavigationDirection.forward, animated: false, completion: nil)
pageVC.dataSource = self
pageVC.delegate = self
// 将pageVC添加到当前VC
self.addChild(pageVC)
self.view.addSubview(pageVC.view)
pageVC.view.frame = self.view.bounds
pageVC.didMove(toParent: self)
}
// MARK: - UIPageViewControllerDataSource
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if self.currentIndex == 1 {
return nil;
}
let videoVC : VideoViewController = VideoViewController()
videoVC.videoIndex = self.currentIndex - 1
videoVC.view.backgroundColor = UIColor.white
return videoVC;
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let videoVC : VideoViewController = VideoViewController()
videoVC.videoIndex = self.currentIndex + 1
videoVC.view.backgroundColor = UIColor.white
return videoVC;
}
// MARK: - UIPageViewControllerDelegate
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
// 简单的动画效果
let videoController : VideoViewController = pageViewController.viewControllers?[0] as! VideoViewController
self.currentIndex = videoController.videoIndex!
UIView.animate(withDuration: 2.0) {
videoController.view.backgroundColor = UIColor.clear
}
}
效果图如下:
此工程我已上传到Github,你的star是我的动力。
最后打个广告,个人第三方库:
UDUserDefaultsModel:NSUserDefaults的改进方案
YIIFMDB:直接操作Model进行增删改查,数学运算等,且sql语句易于管理