UIkit的基本框架

使用语言:swift

在Xcode的mian文件中查找控件:command + shift + L

UILabel

swift 复制代码
 //创建一个label
        let label:UILabel = UILabel(frame: CGRectMake(20, 100, 280, 100))
//        let label = UILabel(frame: CGRect(x: 100, y: 100, width: 150, height: 40))
        label.text = "i am a label,i like ios,i like phone"
        //设置字体
        label.font = UIFont.boldSystemFont(ofSize: 20)
        //设置字体颜色
        label.textColor = UIColor.red
        //设置label的背景颜色
        label.backgroundColor = UIColor.blue
        //设置文字的居中
        label.textAlignment = NSTextAlignment.center
        //设置label的阴影
//        label.shadowColor = UIColor.orange
//        label.shadowOffset = CGSizeMake(10, 10)//向右向下偏移10像素
        //设置label行数:在label的尺寸内将长句换行
        // 0表示无限行
        label.numberOfLines = 2
        
        self.view.addSubview(label)//把标签和视图关联

1.文本的常用字体样式:

2.背景常用的颜色样式:

3.常用颜色构造:

1.UIColor(white:alpha:):是一种快速创建灰度颜色的方法,white 是亮度值(0 是黑,1 是白),适合创建背景、灰色文字等

2.UIColor(red:green:blue:alpha:):通过 RGB 值创建自定义颜色

UIButton

swift 复制代码
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建并设置button类型
        /*
         case custom = 0 //自定义,无类型
         @available(iOS 7.0, *)
         case system = 1 //标准的系统类型
         case detailDisclosure = 2
         case infoLight = 3
         case infoDark = 4  //详情的按钮样式
         case contactAdd = 5 //添加的按钮样式
         */
        let button:UIButton = UIButton(type: .system)
        button.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        button.backgroundColor = UIColor.orange
        
        //添加事件
        //而 addTarget 传递的 selector 不支持带外部标签的写法,所以必须用 _ 省略标签
        button.addTarget(self, action: #selector(click(_:)), for: .touchUpInside)
        
        //设置按钮标题
        button.setTitle("an niu", for: .normal)
        
        self.view.addSubview(button)
    }
    //必须声明这个方法,前面加 @objc才能被Selector调用
    //按钮的点击事件需要 Objective-C runtime 支持
    @objc func click(_ btn:UIButton){
        print("按钮被点击了")
        btn.backgroundColor = UIColor.blue
    }

常用按钮样式

UIImageView

swift 复制代码
 override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建一个imageview对象
        let imageView = UIImageView(frame: CGRectMake(100, 100, 200, 200))
        //给imageview设置图片
        imageView.image = UIImage(named: "p1.jpg")
        //设置imageview的背景颜色
        imageView.backgroundColor = UIColor.red
        
        self.view.addSubview(imageView)
        
        //设置imageView的动画效果
        var array:Array<UIImage?> = Array()
        for i in 1...4 {
            let image:UIImage? = UIImage(named: "p\(i).jpg")
            
            array.append(image)
        }
        //设置动画数组
        imageView.animationImages = array as? [UIImage]
        //设置动画的播放次数
        // 0表示循环播放
        imageView.animationRepeatCount = 0
        //设置播放一轮的时间
        imageView.animationDuration = 3
        //开始播放动画
        imageView.startAnimating()
        
    }

contentMode

contentMode 是 UIImageView 的属性,用来控制图片如何在 UIImageView 的 frame 内缩放、对齐。

控件的layer属性

swift 复制代码
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //layer层专门对控件的视图进行渲染
        
        let imageView:UIImageView = UIImageView(frame: CGRectMake(100, 100, 100, 100))
        imageView.backgroundColor = UIColor.red
        
        //设置圆角
        //imageView.layer.masksToBounds = true
        //imageView.layer.cornerRadius = 50 //此时为圆形了
        //设置边框
        imageView.layer.borderWidth = 2
        imageView.layer.borderColor = UIColor.green.cgColor
        //设置阴影
        imageView.layer.shadowColor = UIColor.brown.cgColor
        imageView.layer.shadowOffset = CGSizeMake(10,10)
        imageView.layer.shadowOpacity = 1 //设置为不透明
        
        self.view.addSubview(imageView)
        
    }

1.相关属性和UI方面

swift 复制代码
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //搜索框控件
        
        //创建一个搜索框
        let searchBar:UISearchBar = UISearchBar(frame: CGRect(x: 20 ,y: 100 ,width: 320 ,height: 180))
        
        //设置输入框上的默认提示语
        searchBar.placeholder = "请输入关键字"
        //设置搜索框上显示的默认文字
        searchBar.text = "你好"
        //设置搜索框风格
        searchBar.barStyle = UIBarStyle.default
        //设置搜索框背景文字
        searchBar.prompt = "这是背景文字"
        //设置相应功能按键的显示与否
//        searchBar.showsBookmarkButton = true
        searchBar.showsSearchResultsButton = true
        //设置渲染颜色
        searchBar.tintColor = UIColor.red
        //设置搜索框颜色
        searchBar.barTintColor = UIColor.blue

		// 刷新布局,必写
        //让控件根据内部子控件内容,自动重新计算、适配自身宽高尺寸,覆盖你手动设置的frame宽高。
        searchBar.sizeToFit()
         
        self.view.addSubview(searchBar)
        
    }

2.与用户交互方面

swift 复制代码
import UIKit

class ViewController: UIViewController,UISearchBarDelegate {
    //创建一个搜索框
    var searchBar:UISearchBar = UISearchBar(frame: CGRect(x: 20 ,y: 100 ,width: 320 ,height: 180))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //搜索框控件
        
        //设置附件视图
        searchBar.scopeButtonTitles = ["1","2","3","4"]
        //展示附件视图
        searchBar.showsScopeBar = true
        searchBar.selectedScopeButtonIndex = 0
    
        //设置输入框上的默认提示语
        searchBar.placeholder = "请输入关键字"
        //设置搜索框上显示的默认文字
//        searchBar.text = "你好"
        //设置搜索框风格
        searchBar.barStyle = UIBarStyle.default
        //设置搜索框背景文字
//        searchBar.prompt = "这是背景文字"
        //设置相应功能按键的显示与否
        searchBar.showsBookmarkButton = true
//        searchBar.showsSearchResultsButton = true
        //设置渲染颜色
//        searchBar.tintColor = UIColor.red
        //设置搜索框颜色
//        searchBar.barTintColor = UIColor.blue
        
        //设置代理
        searchBar.delegate = self
        
        self.view.addSubview(searchBar)
        
    }
    //我们点击输入框时会弹出系统键盘,但是默认收不回去了
    //点击屏幕时系统键盘收起
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        searchBar.resignFirstResponder()//注销第一响应
    }
    
    //代理回调函数
    //点击附件视图代理方法的回调
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        print(selectedScope)
    }
    //当输入框文字变化时调用的方法
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
//        print(searchText)
    }
    //点击图书按钮时触发的方法
    func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
        print("点击了图书按钮")
    }
    //点击结果按钮时触发的方法
    func searchBarResultsListButtonClicked(_ searchBar: UISearchBar) {
        
    }
    //将要进入编辑状态时触发的方法
    //false不能进入编辑状态
    func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
        return true
    }
    ///将要结束编辑状态时触发的方法
    func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
        return true
    }
    //检测用户的输入文字
    func searchBar(_ searchBar: UISearchBar, shouldChangeTextInRanges ranges: [NSValue], replacementText: String) -> Bool {
        print(replacementText)
        return true
    }
    //点击取消按钮时触发的方法
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        
    }
    //点击"搜索"按钮时触发的方法
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        
    } 
}

