iOS 界面开发最重要的是ViewController和View,ViewController是View的控制器,也就是一般的页面,用来管理页面的生命周期(它相当于安卓里的Activity,两者很像,又有一些差异)。
ViewController的特点是它有好几种。一种最基本的UIViewController,和另外三种容器:UINavigationController、UITabBarController、UIPageViewController。
所谓容器,就是它们本身不能单独用来显示,必须在里面放一个或几个UIViewController。
不同容器有不同的页面管理方式和展示效果:
容器还可以嵌套,比如把UITabBarController放进UINavigationController里面,这样在tab页面里,可以用启动导航栏样式的二级子页面。
这是最简单的页面,没有导航栏。
使用present方法展示,展示时从底部弹起,可以用下滑手势关闭,也可以多次启动叠加多个页面。

class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
title = "\(self.hash)"
var label = UIButton(frame: CGRect(x: 10, y: 100, width: 300, height: 100))
label.setTitle("present ViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentVC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 200, width: 300, height: 100))
label.setTitle("present NavigationController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentNC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 300, width: 300, height: 100))
label.setTitle("push ViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(pushVC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 400, width: 300, height: 100))
label.setTitle("present TabbarController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentTC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 500, width: 300, height: 100))
label.setTitle("present PageViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentPC), for: .touchUpInside)
}
@objc func presentVC() {
let vc = ViewController()
vc.view.backgroundColor = .darkGray
present(vc, animated: true)
}
@objc func presentNC() {
let vc = ViewController()
vc.view.backgroundColor = .gray
let nc = UINavigationController(rootViewController: vc)
present(nc, animated: true)
}
@objc func presentTC() {
let tc = MyTabbarController()
tc.view.backgroundColor = .blue
let nc = UINavigationController(rootViewController: tc)
present(nc, animated: true)
}
@objc func presentPC() {
let pc = MyPageViewController()
pc.view.backgroundColor = .red
let nc = UINavigationController(rootViewController: pc)
present(nc, animated: true)
}
@objc func pushVC() {
let vc = ViewController()
vc.view.backgroundColor = .purple
if let nc = navigationController {
nc.pushViewController(vc, animated: true)
} else {
print("navigationController nil!")
}
}
}
这是最常用的页面导航方式,顶部展示导航栏,有标题、返回按钮。
使用pushViewController方法展示,展示时从右往左出现,可以用右滑手势关闭,也可以多次启动叠加多个页面。
注意:UINavigationController用来管理一组UIViewController,这些UIViewController共用一个导航栏。一般来说,UINavigationController能很好地控制导航栏上面的元素显示和转场效果。如果需要定制导航栏元素,尽量修改UIViewController的导航栏,不要直接修改UINavigationController的导航栏。

这个一般用来做主页面的展示,下面配置多个tab,用来切换页面。

class MyTabbarController: UITabBarController {
init() {
super.init(nibName: nil, bundle: nil)
self.tabBar.backgroundColor = .gray
let vc1 = ViewController()
vc1.tabBarItem.image = UIImage(named: "diamond")
vc1.tabBarItem.title = "tab1"
vc1.view.backgroundColor = .red
let vc2 = ViewController()
vc2.tabBarItem.image = UIImage(named: "diamond")
vc2.tabBarItem.title = "tab2"
vc2.view.backgroundColor = .blue
let vc3 = ViewController()
vc3.tabBarItem.image = UIImage(named: "diamond")
vc3.tabBarItem.title = "tab3"
vc3.view.backgroundColor = .purple
self.viewControllers = [
vc1,
vc2,
vc3,
]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
这个用来做翻页的页面,比如电子书或者广告banner。可以配置左右或上下翻译,翻页效果可以配置滚动或者模拟翻书。
用viewControllerBefore和viewControllerAfter回调方法控制页面切换。viewControllerBefore方法是让我们给它提供当前页面的前一个页面,viewControllerAfter方法是让我们给它提供当前页面的后一个页面。
注意:UIPageViewController有预加载机制,它会提前加载当前页面的前后页面。但是它没有实现页面缓存机制,需要我们在外部做缓存。如果页面非常多,但又是同一个类的实例,那么一般创建三个实例就够了,然后在viewControllerBefore和viewControllerAfter方法里循环使用这三个。


class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource {
lazy var vcs = [
ViewController(),
ViewController(),
ViewController(),
ViewController(),
ViewController(),
]
init() {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal)
self.dataSource = self
let vc1 = ViewController()
vc1.view.backgroundColor = .red
let vc2 = ViewController()
vc2.view.backgroundColor = .blue
let vc3 = ViewController()
vc3.view.backgroundColor = .purple
let vc4 = ViewController()
vc4.view.backgroundColor = .gray
vcs = [vc1,vc2,vc3,vc4
]
self.setViewControllers([vcs[0]], direction: .forward, animated: false)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let i = (vcs.firstIndex(of: viewController as! ViewController) ?? 0) - 1
if i < 0 {
return nil
}
return vcs[i]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let i = (vcs.firstIndex(of: viewController as! ViewController) ?? 0) + 1
if i >= vcs.count {
return nil
}
return vcs[i]
}
}
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新rubygems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
在我的Character模型中,我添加了:字符.rbbefore_savedoself.profile_picture_url=asset_path('icon.png')end但是,对于数据库中已存在的所有角色,它们的profile_picture_url为nil。因此,我想进入控制台并遍历所有这些并进行设置。在我试过的控制台中:Character.find_eachdo|c|c.profile_picture_url=asset_path('icon.png')end但这给出了错误:NoMethodError:undefinedmethod`asset_path'formain:O