form1.cn
Make a little progress every day

Part 6:iOS视图控制器与导航模式

01th of March 2017 Swift Swift 2447

本章学习到了:

1,代码弹出模态框,点击空白处收回键盘的事件

2,关闭模态窗口

3,pageControl+scroll的使用

4,UIPageViewController翻页效果,本页事件翻页快有bug

5,三级表视图,加载数据,跳转,一级传值数据到二级的操作


以下为学习时的Demo代码


代码弹出模态框,点击空白处收回键盘的事件

import UIKit

//代码弹出模态框,点击空白处收回键盘的事件
class ViewController: UIViewController {

    @IBOutlet weak var username: UITextField!
    @IBOutlet weak var password: UITextField!
    
    //代码实现弹出模态框
    @IBAction func onReg(_ sender: UIButton) {
        //读取在故事板中定义 的 ID : NavViewController
        let NavViewController = self.storyboard?.instantiateViewController(withIdentifier: "NavViewController") as! UINavigationController
        //弹出模态框
        self.present(NavViewController, animated: true, completion: {() -> Void in
            print("弹出模态框")
        })
    }
    //NavViewController
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        
        //注册点击事件
        self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
        
    }
    
    //点击空白处关闭键盘方法
    func handleTap(sender: UITapGestureRecognizer) {
        if sender.state == .ended {
            print("收回键盘")
            self.username.resignFirstResponder()//username放弃第一响应者
            self.password.resignFirstResponder()//password放弃第一响应者
        }
        sender.cancelsTouchesInView = false
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}


关闭模态窗口

import UIKit

//关闭模态窗口
class CreateViewController: UIViewController {

    @IBAction func onCancel(_ sender: UIBarButtonItem) {
        //关闭模态
        self.dismiss(animated: true, completion: {() -> Void in
            print("关闭模态")
        })
    }
    
    @IBAction func onDone(_ sender: UIBarButtonItem) {
        //关闭模态
        self.dismiss(animated: true, completion: {() -> Void in
            print("关闭模态")
        })
    }
    
    @IBAction func onSave(_ sender: UIBarButtonItem) {
        //TODO 保存数据
        //关闭模态
        self.dismiss(animated: true, completion: {() -> Void in
            print("关闭模态")
        })
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        
        }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    

    /
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    /

}


pageControl+scroll的使用

import UIKit

//ScrollView与PageControl实现平铺导航(图片切换)
//创建一个主View加入ScrollView(设置为可分页)与PageControl
//创建三个View放入3个imageView@图片放进去,每个需要定义storyboardID

//pageControl+scroll的使用
class PageViewController: UIViewController,UIScrollViewDelegate {

    @IBOutlet weak var scroll: UIScrollView! //ScrollView输出口
    @IBOutlet weak var pageControl: UIPageControl! //PageControl输出口
    
    var page1: UIView! = nil
    var page2: UIView! = nil
    var page3: UIView! = nil

    
    override func viewDidLoad() {
        super.viewDidLoad()
        //要实现UIScrollViewDelegate需要将当前scroll指向当前控制器
        self.scroll.delegate = self
        
        //----------------初始化,将page1,2,3加为Scroll的子视图-----------------//
        //self.scroll.frame.size.height|width //当前视图的宽或高
        let scrollWidth = self.scroll.frame.size.width
        let scrollHeight = self.scroll.frame.size.height
        
        //取得主storyboard
        let mainStoryboard = self.storyboard
        //设置scrollView实际内容的大小
        self.scroll.contentSize = CGSize(width: scrollWidth  3, height: scrollHeight)
        
        //获取3个pageViewcontroller视图,,赋值给page,然后设置page的坐标与大小
        let page1Viewcontroller = mainStoryboard?.instantiateViewController(withIdentifier: "page1")
        self.page1 = page1Viewcontroller?.view
        self.page1.frame = CGRect(x: 0, y: 0, width: scrollWidth, height: scrollHeight)
        
        let page2Viewcontroller = mainStoryboard?.instantiateViewController(withIdentifier: "page2")
        self.page2 = page2Viewcontroller?.view
        self.page2.frame = CGRect(x: scrollWidth, y: 0, width: scrollWidth, height: scrollHeight)
        
        let page3Viewcontroller = mainStoryboard?.instantiateViewController(withIdentifier: "page3")
        self.page3 = page3Viewcontroller?.view
        self.page3.frame = CGRect(x: scrollWidth  2, y: 0, width: scrollWidth, height: scrollHeight)
        
        //将page放到scrollView中
        self.scroll.addSubview(page1)
        self.scroll.addSubview(page2)
        self.scroll.addSubview(page3)
    }
    