UISwitch

swift 复制代码
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建一个开关控件
        //大小是系统固定的,影响的只有位置
        let mySwitch:UISwitch = UISwitch(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
        
        //添加触发事件
        mySwitch.addTarget(self, action: #selector(click(_:)), for: .valueChanged)
        
        //设置滑块的颜色
        mySwitch.thumbTintColor = UIColor.red
        //设置开关开启的颜色
        mySwitch.onTintColor = UIColor.blue
        //开关的渲染颜色
        mySwitch.tintColor = UIColor.green
        
        self.view.addSubview(mySwitch)
    }

    @objc func click(_ sw:UISwitch){
        if sw.isOn{
            self.view.backgroundColor = UIColor.gray
        }else{
            self.view.backgroundColor = UIColor.brown
        }
    }
}

对绑定事件和执行回调的理解

swift 复制代码
//......

//添加触发事件
mySwitch.addTarget(self, action: #selector(click(_:)), for: .valueChanged)

//回调方法
@objc func click(_ sw:UISwitch){
        if sw.isOn{
            self.view.backgroundColor = UIColor.gray
        }else{
            self.view.backgroundColor = UIColor.brown
        }
    }

1.语法解释

上面的绑定事件:

1、#selector()

Swift 语法:编译期校验方法是否存在,写错函数名 Xcode 直接报错(老式Selector("字符串")写错要运行才崩溃)。

2.、click(_ :)

click:绑定的方法名;

_ : 冒号代表这个函数需要接收 1 个参数(对应下面click(_ sw:UISwitch)的入参),有几个参数就写几个::

  • 无参函数:#selector(click)
  • 1 个参数:#selector(click(_ :))(现在的写法)
  • 2 个参数:#selector(click(_ :))

下面的回调函数:

1、@objc

Swift 的 addTarget 底层依赖 Objective-C 运行时,不加 @objc,OC 找不到这个 Swift 方法,点击 / 切换开关就找不到函数、直接崩溃。

作用:把 Swift 函数暴露给 OC 运行环境识别。

2、_ sw:UISwitch

  • _ :省略外部参数标签,调用时不用写参数名,直接 click(控件),对应 selector 写法必须带_:
  • sw:形参名,系统自动把触发事件的 UISwitch 控件传进来,sw.isOn 就是读取开关当前开 / 关状态;
  • UISwitch:限定参数类型只能是开关控件。

2.回调逻辑步骤

第 1 步:你注册 "我要监听这个控件的事件"

swift 复制代码
switch.addTarget(
    self,                  // 目标:事件来了交给"当前控制器"处理
    action: #selector(click(_:)), // 用哪个方法来响应
    for: .valueChanged     // 监听什么事件:开关"值变了"
)

你在这里没有调用 click,只是告诉系统:将来发生事时帮我调它。

第 2 步:用户动手(滑动开关)

  • 用户手指滑开关 → 开关内部检测到 "值变了"
  • 开关内部触发 UIControlEvent.valueChanged 事件

第 3 步:系统自动执行回调(核心!)

等价于系统帮你写了一句:

swift 复制代码
self.click(switch)

所以:click(_ :) 是系统调用的,不是你手动调用的。

第 4 步:你的 click(_ :)执行

UISegementControl

1.相关属性和UI方面

swift 复制代码
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建分段控制器控件
        let seg:UISegmentedControl = UISegmentedControl(frame: CGRectMake(20, 100, 280, 40))
        
        //设置按钮
        seg.insertSegment(withTitle: "第一第一第一第一第一第一个按钮", at: 0, animated: true)
        seg.insertSegment(withTitle: "第二个按钮", at: 1, animated: true)
        
        //添加点击事件
        seg.addTarget(self, action: #selector(click(_:)), for: .valueChanged)
        //设置分段控制器是否保持选中状态
        //true表示无法选中
        seg.isMomentary = false
        //设置宽度的自适应
//        seg.apportionsSegmentWidthsByContent = true
        //手动设置某个item的宽度
        seg.setWidth(60, forSegmentAt: 0)
        //设置内容区域的偏移量
        seg.setContentOffset(CGSizeMake(10, 10), forSegmentAt: 1)
        //手动设置默认选中item
        seg.selectedSegmentIndex = 0
        //设置渲染映射
        seg.tintColor = UIColor.red
        
        self.view.addSubview(seg)
    }

    @objc func click(_ seg:UISegmentedControl){
        print(seg.selectedSegmentIndex,"按钮被点击")
    }

2.切换视图方面

先在Main文件中拖取Navigation Controller视图

swift 复制代码
import UIKit

class ViewController: UIViewController {
    
    //创建两个视图
    let viewBlue:UIView = UIView(frame: CGRectMake(0,0,320, 568))
    let viewRed:UIView = UIView( frame: CGRectMake(0,0, 320, 568))

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let seg: UISegmentedControl = UISegmentedControl(items:
        ["blue", "red"])
        
        seg.addTarget(self, action: #selector(change(_:)),
        for: .valueChanged)
        
        self.navigationItem.titleView = seg
        viewBlue.backgroundColor = UIColor.blue
        viewRed.backgroundColor = UIColor.red
        
        self.view.addSubview(viewBlue)
        self.view.addSubview(viewRed)
        
        //先把蓝色的放在上面,就会把红色挡住
        self.view.bringSubviewToFront(viewBlue)
        seg.selectedSegmentIndex = 0
        
    }
    @objc func change(_ seg:UISegmentedControl){
        if seg.selectedSegmentIndex == 0 {
            self.view.bringSubviewToFront(viewBlue)
        }else{
            self.view.bringSubviewToFront(viewRed)
        }
    }
}

UITextField

1.相关属性和UI方面

swift 复制代码
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let textField:UITextField = UITextField(frame:
        CGRectMake (20, 100, 280, 40))
        //设置输入框风格为line
//        textField.borderStyle = UITextField.BorderStyle.line
        
        //设置输入框风格为bezel
        textField.borderStyle = UITextField.BorderStyle.bezel
        //设置输入框的提示文字
        textField.placeholder = "请输入文字"
        //设置输入字体颜色
        textField.textColor = UIColor.red
        //设置输入字体样式
        textField.font = UIFont.italicSystemFont(ofSize: 15)
        //设置文字的对齐方式
        textField.textAlignment = NSTextAlignment.center
        //设置背景颜色
//        textField.backgroundColor = UIColor.red
        //是否每次进入编辑状态时都清空输入框中的文字
        textField.clearsOnBeginEditing = true
        //是否字体大小自适应
        textField.adjustsFontSizeToFitWidth = true
        //设置输入框为无效
//        textField.isEnabled = false
        //设置输入框的左视图
        let viewLeft:UIView = UIView(frame: CGRectMake (0,0,40,40))
        let viewRight:UIView = UIView(frame: CGRectMake(0,0, 40,40))
        viewLeft.backgroundColor = UIColor.blue
        viewRight.backgroundColor = UIColor.green
        textField.leftView = viewLeft
        textField.rightView = viewRight
        //设置左右视图的显示模式
        textField.leftViewMode = UITextField.ViewMode.always
        textField.rightViewMode = UITextField.ViewMode.always
        
        //设置弹出的交互键盘
        let board:UIView = UIView(frame: CGRectMake (0,0,320,80))
        board.backgroundColor = UIColor.orange
