当前位置: > > > Swift - 使用导航条和导航条控制器来进行页面切换

Swift - 使用导航条和导航条控制器来进行页面切换

通过使用导航条(UINavigationBar)与导航条控制器(UINavigationController)可以方便的在主页面和多层子页面之间切换。下面通过一个简单“组件效果演示”的小例子来说明如何通过代码来进行页面的切换。

功能如下:
1,在AppDelagete.swift入口文件中把首页ViewController做了导航控件的封装
2,首页是一个表格列出几个Swift控件的名称
3,点击表格项即切换到对应组件展示页面,顶部的导航条标题变为该控件的名称,同时导航条左侧还有返回按钮
4,在展示页中,给导航条右侧添加了“效果/代码”切换的按钮,点击分别展示组件的效果和代码

效果图如下:
     

代码如下:
--- 入口文件 AppDelegate.swift ---
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        
        // 把起始ViewController作为导航控件封装,我们在ViewController里就能调用导航条进行页面切换了
        let rootViewController = ViewController()
        let rootNavigationController = UINavigationController(rootViewController: rootViewController)
        self.window!.rootViewController = rootNavigationController
        
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
    }

    func applicationDidEnterBackground(application: UIApplication) {
    }

    func applicationWillEnterForeground(application: UIApplication) {
    }

    func applicationDidBecomeActive(application: UIApplication) {
    }

    func applicationWillTerminate(application: UIApplication) {
    }
}

--- 主页面 ViewController.swift ---
import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    // 表格加载
    var tableView:UITableView?
    
    // 控件类型
    var ctrls = ["UILabel", "UIButton", "UIImageView", "UISlider", "UIWebView"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.title = "Swift控件演示"
        self.tableView = UITableView(frame:self.view.frame, style:UITableViewStyle.Plain)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell")
        self.view.addSubview(self.tableView!)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // UITableViewDataSource协议方法
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return self.ctrls.count
    }
    
    // UITableViewDataSource协议方法
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
        -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCellWithIdentifier("SwiftCell", forIndexPath:indexPath)
            as UITableViewCell
        cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        cell.textLabel?.text = self.ctrls[indexPath.row]
        
        return cell
    }
    
    // UITableViewDelegate协议方法,点击时调用
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        // 跳转到detailViewController,取消选中状态
        self.tableView!.deselectRowAtIndexPath(indexPath, animated: true)
        // 创建DetailViewController
        let detailViewController = DetailViewController()
        // 传递控件的title,在detailView里用于判断生成响应的控件
        detailViewController.title = self.ctrls[indexPath.row]
        // navigationController跳转到detailViewController
        self.navigationController!.pushViewController(detailViewController, animated:true)
    }
}

--- 子页面 DetailViewController.swift ---
import UIKit

class DetailViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //设置背景色
        self.view.backgroundColor = UIColor.whiteColor()
        //按title加载控件
        loadControl(self.title!)
        
        //设置代码和控件展示切换按钮,增加到导航条的右侧
        //这里采用了navigationController不能增加navigationItem
        let btn = UIBarButtonItem(title:"代码", style: .Plain, target: self,
                                  action: #selector(DetailViewController.btnCodeClicked(_:)))
        self.navigationItem.rightBarButtonItem = btn
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    //构建控件并加载到界面
    func loadControl(ctrl:String) {
        switch (ctrl) {
        case "UILabel":
            let label = UILabel(frame: self.view.bounds)
            label.backgroundColor = UIColor.clearColor()
            label.textAlignment = NSTextAlignment.Center
            label.font = UIFont.systemFontOfSize(36)
            label.text = "Hello, hangge.com"
            self.view.addSubview(label)
        case "UIButton":
            let button = UIButton(frame: CGRectMake(110,120,100,60))
            button.backgroundColor = UIColor.blueColor()
            button.setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
            button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Highlighted)
            button.setTitle("点击我", forState: .Normal)
            button.addTarget(self, action: #selector(DetailViewController.buttonClicked(_:)),
                             forControlEvents: UIControlEvents.TouchUpInside)
            self.view.addSubview(button)
        case "UIImageView":
            let image     = UIImage(named: "swift.png")
            let imageView = UIImageView(frame:
                CGRectMake((CGRectGetWidth(self.view.bounds) - image!.size.width) / 2.0, 120.0,
                    image!.size.width, image!.size.height))
            imageView.image = image!
            self.view.addSubview(imageView)
        case "UISlider":
            let slider = UISlider(frame:CGRectMake(60.0, 120.0, 200.0, 30.0))
            self.view.addSubview(slider)
        case "UIWebView":
            let webView = UIWebView(frame:self.view.bounds)
            let url = NSURL(string: "http://www.hangge.com")
            let request = NSURLRequest(URL: url!)
            webView.loadRequest(request)
            self.view.addSubview(webView)
            
        default:
            print("control name: \(ctrl)")
        }
    }
    
    //显示控件的代码
    func loadCode(ctrl:String) {
        var str:String
        switch (ctrl) {
        case "UILabel":
            str = "let label = UILabel(frame: self.view.bounds)\n"
            str += "label.backgroundColor = UIColor.clearColor()\n"
            str += "label.textAlignment = NSTextAlignment.Center\n"
            str += "label.font = UIFont.systemFontOfSize(36)\n"
            str += "label.text = \"Hello, Ucai\"\n"
            str += "self.view.addSubview(label)"
        case "UIButton":
            str = "UIButton"
        case "UISlider":
            str = "let slider = UISlider(frame:CGRectMake(60.0, 120.0, 200.0, 30.0))\n"
            str += "self.view.addSubview(slider)"
        default:
            str = "other ctrl"
        }
        
        //在导航条下方位置显示源代码
        let txt = UITextView(
            frame: CGRectMake(0, 60, self.view.bounds.size.width,
                self.view.bounds.size.height - 60))
        txt.text = str
        self.view.addSubview(txt)
    }
    //清空所有子视图
    func clearViews() {
        for v in self.view.subviews as [UIView] {
            v.removeFromSuperview()
        }
    }
    
    func buttonClicked(sender:AnyObject) {
        print("you clicked button")
    }
    
    //显示控件的代码
    func btnCodeClicked(sender:AnyObject) {
        print("title: \(self.title)")
        clearViews()
        if self.navigationItem.rightBarButtonItem!.title == "代码" {
            loadCode(self.title!)
            self.navigationItem.rightBarButtonItem!.title = "效果"
        }
        else {
            self.navigationItem.rightBarButtonItem!.title = "代码"
            loadControl(self.title!)
        }
    }
    /*
     func btnBackClicked(sender:AnyObject) {
     self.navigationController.navigationBar.popNavigationItemAnimated(true)
     }
     */
}
源码下载: hangge_586.zip