    //------------实现UIScrollViewDelegate协议方法
    //实现滚动视图的滚动事件,图标滚动时 page的小点也跟个翻页
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        //获取scroll的偏移量对像
        let offset = scrollView.contentOffset
        //offset的x除以scrollWidth得到整数,赋值给pageControl的当前页
        self.pageControl.currentPage = Int(offset.x) / Int(self.scroll.frame.size.width)
    }
    
    //PageControl动作事件,page小点变换时,图片也跟着变化
    @IBAction func changaPage(_ sender: UIPageControl) {
        //得到pageControl的当前页数
        let whicth = self.pageControl.currentPage
        //设置scroll的偏移量,这种方法比较生硬,没有动画效果
        //self.scroll.contentOffset = CGPoint(x: CGFloat(whicth)  self.scroll.frame.size.width, y: 0)
        //使用setContentOffset可设置动画效果
        self.scroll.setContentOffset(CGPoint(x: CGFloat(whicth)  self.scroll.frame.size.width, y: 0), animated: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
}


UIPageViewController翻页效果

import UIKit

//定义一个枚举
enum DirectionForward: Int{
    case Before = 1 //向前翻页
    case After = 2 //向后翻页
}

//UIPageViewController翻页效果,问题:当效果为scroll的时候,第二张会重复,第一页翻,前一页后一页方法都会调用???
class FanyeViewController: UIViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource {

    //当前页的索引
    var pageIndex = 0
    //将枚举放到变量,翻页时随时更换
    var directionForward = DirectionForward.Before //默认向后翻页
    //定义当前视图控制器成员常量 pageViewController
    var pageViewController: UIPageViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //实例化UIPageViewController
        //UIPageViewControllerTransitionStyle为动画效果@翻书效果,枚举可以直接用点 .pageCurl
        //UIPageViewControllerNavigationOrientation为设备朝向@水平的
        self.pageViewController = UIPageViewController(transitionStyle: UIPageViewControllerTransitionStyle.pageCurl, navigationOrientation: UIPageViewControllerNavigationOrientation.horizontal, options: nil)
        
        
        //指定pageViewController的delegate与dataSource的实现者为当前视图
        self.pageViewController.delegate = self
        self.pageViewController.dataSource = self
        
        //取得主storyboard
        let mainStoryboard = self.storyboard
        //获取3个pageViewcontroller视图,,赋值给page,然后设置page的坐标与大小
        let page1Viewcontroller = mainStoryboard?.instantiateViewController(withIdentifier: "page1")
        
        //设置首页显示的视图为page1ViewController @ 第一个视图
        let viewControllers: NSArray = [page1Viewcontroller as Any]
        self.pageViewController.setViewControllers((viewControllers as! [UIViewController]),direction: .forward,animated: true, completion: nil)
        //将pageViewController加入到当前视图中
        self.view.addSubview(self.pageViewController.view)
        
        
    }

    
    //-----------------实现数据源DataSource协议方法
    
    
    //设置向前一页,必须实现的方法
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        //设置前当页索引
        pageIndex = pageIndex - 1
        if pageIndex < 0 {
            pageIndex = 0
            return nil
        }
        
        //print("Before\(pageIndex)")
        
        self.directionForward = .Before
        
        //NSString将字符串和数字拼接为String
        let pageId = NSString(format:"page%i",pageIndex + 1)
        //获取当前的page*并return 返回
        let pvcontroller = self.storyboard?.instantiateViewController(withIdentifier: pageId as String)
        return pvcontroller
    }
    
    //设置向后一页,必须实现的方法
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        //设置前当页索引
        pageIndex = pageIndex + 1
        if pageIndex > 2 {
            pageIndex = 2
            return nil
        }
        
        //print("After\(pageIndex)")
        
        self.directionForward = .After
        
        //NSString将字符串和数字拼接为String
        let pageId = NSString(format:"page%i",pageIndex + 1)
        //获取当前的page*并return 返回
        let pvcontroller = self.storyboard?.instantiateViewController(withIdentifier: pageId as String)
        return pvcontroller
    }
    
    
    //-----------------实现委托Delegate协议方法
    
    //设置书脊和是否双面显示
    func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewControllerSpineLocation {
            //true为双面显示,false为单面显示
            self.pageViewController.isDoubleSided = false
            //设置书脊为min最小,在左侧
            return .min
    }
    
    //该委托方法是在翻页动作完成后触发的方法
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        //completed == true 说明翻页成功
        
        //没有翻页成功设置
        if completed == false {
            if self.directionForward == .Before {//如果向前翻页
                pageIndex += 1 //还原翻页之前
                //print("qian:\(pageIndex)")
            }else if self.directionForward == .After {//如果向后翻页
                pageIndex -= 1 //还原翻页之前
                //print("hou:\(pageIndex)")
            }
        }
    }
    
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}