//        textField.inputView = board
        //设置附键盘视图
        textField.inputAccessoryView = board
        
        self.view.addSubview(textField)
    }
}

2.与用户交互方面

swift 复制代码
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let textField:UITextField = UITextField(frame:
        CGRectMake (20, 100, 280, 40))
        //设置输入框风格为line
//        textField.borderStyle = UITextField.BorderStyle.line
        
        //设置输入框风格为bezel
        textField.borderStyle = UITextField.BorderStyle.bezel
        //设置输入框的提示文字
        textField.placeholder = "请输入文字"
        //设置输入字体颜色
        textField.textColor = UIColor.red
        //设置输入字体样式
        textField.font = UIFont.italicSystemFont(ofSize: 15)
        //设置文字的对齐方式
        textField.textAlignment = NSTextAlignment.center
        //设置背景颜色
//        textField.backgroundColor = UIColor.red
        //是否每次进入编辑状态时都清空输入框中的文字
        textField.clearsOnBeginEditing = true
        //是否字体大小自适应
        textField.adjustsFontSizeToFitWidth = true
        //设置输入框为无效
//        textField.isEnabled = false
        //设置输入框的左视图
        let viewLeft:UIView = UIView(frame: CGRectMake (0,0,40,40))
        let viewRight:UIView = UIView(frame: CGRectMake(0,0, 40,40))
        viewLeft.backgroundColor = UIColor.blue
        //viewRight.backgroundColor = UIColor.green
        textField.leftView = viewLeft
        textField.rightView = viewRight
        //设置左右视图的显示模式
        textField.leftViewMode = UITextField.ViewMode.always
        textField.rightViewMode = UITextField.ViewMode.always
        
        //设置弹出的交互键盘
        let board:UIView = UIView(frame: CGRectMake (0,0,320,80))
        board.backgroundColor = UIColor.orange
//        textField.inputView = board
        //设置附键盘视图
        textField.inputAccessoryView = board
        
        //设置代理
        textField.delegate = self
        //设置文本框清除按钮的显示模式
        textField.clearButtonMode = UITextField.ViewMode.always
        
        self.view.addSubview(textField)
    }
    //代理方法
    //当输入改变时调用的方法
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        print(string)
        return true
    }
    //已经进入编辑状态时调用的方法
    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("didBegin")
    }
    //结束编辑状态时调用的方法
    func textFieldDidEndEditing(_ textField: UITextField) {
        print("didEnd")
    }
    //将要进入编辑状态时调用的方法
    //false表示不能进入编辑状态
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        print("shouldBegin")
        return true
    }
    //将要结束编辑状态时调用的方法
    //false表示不能进入结束编辑状态
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        print("shouldEnd")
        return true
    }
    //设置清除键模式是否生效
    func textFieldShouldClear(_ textField: UITextField) -> Bool{
        return true
    }
    //点击键盘中return键触发的方法
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

UISlider

swift 复制代码
import UIKit

class ViewController: UIViewController {
    //创建一个滑块对象
    let slider:UISlider = UISlider(frame: CGRectMake(20,100, 280, 40))
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //滑块控件UISlider
        
        //添加一个控制方法
        slider.addTarget(self, action: #selector(slider(_:)), for: .valueChanged)
        //设置滑块的取值范围
        slider.maximumValue = 100
        slider.minimumValue = 1
        //设置是否在滑动时持续触发方法
        //false代表停止滑动时才触发方法
        slider.isContinuous = true
        //设置滑动轴的颜色
        slider.minimumTrackTintColor = UIColor.red
        slider.maximumTrackTintColor = UIColor.yellow
        
        self.view.addSubview(slider)
    }
    
    @objc func slider(_ mysl:UISlider){
        print(mysl.value)
    }
    //点击屏幕滑块到任意位置
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        slider.setValue((Float)(arc4random()%99+1), animated: true)
    }
}

UISlider的实操

实现通过滑块的滑动改变图片的大小

swift 复制代码
import UIKit

class ViewController: UIViewController {
    let imageView: UIImageView = UIImageView(frame: CGRectMake(0, 0, 320,400))

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
             
        let slider:UISlider = UISlider(frame: CGRectMake(20, self.view.frame.size.height - 60,280, 20)) ;
        self.view.addSubview(slider);
        
        slider.addTarget(self, action: #selector(slider(_:)),
        for: .valueChanged)
        
        slider.maximumValue = 100
        slider.minimumValue = 0
        
        imageView.image = UIImage(named:"p1.jpg")
        self.view.addSubview( imageView)
    }

    @objc func slider(_ mysl:UISlider){
        let value:Float = 1-mysl.value/100
        
        imageView.bounds = CGRectMake(0, 0,320*(CGFloat) (value), 400*(CGFloat) (value))
    }
}

UIActivityIndicatorView

swift 复制代码
import UIKit

class ViewController: UIViewController {
    //创建一个活动提示控件
    let act:UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 320/2-10, y: 568/2, width: 20, height: 20))
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
//        UIActivityIndicatorView -- 加载时出现的小圈圈
        
        self.view.backgroundColor = UIColor.gray
        
        //设置提示圈颜色
        act.color = UIColor.red
        
        //使用时要设置开始动画
        act.startAnimating()
        
        self.view.addSubview(act)
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //停止活动
        act.stopAnimating()
    }
}

UIProgressView

swift 复制代码
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //进度条控件
        
        let progress:UIProgressView = UIProgressView(progressViewStyle: UIProgressView.Style.default)
        
        progress.frame = CGRect(x: 20, y: 100, width: 280, height: 20)
        
        //设置进度条进度 0-1
        progress.progress = 0.5
        //设置走过的进度颜色
        progress.progressTintColor = UIColor.red
        //设置没走过的进度颜色
        progress.trackTintColor = UIColor.green
        
        self.view.addSubview(progress)
    }
}

UIPageControl

swift 复制代码
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建一个分页控制器
        let page:UIPageControl = UIPageControl(frame: CGRect(x: 150, y: 100, width: 100, height: 30))
        
        self.view.backgroundColor = UIColor.red
        
        //设置分页页数
        page.numberOfPages = 4
        //设置当前页码,下标从0开始
        page.currentPage = 3
        //设置只有一页时,是否自动隐藏
        //true代表会自动隐藏
        page.hidesForSinglePage = false
        //设置分页控制器的当前页颜色
        page.currentPageIndicatorTintColor = UIColor.blue
        //设置分页点颜色
        page.pageIndicatorTintColor = UIColor.purple
        
        //添加方法
        page.addTarget(self, action: #selector(change(_:)), for: .valueChanged)
        
        self.view.addSubview(page)
    }
    
    @objc func change(_ pg:UIPageControl){
        print(pg.currentPage) //打印当前页号
    }

}

UIStepper

swift 复制代码
import UIKit

class ViewController: UIViewController {
    
    let label:UILabel = UILabel(frame: CGRect(x: 100, y: 300, width: 100, height: 100))

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建一个Stepper步进控制器
        let steper:UIStepper = UIStepper(frame: CGRect(x: 100, y: 100, width: 100, height: 40))
        
        label.text = String(format: "%f", steper.value)
        
        //设置最大值和最小值。默认是[0,100]
        steper.maximumValue = 10
        steper.minimumValue = 0
        
        //设置步长
        steper.stepValue = 2
        //是否连续触发响应函数
        steper.isContinuous = false
        //值是否持续改变
        //false表示长按后松手值不会改变
        steper.autorepeat = false
        //设置到达最值后是否可以循环触发
        steper.wraps = true
        