如果使用StoryBoard实现更加简单
AppDelegate.swift都不需要修改。打开Main.storyboard。
(1)点击首页的Scene,选择Editor -> Embed In -> Navigation Controller 即可。


(2)从首页单元格拖“show”的关联Segue到详细页,或从首页View Controller拖手动关联Segue到详细页

(3)定义上面刚添加的Segue的Indentifier(比如detail)

这样,点击单元格跳转的代码有所改变,是根据刚才定义Segue的Indentifier来跳转
// UITableViewDelegate协议方法,点击时调用
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
    // 跳转到detailViewController,取消选中状态
    self.tableView!.deselectRowAtIndexPath(indexPath, animated: true)
    //更具定义的Segue Indentifier进行跳转
    self.performSegueWithIdentifier("detail", sender: self.ctrls[indexPath.row])
}
    
//在这个方法中给新页面传递参数
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "detail"{
        let controller = segue.destinationViewController as! DetailViewController
        controller.title = sender as? String
    }
}
评论6
  • 6楼
    2016-08-11 16:55
    小白

    嗯嗯,已经好了。是我自己的问题。class继承的时候。少写了UI。。神奇的是没报错。。后面排查发现了。。谢谢航哥

    站长回复

    不客气,找到原因就好。

  • 5楼
    2016-07-28 11:51
    小白

    航哥。为什么我这里测试一直发现detailViewController.的self.title一直是初始化的值,根本带不过去啊。。。

    站长回复

    我试了下是可以传过去的。我把整个工程上传了,你下载下来和你写的比较下,看看是不是那里写的有问题。

  • 4楼
    2016-01-19 17:00
    小华

    我写的第二个例子很简单,在导航首页添加一个按钮通过segue来进行跳转,没有show这个选项,有push、modal、custom,我用的是push,也是提示has no segue with identifier'second'

    站长回复

    identifier没配好。看我另一个回复,再检查下。

  • 3楼
    2016-01-19 16:50
    小华

    你好,请教你一下:使用StoryBoard实现的时候,按照你的文章思路写好了转换的功能,一直提示has no segue width identifier 'detail'是什么原因?segue的Indentifier属性我也配置过了

    站长回复

    如果配置正确是不会有问题的。你确定下segue是不是配置了identifier,不要配错了。(segue是那根连接线,不要配成视图页的identifier,见我文章刚补的图)

  • 2楼
    2015-12-10 20:23
    kuso

    抱歉,我的表述有问题;
    实际情况是:webView的导航栏上只有一个返回按钮;当点击网页里的一个连接,此webView就跳到了网页的2级页面,此时在导航栏上 增加一个按钮,作用是直接退出webView,而不是返回到上一页面

    站长回复

    哦,我知道了。那可以通过leftBarButtonItems和rightBarButtonItems设置导航栏左侧和右侧的按钮,而且不管左侧还是右侧都可以放置多个按钮的。你可以看我这篇文章(http://www.hangge.com/blog/cache/detail_964.html)

  • 1楼
    2015-12-10 10:15
    kuso

    请教个问题:webView的二级页面的导航栏上添加按钮,怎么添加啊???
    就是在webView中点击了一个连接,进入页面后,在导航栏添加按钮,而在webView根视图的导航栏上是没有这个按钮的。

    站长回复

    你指的是我样例里二级页面右上角的“代码”“效果”那个按钮吗?那个是在二级页面(DetailViewController.swift)里添加的。具体看代码高亮的部分。