三级表视图跳转传值:一级视图

import UIKit

//三级表视图,第一级 @ 其中cell连线到二级表视图时,选择selectionSegue为点击整个cell时,accessory为点击扩展图标
class TreeTableViewController: UITableViewController {
    
    var allData: NSDictionary!
    var provinces: NSArray!

    override func viewDidLoad() {
        super.viewDidLoad()

        //获取plist文件路径
        let plistPath = Bundle.main.path(forResource: "provinces_cities", ofType: "plist")
        //获取属性列表文件中的全部数据保存到allData中
        self.allData = NSDictionary(contentsOfFile: plistPath!)
        //取allData字典所有key为数组放到provinces中
        self.provinces = self.allData.allKeys as NSArray!
        //设置当前Navigation下面表视图的标题
        self.title = "省份信息"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //TableViewDataSource 协议方法实现
    //返回表视图节的个数
    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    //返回表视图每个节中的行数
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return self.provinces.count
    }

    //返回每一个 自定义cell 的内容
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //请求可重用单元格,需要一个标识,CustomCellTableViewCell为自定义单元格类
        let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as UITableViewCell
        //设置扩展视图的类型,就是Cell右侧的小箭头
        cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
        //设置单元格中的主标题
        cell.textLabel?.text = self.provinces[indexPath.row] as? String
        
        return cell
    }
    
    //点击Cell会触发视图控制器的Segue方法
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //判断是跳转的哪个segue,showtow为segue在故事板中定义的identifier
        if segue.identifier == "showtwo" {
            //得到二级(城市信息控制器)
            let datailVC = segue.destination as! TreetwoTableViewController
            //当前表视图被选择单元格
            let indexPath = self.tableView.indexPathForSelectedRow
            //以上得到的单元格的索引Row
            let row = indexPath?.row
            //当前单元格所对应的省份的名字
            let selectname = self.provinces[row!]
            //当前省份对应的城市信息的数组(将信息传给二级的listData)
            datailVC.listData = self.allData[selectname] as! NSArray
            //设置二级表视图名称
            datailVC.title = selectname as? String
        }
    }
    

}


三级表视图跳转传值:二级视图

import UIKit
//三级表视图,第二级 
class TreetwoTableViewController: UITableViewController {
    
    //在一级视图获取当前cell的省信息中的城市信息为数据传递过来
    var listData: NSArray! = nil

    override func viewDidLoad() {
        super.viewDidLoad()


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated
    }

    //TableViewDataSource 协议方法实现
    //返回表视图节的个数
    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
    //返回表视图每个节中的行数
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return self.listData.count
    }
    
    //返回每一个 自定义cell 的内容
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //请求可重用单元格,需要一个标识,CustomCellTableViewCell为自定义单元格类
        let cell = tableView.dequeueReusableCell(withIdentifier: "towidentifier", for: indexPath) as UITableViewCell
        //设置扩展视图的类型,就是Cell右侧的小箭头
        cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
        //某个省数据信息中的城市字典信息
        let towDict = self.listData[indexPath.row] as! NSDictionary
        //设置单元格中的主标题
        cell.textLabel?.text = towDict["name"] as? String
        return cell
    }
   
    //点击Cell会触发视图控制器的Segue方法
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //判断是跳转的哪个segue,showthree为segue在故事板中定义的identifier
        if segue.identifier == "showthree" {
            //得到三级(城市信息控制器)
            let datailVC = segue.destination as! TreeThreeViewController
            //当前表视图被选择单元格
            let indexPath = self.tableView.indexPathForSelectedRow
            //以上得到的单元格的索引Row
            let row = indexPath?.row
            //当前单元格所对应的城市信息字典
            let twoDict = self.listData[row!] as! NSDictionary
            //当前省份对应的城市信息的数组(将信息传给三级的twoUrl)
            datailVC.twoUrl = twoDict["url"] as! String
            //设置三级表视图名称
            let threeTitle = NSString(format:"百科:%@",(twoDict["name"] as? String)!)
            datailVC.title = threeTitle as String
        }
    }

}


三级表视图跳转传值:二级视图

import UIKit
//三级表视图,第三级 
class TreeThreeViewController: UIViewController,UIWebViewDelegate {

    var twoUrl: String!
    
    @IBOutlet weak var threewebHF: UIWebView! //webview输出口
    //如果上下有灰色或出现黑色,需要先加webview在连线
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //设置访问资源 - 百度搜索
        let url = URL(string: self.twoUrl)//只能https,http当前版本做了限制
        //建立网络请求
        let request = URLRequest(url: url!)
        //加载网络请求
        self.threewebHF.loadRequest(request)
        
        //print(self.twoUrl)
        self.threewebHF.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}