        //设置控件的颜色
        steper.tintColor = UIColor.red //err
        
        //添加方法
        steper.addTarget(self, action: #selector(change(_:)), for: .valueChanged)
        
        self.view.addSubview(steper)
        self.view.addSubview(label)
    }

    @objc func change(_ steper:UIStepper){
        //改变值时显示在标签里
        label.text = String(format: "%f", steper.value)
    }
}

UIAlertController

1.UIAlertController = 弹窗本身

就是你看到的那个白色框、标题、消息。

2.UIAlertAction = 弹窗里的按钮

就是 "确定""取消""删除" 这些可点击的按钮。

3.addAction = 把按钮加到弹窗里

1.AlertView

swift 复制代码
import UIKit

class ViewController: UIViewController,UIAlertViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //使用旧方法创建警告框
//        let alertView:UIAlertView = UIAlertView(title: "alert", message: "look me", delegate: self, cancelButtonTitle: "cancel", otherButtonTitles: "sure")
//        
//        //设置alertView的风格
//        alertView.alertViewStyle = UIAlertViewStyle.loginAndPasswordInput
//        
//        alertView.show()
        
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //使用新方法创建警告框
        //UIAlertController不用代理,靠闭包 handler 接收点击事件。
        let alertView:UIAlertController = UIAlertController(title: "alert", message: "look me", preferredStyle: UIAlertController.Style.alert)
        //添加了一个封装了操作逻辑的按钮
        let alertActionOne:UIAlertAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.destructive, handler: {
            (alert) -> Void in print("cancel")
        })
        //添加一个输入框
        alertView.addTextField(configurationHandler: {
            (textField) -> Void in textField.placeholder = "hello world"
        })
        alertView.addAction(alertActionOne)
        //弹出警告框
        self.present(alertView, animated: true)
    }
    
    //代理回调方法
//    func alertView(alertView:UIAlertView, clickedButtonAtIndex buttonIndex:Int){
//        print(buttonIndex)
//    }
}

为什么使用新方法创建警告框要重写在touchesBegan里,不能直接写在viewDidLoad?

1、viewDidLoad 阶段页面还没渲染、控制器还没完成挂载到屏幕上,不能执行 present 弹窗;

2、touchesBegan 是点击屏幕后、页面已经完全加载完毕,此时可以正常弹窗。

2.ActionSheet

swift 复制代码
import UIKit

class ViewController: UIViewController ,UIActionSheetDelegate{

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //警告弹窗
        
        //使用旧的方法创建actionSheet
//        let sheet: UIActionSheet = UIActionSheet(title: "actionSheet",delegate: self, cancelButtonTitle: "cancel",
//        destructiveButtonTitle: "delete")
//        
//        sheet.show(in: self.view
            
    }
    //使用xin的方法创建actionSheet
     override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
         //创建一个警告弹窗
        let actionSheet:UIAlertController = UIAlertController(title:"actionSheet", message: "look me", preferredStyle:
        UIAlertController.Style.actionSheet)
        
         let actionAction:UIAlertAction = UIAlertAction(title:"one",style: UIAlertAction.Style.default) {(action) -> Void in
             print("helle world")
         }
            
         let actionActionOther:UIAlertAction = UIAlertAction(title:"cancel", style: UIAlertAction.Style.cancel) { (action) -> Void in print("cancel")
         }
            
            actionSheet.addAction(actionAction)
            actionSheet.addAction (actionActionOther)
         
         //弹出警告框
        self.present(actionSheet, animated: true)
    }
  
    //代理方法,点击按钮时触发
//    func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
//        print(buttonIndex)
//    }
}

UIScrollView

一共包含两个部分:

相关属性和UI方面+与用户交互方面(代理方法)

swift 复制代码
import UIKit

class ViewController: UIViewController,UIScrollViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //滚动视图
        let scrollView:UIScrollView = UIScrollView(frame: self.view.frame )
      
        let view:UIView = UIView(frame:
        CGRectMake (100,100,100, 100))
        view.backgroundColor = UIColor.red
        scrollView.addSubview(view)
        //设置scrollerView的内容尺寸
        scrollView.contentSize = CGSizeMake(self.view.frame.size.width*2, self.view.frame.size.height*2)
        //设置回弹效果
        scrollView.bounces = true
        //设置指示条的位置
        scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 20.0, right: 20.0)
        //设置指示条是否显示
        scrollView.showsHorizontalScrollIndicator = true
        //设置是否翻页效果
        scrollView.isPagingEnabled = true
        
        //设置拉伸和缩放的比值
        scrollView.minimumZoomScale = 0.5
        scrollView.maximumZoomScale = 2;
        
        //设置代理
        scrollView.delegate = self
        
        self.view.addSubview(scrollView)
    }
    //设置拉伸和缩放操作,返回进行缩放的视图
    func viewForZooming(in scrollView: UIScrollView) -> UIView?
    {
        return scrollView.subviews.first
    }
    //scrollView减速结束时触发的代理方法
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        
    }
    //scrollView停止拖拽时触发的方法
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        
    }
    //scrollView停止动画的时候触发的方法
    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        
    }
    //scrollView停止缩放效果时触发的方法
    func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
        
    }
    //scrollView进行缩放效果时触发的方法
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        
    }
    //scrollView开始滑动时触发的方法
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
    }
    //scrollVie滑动到顶部时触发的方法
    func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
        
    }
    //scrollVie将要滑动到顶部时触发的方法
    //false代表不能进行回到顶部的操作
    func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
        return true
    }
}

UITableView

UITableView的创建流程+头尾视图的创建+编辑状态的变化+相关代理方法。

1.UITableView的创建的步骤

1.控制器遵守两个协议(必加)

dataSource:提供单元格数据;delegate:处理点击,缺少就空白

2.绑定数据源与代理

3.数据源的三个核心方法

设置分区,设置每个分区的行数,设置每行单元格

2.头尾视图的创建的步骤

首先说明,plain 样式默认没有 Header/Footer 视图。

1.设置头视图的高度

2.必须返回一个view视图,空白占位也要创建View,nil=系统默认空白不生效

3.改变编辑状态的两个步骤

1.设置具体的编辑状态

2.点击左侧删除圆圈触发

swift 复制代码
import UIKit

//1. 控制器遵守两个协议(必加)
//dataSource:提供单元格数据;delegate:处理点击,缺少就空白
class ViewController: UIViewController ,UITableViewDataSource, UITableViewDelegate{

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //创建tableView 风格可以是普通和分组两种
        let tableView:UITableView = UITableView(frame: self.view.frame,style: UITableView.Style.grouped)
        //2.绑定数据源与代理
        tableView.dataSource = self
        tableView.delegate = self
        
        //重新刷新数据
        tableView.reloadData()
        
        //设置tableView的回弹效果
        tableView.bounces = false
        
        //设置tableView的编辑状态
        tableView.isEditing = true
        
        self.view.addSubview(tableView)
    }
    //3.数据源的三个核心方法
    //分区数
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    // 行数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // 一共10行
    }
    // 每行单元格
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        cell.textLabel?.text = "第\(indexPath.row)行"
        return cell
    }
    
    //plain 样式默认没有 Header/Footer 视图
    //必须同时实现【高度方法 + 返回 header 视图】
    //1.设置头视图的高度
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 100
    }
    //2.必须返回一个view,空白占位也要创建View,nil=系统默认空白不生效
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = UIView()
        header.backgroundColor = UIColor.red //上色就能直观看到高度
        return header
    }
    //设置尾视图的高度
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 100
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let footer = UIView()
        footer.backgroundColor = UIColor.blue
        return footer
    }
    //设置cell的高度,默认时44
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60
    }
    
    //相关代理方法
    //点击cell触发的方法
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("%d, %d", indexPath.section, indexPath.row)
    }
    //取消选中某个cell触发的方法
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        
    }
    
    //1.设置具体的编辑状态
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return UITableViewCell.EditingStyle.delete
    }
    //2.点击左侧删除圆圈触发
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            //1.先删除数据源
            //xxxx.remove(at: indexPath.row)
            //2.再删除单元格
            //xxxx.deleteRows(at: [indexPath], with: .automatic)
        }else if editingStyle == .insert{
            //xxx.append()
        }
    }
    
    //设置tableView的移动
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
//        let str = dataArray?[sourceIndexPath.row]
//        dataArray?. removeAtIndex(sourceIndexPath.row)
//        dataArray?.insert(str!, atIndex: destinationIndexPath.row)
    }
}

UITextView

特点:文字链接化,还包括电话,地址,日历等类型

swift 复制代码
import UIKit

class ViewController: UIViewController,UITextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let textVew:UITextView = UITextView(frame: CGRectMake(20, 100,280, 100))
        textVew.backgroundColor = UIColor.gray
        
        //设置字体
        textVew.font = UIFont.systemFont(ofSize: 25)
        //设置文字颜色
        textVew.textColor = UIColor.red
        //设置对齐模式
        textVew.textAlignment = NSTextAlignment.center
        //设置是否可编辑
        textVew.isEditable = true
        //设置内容
//        textVew.text = "你好,我是textView\n 网址:www.baidu.coml"
        //设置链接化类型
        textVew.dataDetectorTypes = UIDataDetectorTypes.link
        
        //设置代理
        textVew.delegate = self
        
        self.view.addSubview(textVew)
    }
    //输入字符时调用
    //false代表此时不能输入
    func textView(_ textView: UITextView, shouldChangeTextInRanges ranges: [NSValue], replacementText text: String) -> Bool {
        return false
    }
    //开始编辑时调用
    func textViewDidBeginEditing(_ textView: UITextView) {
        
    }
    //结束编辑时调用
    func textViewDidEndEditing(_ textView: UITextView) {
        
    }
    //输入改变时调用
    func textViewDidChange(_ textView: UITextView) {
        
    }
    //改变选中文字时调用
    func textViewDidChangeSelection(_ textView: UITextView) {
        
    }
    //将要开始编辑时调用
    func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
        return true
    }
    //将要结束编辑时调用
    func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
        return true
    }

}

UIPickerView

swift 复制代码
import UIKit

class ViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource {
    var dataArray:Array<String>?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //UIPickerView类似于UITableView,只不过UIPickerView的表现形式是滚动形式
        let pickerView:UIPickerView = UIPickerView(frame: CGRect(x: 100, y: 100, width: 200, height: 150))
        
        //设置数据源和代理
        pickerView.delegate = self
        pickerView.dataSource = self
        
        dataArray = ["one","two","three","four","five"]
        
        self.view.addSubview(pickerView)
    }
    //设置分区数
    func  numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    //设置每个分组的行数
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return dataArray!.count
    }
    //设置每一行的内容
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return dataArray?[row]
    }
    //设置每个分区的宽度
    func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
        return 100
    }
}

UIDatePicker

swift 复制代码
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //系统帮我们封装好的有关时间的操作
        
        let datePicker:UIDatePicker = UIDatePicker(frame:
        CGRectMake (100, 100, 200, 200))
        //设置显示模式
        datePicker.datePickerMode = UIDatePicker.Mode.dateAndTime
        
        //继承了UIControl,可以添加绑定方法
        datePicker.addTarget(self, action: #selector(changeDate(_:)), for: .valueChanged)
       
        self.view.addSubview(datePicker)
        
    }
    @objc func changeDate(_ sp:UIDatePicker){
        let date = sp.date
        print(date)
    }

}

UIWebView

要导入头文件 import WebKit

swift 复制代码
import UIKit
import WebKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //网页视图,类似于一种简洁的网页浏览器
        let webView:WKWebView = WKWebView(frame:self.view.bounds)
        // 规范URL写法:https(现在苹果禁用http明文)
        guard let url = URL(string: "https://www.baidu.com") else { return }
        
        let req = URLRequest(url: url)
        webView.load(req)
        
        self.view.addSubview(webView)
    }
}

UICollectionView

1.UICollectionView创建的步骤

1.控制器遵守协议

UICollectionViewDataSource:提供 item 个数、创建 cell;

UICollectionViewDelegateFlowLayout:布局、尺寸、边距、头尾部尺寸

布局类:必须搭配UICollectionViewFlowLayout(流式布局,格子排布规则)

2.绑定代理、注册 Cell

创建布局对象

创建collectionView

绑定数据源、代理

注册cell(必填,复用标识)

3.数据源的三个核心数据源方法

设置分区,设置每个分区的行数,设置每行单元格

swift 复制代码
import UIKit

class ViewController: UIViewController,UICollectionViewDelegateFlowLayout,UICollectionViewDataSource {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        //有点类似于UITableView,但是比UITableView更强大,不仅仅能设计表格类的布局,还能自定义布局(元素的大小,元素的排列方式)
        
        let layout:UICollectionViewFlowLayout =
        UICollectionViewFlowLayout()
        //设置布局方向
        layout.scrollDirection = UICollectionView.ScrollDirection.horizontal
        //设置每个元素的大小
        layout.itemSize = CGSizeMake (80, 80)
        //设置元素间距
        layout.minimumInteritemSpacing = 10
        //设置行间距
        layout.minimumLineSpacing = 30

        let collectionView:UICollectionView = UICollectionView(frame:
        self.view.frame, collectionViewLayout: layout)
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        //注册普通 Item 单元格
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
        
        self.view.addSubview(collectionView)
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath)
        
        cell.backgroundColor = UIColor.red
        
        return cell
    }
    
    //可以自定义色块的大小
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let tmp = indexPath.row%3 //0 1 2
        if tmp == 0{
            return CGSize(width: 50, height: 50)
        }else if tmp == 1{
            return CGSize(width: 100, height: 100)
        }else{
            return CGSize(width: 50, height: 50)
        }
    }
}

其他代理方法:

didSelectItemAt:

它是 UICollectionViewDelegate 协议的核心方法,当用户点击相册中的某张照片 / 视频单元格时,系统会自动调用这个方法。这段代码的核心逻辑是:根据用户点击的资源,调用 toggleSelection 方法来切换选中状态。

trailingSwipeActionsConfigurationForRowAt:处理单元格左滑操作。

contextMenuConfigurationForRowAt:处理单元格长按弹出菜单

2.UICollectionView的实操

做出来一个随机颜色的UICollectionView布局

自定义布局类MyLayout

swift 复制代码
import UIKit

class MyLayout: UICollectionViewFlowLayout {
    
    var itemCount:Int? //元素个数
    var attributeArray:Array<UICollectionViewLayoutAttributes>? //存放layout中的布局属性
    
    override func prepare(){
        super.prepare()
        attributeArray = Array()
        //计算每个元素的宽度
        let Width = (UIScreen.main.bounds.size.width - self.minimumInteritemSpacing) / 2
        //循环设置每个元素的布局属性
        var l = 0 //左边 列高
        var r = 0 //右边 列高
        for  i in 0..<itemCount!{
            let indexPath = NSIndexPath(item: i, section: 0)
            let atti = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
            //哪一个列高更小元素放在那一边
            let height = (Int)(arc4random()%140 + 50) //随机高度
            var tmp = 0//记录元素放在哪一列,0是第一列,1是第二列
            var H = 0
            if(l <= r){
                H = l
                l += (height + (Int)(self.minimumLineSpacing))
                tmp = 0
              
            }else{
                H = r
                r += (height + (Int)(self.minimumLineSpacing))
                tmp = 1
                
            }
            //每个元素块的放置位置和大小
            atti.frame = CGRect(x: Int((CGFloat)(tmp) * (Width + self.minimumInteritemSpacing)), y: (Int)(H), width: (Int)(Width), height: height)
            attributeArray?.append(atti)
        }
        if l <= r{
            self.itemSize = CGSize(width: Width, height: CGFloat((r * 2 / itemCount!)) - self.minimumLineSpacing)
        }else{
            self.itemSize = CGSize(width: Width, height: CGFloat((l * 2 / itemCount!)) - self.minimumLineSpacing)
        }
    }
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return attributeArray
    }
}

ViewController.swift

swift 复制代码
import UIKit

class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let myLayout = MyLayout()
        myLayout.itemCount = 100
        
        let collectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: myLayout)
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
        
        self.view.addSubview(collectionView)
        
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath)
        
        //给cell设置随机色
        cell.backgroundColor = UIColor(red: CGFloat((CFloat)(arc4random()%255)/255.0), green: CGFloat((CFloat)(arc4random()%255)/255.0), blue: CGFloat((CFloat)(arc4random()%255)/255.0), alpha: 1)
        
        return cell
    }
}

UIStackView

用来垂直排列所有卡片的容器,它的好处是自动处理间距,不用手动给每个卡片加垂直约束。

一、核心布局属性(最常用)

1.axis:排列方向(主轴)

可选值:

.horizontal:水平排列(默认)

.vertical:垂直排列

作用:决定子视图是一行排开,还是一列排开。

swift 复制代码
stackView.axis = .vertical

2.distribution:主轴方向分布方式

主轴:axis 指定的方向(水平 / 垂直)。

可选值(5 种):

.fill(默认)

拉伸子视图填满主轴空间

按 Content Hugging/Compression Resistance 决定谁被拉伸

.fillEqually

所有子视图等宽 / 等高(平分空间)

.fillProportionally

按子视图固有内容大小比例分配空间

.equalSpacing

子视图尺寸不变,间距自动相等

首尾也有空白间距

.equalCentering

子视图中心间距相等

视图不拉伸,适合图标 + 文字均匀分布

3.alignment:交叉轴对齐方式

交叉轴:与 axis 垂直的方向。

可选值:

.fill(默认) :子视图填满交叉轴

.leading / .top :靠起始边(水平→上对齐;垂直→左对齐)

.trailing / .bottom :靠结束边

.center:居中对齐

swift 复制代码
// 水平stackView,子视图垂直居中
stackView.alignment = .center

4.spacing:子视图之间的间距

单位:pt

默认:0

作用:相邻子视图之间的最小间距Apple Developer

注意:distribution = .equalSpacing 时,spacing 是最小间距,实际会更大。

swift 复制代码
stackView.spacing = 10

二、边距与基线相关(常用)

5.isLayoutMarginsRelativeArrangement

核心作用:

  • 控制 StackView 的子视图是否以 layoutMargins 作为边界来布局。
  • 默认值:false,子视图直接贴着 StackView 的边缘排列,不会留出内边距。

开启 true 时的效果:

  • 子视图会自动和 layoutMargins 保持距离,不会顶到边缘;
  • 你可以通过 stackView.layoutMargins 设置上下左右的内边距,子视图会自动适应。

典型用法:

swift 复制代码
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)

开启后,子视图就会和 StackView 边缘保持 16pt 的边距,不用再给每个子视图单独设置 leading/trailing 约束。

6.isBaselineRelativeArrangement

核心作用:

  • 控制 垂直方向 子视图之间的间距,是按「视图顶部」计算,还是按「文字基线」计算。
  • 默认值:false,间距是按子视图的 frame 边界计算的。

开启 true 时的效果

  • 垂直 StackView 中,两个带文字的控件(比如两个 UILabel)之间的间距,会从上一行文字的基线,算到下一行文字的基线,而不是从控件的顶部 / 底部计算。
  • 这样多行文本的排版会更整齐,视觉上的间距也更均匀。

举个直观例子

比如两个高度不同的 UILabel:

  • false:间距按控件底部到下一个控件顶部计算,文字可能看起来挤在一起;
  • true:间距按文字基线计算,两行文字的距离会更一致,排版更舒服。

适用场景:

  • 垂直排列多行文本、标签、按钮,希望文字对齐更自然。
  • 表单、说明文字、多行列表等排版场景。

小建议:

  • 做卡片 / 列表:isLayoutMarginsRelativeArrangement = true 基本是必开的;
  • 做多行文本:isBaselineRelativeArrangement = true 能让排版好看很多。

三、子视图管理属性

7.arrangedSubviews

swift 复制代码
var arrangedSubviews: [UIView] { get }

只读数组:当前被 StackView 管理的子视图。

区别:

  • addArrangedSubview(view):加入 arrangedSubviews,自动布局
  • addSubview(view):仅添加到视图层级,不自动布局

8.addArrangedSubview(_ :) / removeArrangedSubview(_ :)

swift 复制代码
func addArrangedSubview(_ view: UIView)
func removeArrangedSubview(_ view: UIView)
  • 添加 / 移除受管理的子视图
  • removeArrangedSubview 不会把 view 从父视图移除(只是不再管理布局)

UIViewController

Controller是将view和逻辑结合的控制器层。

本节学习的是ViewController的生命周期的相关方法。

先在main文件里再拖拽一个ViewController2界面,创建一个ViewController2.swift文件与这个界面关联,在第一个ViewController界面中放入一个"跳转"按钮,与第二个界面关联。

下面代码是在ViewController2.swift文件里写的:

swift 复制代码
import UIKit

class ViewController2: UIViewController {
    
    var tmp:Int = 0
    
    override func loadView() {
        super.loadView()
        tmp += 1
        print(tmp, "loadView")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        tmp += 1
        print(tmp, "viewDidLoad")

        // Do any additional setup after loading the view.
    }
    //视图将要展示时调用的方法
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tmp += 1
        print(tmp, "viewWillAppear")
    }
    //将要布局子视图
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        tmp += 1
        print(tmp, "viewWillLayoutSubviews")
    }
    //已经布局子视图完成
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tmp += 1
        print(tmp, "viewDidLayoutSubviews")
    }
    //视图已经展示
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        tmp += 1
        print(tmp, "viewDidAppear")
    }
    //视图将要消失
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        tmp += 1
        print(tmp, "viewWillDisappear")
    }
    //视图已经消失
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        tmp += 1
        print(tmp, "viewDidDisappear")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //返回上一个controller
        self.dismiss(animated: true, completion: nil)
    }

从点击"跳转"到结束过程如下:

UINavigationController

UINavigationController 就是一个 "栈管理器"。

它用 栈(先进后出)结构 来管理一堆 UIViewController,是层级结构,负责:

1.压入页面(push)

2.弹出页面(pop)

3.显示顶部页面

4.自动生成导航栏(返回按钮、标题)

main文件准备

拖拽到导航界面

把View Controller界面与ViewController类关联

ViewController.swift文件

1、NavigationController页面与ViewController的切换

2、导航栏设置

导航栏标题规则:导航栏永远读取当前栈顶控制器的 title

  • 首页在栈顶 → 显示首页
  • push 新页面后新 VC 变成栈顶 → 显示新 VC 的 title(没赋值就空白)

iOS15之后的导航栏不显示且无色,要强制显示并设置背景颜色。

3、导航栏按键的自定义

swift 复制代码
import UIKit

//导航栏标题规则:导航栏永远读取当前栈顶控制器的 title
//-首页在栈顶 → 显示首页
//-push 新页面后新 VC 变成栈顶 → 显示新 VC 的 title(没赋值就空白)

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        // 内容自动从导航栏下方开始
        edgesForExtendedLayout = []
        // 强制显示导航栏
        navigationController?.setNavigationBarHidden(false, animated: false)
            // iOS15+强制显示导航栏底色(默认导航栏透明无底色)
        let app = UINavigationBarAppearance()
        app.backgroundColor = .gray
        navigationController?.navigationBar.standardAppearance = app
        navigationController?.navigationBar.scrollEdgeAppearance = app
        
        self.title = "首页"
        
        
        let label:UILabel = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 30))
        label.backgroundColor = UIColor.red
        label.text = "hello world"
        
        let button:UIButton = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 30))
        button.backgroundColor = UIColor.green
        button.setTitle("切换", for: .normal)
        button.addTarget(self, action: #selector(changeController(_:)), for: .touchUpInside)
        
        //自定义导航栏按钮
        let barButtonItem:UIBarButtonItem = UIBarButtonItem(title: "返回", style: .plain, target: self, action:#selector(back))
        
        //只能对UI方面进行修改,无法触发方法
        //self.navigationItem.backBarButtonItem = barButtonItem
        
        self.navigationItem.leftBarButtonItem = barButtonItem
        //使用系统的左右按键样式
        let barR1 = UIBarButtonItem(barButtonSystemItem:
        UIBarButtonItem.SystemItem.bookmarks, target:self, action:#selector(action1))
        
        let barR2 = UIBarButtonItem(barButtonSystemItem:
        UIBarButtonItem.SystemItem.camera, target: self, action:#selector(action2))
        self.navigationItem.rightBarButtonItems = [barR1, barR2]
        
        //系统的工具栏
        //self.navigationController?.isToolbarHidden = false
        //self.toolbarItems = [barR1, barR2]
        
        self.view.addSubview(label)
        self.view.addSubview(button)
    }
    @objc func changeController(_ bnt:UIButton){
        let viewController:UIViewController = UIViewController()
        //给新添加的页面设背景色
        viewController.view.backgroundColor = UIColor.white
        viewController.title = "标题2"
        // 关键:自定义返回按钮文字(在上一页设置,不是新页面)
        let backItem = UIBarButtonItem(title:"首页", style:.plain, target:nil, action:nil)
        navigationItem.backBarButtonItem = backItem
        
        self.navigationController?.pushViewController(viewController, animated: true)
    }
    @objc func back(){
        print("返回")
    }
    @objc func action1() {
        print("action1")
    }
    @objc func action2 () {
        print("action2")
    }

}

一、最最常用

1.navigationBar

导航条本身(顶部那一条)

swift 复制代码
navigationController?.navigationBar

你可以设置它的颜色、字体、背景、高度、隐藏分割线等。

2.viewControllers

栈里所有控制器(数组)

swift 复制代码
navigationController?.viewControllers
  • 第一个 = 根控制器
  • 最后一个 = 当前显示的控制器

3.topViewController

当前最顶部的控制器

swift 复制代码
navigationController?.topViewController

4.visibleViewController

当前正在显示的控制器(和 top 基本一样)

二、显示 / 隐藏导航栏

5.isNavigationBarHidden

隐藏 / 显示导航条

swift 复制代码
navigationController?.isNavigationBarHidden = true // 隐藏
navigationController?.isNavigationBarHidden = false // 显示

带动画隐藏:

swift 复制代码
navigationController?.setNavigationBarHidden(true, animated: true)

三、导航栏外观(最常用)

6.navigationBar.tintColor

导航条上按钮颜色(返回键、文字图标)

swift 复制代码
navigationController?.navigationBar.tintColor = .red

7.navigationBar.barTintColor

导航条背景颜色

swift 复制代码
navigationController?.navigationBar.barTintColor = .white

8.navigationBar.titleTextAttributes

导航标题字体、颜色

swift 复制代码
navigationController?.navigationBar.titleTextAttributes = [
    .foregroundColor: UIColor.black,
    .font: UIFont.systemFont(ofSize: 17, weight: .bold)
]

9.isTranslucent

导航条半透明(默认 true)

swift 复制代码
navigationController?.navigationBar.isTranslucent = false
  • true:内容会从导航栏底下穿过
  • false:内容从导航栏底部开始

10.去掉导航栏底部分割线(超级常用)

swift 复制代码
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)

四、手势(侧滑返回)

11.interactivePopGestureRecognizer

侧滑返回手势

swift 复制代码
// 关闭侧滑返回
navigationController?.interactivePopGestureRecognizer?.isEnabled = false

五、页面切换(方法)

12.pushViewController 进入下一页

swift 复制代码
navigationController?.pushViewController(vc, animated: true)

13.popViewController 返回上一页

swift 复制代码
navigationController?.popViewController(animated: true)

14.popToRootViewController 回到根控制器

swift 复制代码
navigationController?.popToRootViewController(animated: true)

UITabBarController

UITabBarController = 底部导航栏容器控制器

  • 它是一个容器,专门管理多个并列页面
  • 屏幕底部那一排可点击的按钮,就是它自带的 UITabBar
  • 点击按钮 → 自动切换不同页面

关键点:

  • 永远只显示一个子页面(当前选中的)
  • 子页面之间是并列关系,不是栈
  • 每个子页面最好套一层导航控制器(UINavigationController),这样才能 push 跳转

/////////////////////////////////////////////////////////////////////////////////////////////

UIStoryboard

UIStoryboard(name:bundle:) 是 iOS 中用来加载 Storyboard 文件的初始化方法。

参数:

name: 要加载的 Storyboard 文件名(不带 .storyboard 后缀)

bundle: 要从哪个「资源包」里找这个文件,一般传 nil 表示从当前 App 的主 Bundle 中加载

约束constraint

在 iOS 里,AutoLayout(自动布局)= 用 "约束公式" 代替 frame。

1.写法

swift 复制代码
piece.leadingAnchor.constraint(equalTo: cornerContainer.leadingAnchor, constant: x)
piece.topAnchor.constraint(equalTo: cornerContainer.topAnchor, constant: y)
piece.widthAnchor.constraint(equalToConstant: ...)

这叫 Layout Anchors(锚点约束),是苹果推荐的、最简洁的写法。

最容易混的:equalTo 到底 "等于" 谁?

【谁.锚点】.constraint(equalTo:【和谁.锚点】, constant: 偏移)

左边:我自己(要布局的控件)

equalTo 右边:参照物(父 view 或别的控件)

constant:我相对于参照物的偏移

1.位置约束:leadingAnchor / topAnchor

swift 复制代码
piece.leadingAnchor.constraint(equalTo: cornerContainer.leadingAnchor, constant: x)
  • leadingAnchor = 左边那条线
  • equalTo: 父视图的 leadingAnchor = 和父视图左边对齐
  • constant: x = 向右偏移 x 个点(x 为负就向左)

同理:

  • topAnchor = 上边那条线,constant: y 就是向下偏移 yApple Developer。

一句话:

  • leading + top 就是用来定 "左上角坐标" 的

2.大小约束:widthAnchor / heightAnchor

swift 复制代码
piece.widthAnchor.constraint(equalToConstant: length)
piece.heightAnchor.constraint(equalToConstant: width)
  • equalToConstant: 数值 = 固定宽 / 高,不依赖别的 view。
  • 横线:width = 长,height = 粗
  • 竖线:width = 粗,height = 长

一句话:

  • width + height 就是用来定 "矩形尺寸" 的

2.关键点

1.关掉 autoresizing(必须!)

swift 复制代码
piece.translatesAutoresizingMaskIntoConstraints = false

意思:不用旧的 frame 布局,全权交给约束。

2.约束要激活

swift 复制代码
// 写法1:单个激活
c.isActive = true

// 写法2:批量激活(推荐)
NSLayoutConstraint.activate([
    piece.leadingAnchor.constraint(...),
    piece.topAnchor.constraint(...)
])

不激活 = 约束只是创建了,没生效。

3.父子关系要先建立

swift 复制代码
cornerContainer.addSubview(piece)

必须先 addSubview,再加约束,否则崩溃。

3.总结

leadingAnchor / topAnchor → 定坐标(x,y)

widthAnchor / heightAnchor → 定宽高

equalTo: → 相对另一个 view

equalToConstant: → 固定数值

必须:translatesAutoresizingMaskIntoConstraints = false + 激活约束。

CAShapeLayer

一、CAShapeLayer 是什么?

CAShapeLayer = 专门用来画矢量图形的图层

  • CAShapeLayer:矢量绘图层(CALayer 子类),只负责渲染形状、线条、颜色
  • UIBezierPath:路径容器,定义点、线、圆、圆弧、多边形等轮廓

和普通 UIView 区别:

  • UIView:靠 frame 画矩形、图片
  • CAShapeLayer:画任意形状(圆、弧、线、多边形、曲线)

二、使用步骤

1.使用UIBezierPath创建路径(path)

2.创建 CAShapeLayer对象layer

3.layer.path = path.cgPath

4.设置颜色、线宽

5.加到视图 layer 上(layer.addSublayer)

swift 复制代码
// 1. 构造路径
let path = UIBezierPath()
// 2. 构造绘图层
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath // 关键:转 CGPath
// 3. 样式配置
shapeLayer.strokeColor = UIColor.xxx.cgColor
shapeLayer.fillColor = UIColor.xxx.cgColor
shapeLayer.lineWidth = 数值
// 4. 添加到视图
view.layer.addSublayer(shapeLayer)

三、CAShapeLayer 最常用属性

1.path

  • 形状路径
  • 必须传 CGPath
  • 用 UIBezierPath 生成
swift 复制代码
shapeLayer.path = path.cgPath

2.strokeColor

  • 线条颜色
  • 必须是 CGColor
swift 复制代码
shapeLayer.strokeColor = UIColor.blue.cgColor

3.fillColor

  • 填充颜色
  • 只想画线,必须设为透明
swift 复制代码
shapeLayer.fillColor = UIColor.clear.cgColor

4.lineWidth

  • 线条宽度(pt)
swift 复制代码
shapeLayer.lineWidth = 4

5.lineCap

  • 线头样式

.butt 默认直角

.round 圆头

.square 方头

swift 复制代码
shapeLayer.lineCap = .round

6.lineJoin

  • 线条拐角样式

.miter 直角

.round 圆角

.bevel 斜角

swift 复制代码
shapeLayer.lineJoin = .round

7.lineDashPattern

  • 画虚线(常用)
swift 复制代码
//→ 实线 5pt + 空 3pt
shapeLayer.lineDashPattern = [5,3]  as [NSNumber]

8.strokeStart / strokeEnd

  • 控制线条画多少
  • 做扫描动画、进度条、路径动画必备

四、UIBezierPath 常用方法(画形状用)

1.基础移动 & 直线(画单条线、折线、L 型)

swift 复制代码
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))    // 抬起画笔,移动到起点
path.addLine(to: CGPoint(x: 50, y: 0))// 画直线
path.addLine(to: CGPoint(x: 50, y: 50))// 折角,组成 L 型

2.圆弧 / 圆形(圆环、圆角拐角、整圆)

① 整圆(快门按钮、圆形图标)

swift 复制代码
let center = CGPoint(x: 40, y: 40) // 圆心
let path = UIBezierPath(
    arcCenter: center,
    radius: 30,        // 圆半径
    startAngle: 0,     // 起始角度(弧度)
    endAngle: 2 * .pi, // 结束角度,2π = 360° 整圆
    clockwise: true    // 是否顺时针绘制
)

clockwise: true:顺时针绘制圆弧

clockwise: false:逆时针绘制圆弧

它决定了画笔从 startAngle 到 endAngle 是往哪个方向走,直接影响圆弧的形状和位置。

② 局部圆弧(做圆角拐角核心)

swift 复制代码
// 画 90° 圆弧(L型拐角圆角)
path.addArc(
    withCenter: CGPoint(x: 20, y: 20), // 圆弧圆心
    radius: 8,                         // 圆角半径
    startAngle: -.pi/2,                // 起始角度
    endAngle: 0,                       // 结束角度
    clockwise: true
)

角度速记(弧度):

0 → 向右

.pi/2 → 向下

.pi → 向左

-.pi/2 → 向上

3.圆角矩形(卡片、带圆角边框)

swift 复制代码
let rect = CGRect(x: 0, y: 0, width: 200, height: 100)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 12)

4.虚线

swift 复制代码
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 20))
path.addLine(to: CGPoint(x: 200, y: 20))

let layer = CAShapeLayer()
layer.path = path.cgPath
layer.lineDashPattern = [4,4] // 实线4pt,间隔4pt

五、CAShapeLayer 使用场景

1.画圆角 L 型角(你现在的扫描框)

直角 → 圆角

用路径 + 圆弧实现

2.画圆环(快门按钮)

多层圆环

填充透明,只画线

3.圆角矩形卡片

比 cornerRadius 更流畅、不耗性能

4.虚线、分隔线

swift 复制代码
lineDashPattern = [4,4]

5.扫描动画、波浪动画、圆弧进度条

靠 strokeEnd 从 0→1 动画

6.任意不规则图形

曲线、箭头、标签气泡、图标

7.带圆角的线条

比如你现在的圆滑边角

UIGraphicsGetCurrentContext

一、核心作用

  • 获取当前的图形上下文(CGContext)
  • 你在draw(_:)里画线条、形状、文字、图片时,必须先拿到这个上下文
  • 本质上是一个全局状态指针,记录当前绘制的画布、画笔样式、坐标系统等信息

二、基础用法(标准场景:UIView 的 draw 方法)

swift 复制代码
override func draw(_ rect: CGRect) {
    // 1. 获取当前上下文(必须在 draw 方法里调用)
    guard let ctx = UIGraphicsGetCurrentContext() else { return }
    
    // 2. 开始绘制
    // 示例:画一个红色圆形
    ctx.setFillColor(UIColor.red.cgColor)
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 100, height: 100))
    ctx.fill()
}

UIGraphicsGetCurrentContext() 就是获取当前 "画布" 的入口,是所有自定义绘制代码的起点,没有它就无法执行任何 Core Graphics 绘制操作。