iOS 之控件外观设置

iOS 的控件有很多种, 每种的设置方式也不相同. 对我来说, 有些控件的 color, 背景, 内容偏移等设置经常容易混淆, 这里记录下每种控件的简单使用, 方便实际运用时快速查阅

himg

UIImageView

1
2
3
4
5
6
7
8
9
10
let image = UIImage(systemName: "mic.fill")
let imageView = UIImageView()
// aspectFill 固定比例将两侧填充到 imageView 的边缘, 最后填充的一侧会超出 imageView
// aspectFit 固定比例将 image 的一侧填充到 imageView 中即停止填充
// scaleToFill 不管比例, 将 image 的两侧完全填充到 imageView 的两侧, 因此 image 会被拉伸
imageView.contentMode = . scaleAspectFit
imageView.image = image
imageView.backgroundColor = .red
imageView.frame = CGRect(x: 30, y: 100, width: 400, height: 200)
self.view.addSubview(imageView)

UILabel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
let label = UILabel(frame: CGRect(x: 20, y: 20, width: 200, height: 30)) // 创建一个标签
label.text = "我是一个普通的便签控件" // 为 lable 设置文本
label.textColor = UIColor.red // 设置字体颜色
label.shadowColor = UIColor.green // 设置阴影颜色
label.shadowOffset = CGSize(width: 2, height: 2) // 设置阴影偏移
label.textAlignment = NSTextAlignment.center // 设置文本对齐方式(label 没有内距缩进选项)
label.font = UIFont.boldSystemFont(ofSize: 20) // 设置 label 的字体
label.adjustsFontSizeToFitWidth = true // 文本超过宽度时, 允许缩小 label 宽度
label.minimumScaleFactor = 0.8 // 文本超过宽度时, 允许的最小缩小系数
label.numberOfLines = 7 // label 的最大可显示行数(是最大, 不是一定. 即如果以 label 的宽度能根据现有字体大小在单行显示全部的话, 那么 label 就只会显示单行)
self.view.addSubview(label) // 将其添加到当前视图上

let label2 = UILabel(frame: CGRect(x: 20, y: 290, width: 200, height: 30))
let attri = NSMutableAttributedString(string: "我是个性化文本")
attri.addAttributes(
[
NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 20), // 也可以用 UIFont(name: "PingFang SC", size: 10)!
NSAttributedString.Key.foregroundColor: UIColor.red
],
range: NSRange(location: 0, length: 2))
label.attributedText = attri
self.view.addSubview(label2)

// 一个 label 中实现多个字体多个颜色
let label6 = UILabel(frame: CGRect(x:20, y 20, width: 300, height: 50))
let attrString6 = NSMutableAttributedString(string: "登录即代表阅读并同意服务协议和隐私协议")
label6.numberOfLines = 0
let attr6: [NSAttributedString.Key : Any] = [
.font: UIFont(name: "PingFang SC", size: 12)!,
.foregroundColor: UIColor(red: 0.2, green: 0.2, blue: 0.2,alpha:1)
]
attrString6.addAttributes(attr6, range: NSRange(location: 0, length: attrString6.length))

let strSubAttr1: [NSMutableAttributedString.Key: Any] = [
.font: UIFont(name: "PingFang-SC-Regular", size: 10)!,
.foregroundColor: UIColor(red: 0.2, green: 0.2, blue: 0.2,alpha:1)
]
attrString6.addAttributes(strSubAttr1, range: NSRange(location: 0, length: 10))

let strSubAttr2: [NSMutableAttributedString.Key: Any] = [
.font: UIFont(name: "PingFang SC", size: 10)!,
.foregroundColor: UIColor(red: 0.35, green: 0.4, blue: 0.85,alpha:1)
]
attrString6.addAttributes(strSubAttr2, range: NSRange(location: 10, length: 4))

let strSubAttr3: [NSMutableAttributedString.Key: Any] = [
.font: UIFont(name: "PingFang SC", size: 10)!,
.foregroundColor: UIColor(red: 0.2, green: 0.2, blue: 0.2,alpha:1)
]
attrString6.addAttributes(strSubAttr3, range: NSRange(location: 14, length: 1))

let strSubAttr4: [NSMutableAttributedString.Key: Any] = [
.font: UIFont(name: "PingFang SC", size: 10)!,
.foregroundColor: UIColor(red: 0.35, green: 0.4, blue: 0.85,alpha:1)
]

attrString6.addAttributes(strSubAttr4, range: NSRange(location: 15, length: 4))

label6.attributedText = attrString6
view.addSubview(label6)

UIButton

UIButton 的特别之处在于其有多个状态, normal, selected, highlighted 等, 因此设置其 titleLabel 的颜色或文字的前提是已经通过 setTitle(title:for:) 确定了 titleLabel 的状态, 否则设置是无效的
UIButton 内部有label 与 imageView, 默认情况下 imageView 在左, label 在右, 没什么简便的方法可以改变顺序, 因此如果设计要求按钮有图标且文字, 同时对布局有硬性要求, 那么最好不要在 button 内部实现 imageView 与 label. 使用只含 imageView 的 button 外加一个 label 来实现更容易操作

1
2
3
4
5
6
7
8
9
10
11
12
13
let btn = UIButton(type: UIButton.ButtonType.custom)
btn.frame = CGRect(x: 20, y: 340, width: 100, height: 30)
btn.backgroundColor = UIColor.purple
btn.setTitle("标题", for: .normal) // 为 btn 的 titleLabel 设置文本(必须要确定状态, 设置了 normal 后如果不设置其他状态下 label 的话, 默认都是用 normal 的设置)
btn.setImage(UIImage(systemName: "mic"), for: UIControl.State.normal) // 为 btn 设置内容图片
btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 20) // 为文字设置相对于 btn 内 titleLabel 的偏移量
btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 0) // 为图片设置相对于 btn 内 imageView 的偏移量
btn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 20) // 为 btn 的内容设置偏移量(包括内部的 label 与 imageView)
btn.semanticContentAttribute = .forceRightToLeft // 强制 button 的布局顺序从右至左, 即图片在右文字在左
btn.setBackgroundImage(UIImage(systemName: "mic"), for: .normal) // 设置 btn 背景图片
btn.contentHorizontalAlignment = .left // 让 btn 中的内容框水平左对齐
btn.contentVerticalAlignment = .center // 让 btn 中的内容垂直居中对齐
self.view.addSubview(btn)

UITableView

UITableView 中有一个主 headerView, 有多个 section, 每个 section 都有一个独立的 section headerView
UITableView 的 cell 可以自定义背景颜色, 如果不自定义背景颜色, 那么将会看到 UITableView 的 backgroundColor, 如果 UITableView 没有自定义 backgroundColor, 那么将为白色.

1
2
3
4
5
6
7
8
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = UIColor(hex: 0x232337) // 下拉刷新时, 在 section 与主 header 中露出的颜色就是 backgroundColor, 如果tableview 的 cell 没有定义 cell.backgroundColor, 那么 tableView.backgroundColor 就会是 cell 的背景颜色
tableView.tintColor = .red // 如果对 tableview 中的内容没有自定义的话, 那么系统会将内容颜色配置为 tintColor
tableView.headerView(forSection: 1)?.contentView.backgroundColor // 设置 section 的 headerView 的 backgroundColor
let customHeaderView = HLCustomHeaderView()
customHeaderView.backgroundColor = .red
tableView.tableHeaderView = customeHeaderView // 自定义添加 tableview 的主 headerView
tableView.separatorStyle = .none // 取消表格的间隔显示 separatorStyle
  • 有时约束 tableviewvcview 底部时会导致 tableview 的某些 row 不能被正确点击识别, 此时可以将 tableview 的底部对齐到 vcview 底部上方一个像素

UITableViewCell

1
2
3
4
5
6
7
8
// 设置 cell 的背景颜色
cell.contentView.backgroundColor = .red
cell.selectionStyle = .none // 控制点击 cell 后的样式(不设置的话会在点击时有白色边框)

// 设置 cell 被按下时显示的颜色, 注意 contentView 不能设置 backgroundColor, 且 selectionStyle 不能为 .none
let selectedBgView = UIView()
selectedBgView.backgroundColor = .red
cell.selectedBackgroundView = selectedBgView

UICollectionView

1
2
3
4
5
6
7
8
9
10
11
12
13
let flowLayout = UICollectionViewFlowLayout()
flowLayout.minimumLineSpacing = 20.0 // 设置最小线间距, 对于横向排列的 item 来说, 是横向间距, 对于纵向排列的 item 来说, 是纵向间距
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 13, bottom: 0, right: 13) // 每个 section 的内缩值
flowLayout.itemSize = CGSize(width: width, height: 109.0) // 每个 item 的尺寸
collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
collectionView.backgroundColor = UIColor(hex: 0x232337)
collectionView.ck.registerCell(type: MarketIndexCell.self)
collectionView.delegate = self
collectionView.dataSource = self
self.addSubview(collectionView)
collectionView.snp.makeConstraints {
$0.edges.equalToSuperview()
}

UINavigationBar & UINavigationItem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 导航列显示为大标题. 需要确保方法位于func viewDidLoad() 中(在 storyboard 中也可设置达到同样效果)
// 若希望同一 navigationController 下所有视图控制器皆为大标题, 可这样设置:
navigationController?.navigationBar.prefersLargeTitles = true

// 若只是单一视图控制器需要设置大标题或普通, 可这样设置(或者在单一视图控制器的storyboard中添加navigation Item然后对其设置为小标题) (只有开启了preferLargeTitle的情况下再修改Mode才是有意义的!)
navigationItem.largeTitleDisplayMode = .never

// 自定义导览列文字属性(颜色,字体)(此设置需配合大标题使用)
let customFont = UIFont(name: "Rubik-Medium", size: 40.0)
let customColor = UIColor(red: 231 / 255, green: 76 / 255, blue: 60 / 255, alpha: 1.0)
navigationController?.navigationBar.largeTitleTextAttributes = [
NSAttributedString.Key.foregroundColor: customColor,
NSAttributedString.Key.font: customFont!
]

navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:UIColor.white] // 自定义导航条文字颜色(此设置无需配合大标题使用)
navigationController?.navigationBar.barTintColor = .white // 自定义导航条背景颜色
navigationController?.navigationBar.tintColor = UIColor.orange // 前景色, 按钮颜色(就是 navigationItem 的颜色)
// 导航条背景是否透明, 很重要, 会影响 MJRefresh 的 header 的顶部是约束到屏幕顶部(被 navigationBar 覆盖)还是 navigationBar 底部
// 如果不设置此项的话设置约束到父视图的 topMargin 也可以使 MFRefresh 的 header 贴于 navigationBar 下方
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) // 自定义导览列为背景透明
navigationController?.navigationBar.shadowImage = UIImage()

tableView.contentInsetAdjustmentBehavior = .never // 自定义导航列显示为透明后内容自动补充至余下空间内(仅表格视图)

// 自定义“返回按钮”的图标, 将代码插入AppDelegate文件的didFinishLaunching方法中
let backButtonImage = UIImage(named: "back")
UINavigationBar.appearance().backIndicatorImage = backButtonImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backButtonImage

// 滑动时隐藏导览列或不隐藏导览列, storyboard中只能设置全局, 若想针对某一视图控制器设置, 需在对应视图控制器中添加代码(且必须置于viewWillAppear方法中)
// 滑动时隐藏导览列
navigationController?.hidesBarsOnSwipe = true

// 滑动时不隐藏导览列
navigationController?.hidesBarsOnSwipe = false
navigationController?.setNavigationBarHidden(false, animated: true)

// 配置 navigationbar 的按钮(本例为右侧, 左侧同理)
let refreshBtn = UIButton(frame: .zero)
refreshBtn.setImageForAllStates(UIImage(named: "refresh")!)
let refreshItem = UIBarButtonItem(customView: refreshBtn)

let gap = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
gap.width = 20

let searchBtn = UIButton(frame: .zero)
searchBtn.setImageForAllStates(UIImage(named: "search")!)
let searchItem = UIBarButtonItem(customView: searchBtn)

navigationItem.title = "test" // 设置 navigationItem 的标题

navigationItem.rightBarButtonItems = [refreshItem, gap, searchItem]

segment

1
2
3
4
5
6
7
8
9
10
11
12
let segmentedControl1 = UISegmentedControl(items: ["按钮1", "按钮2", "按钮3", "按钮4"]) // 创建分部控制器实例
segmentedControl1.frame = CGRect(x: 100, y: 300, width: 200, height: 30) // 设置属性
segmentedControl1.tintColor = UIColor.blue // 设置染色
segmentedControl1.isMomentary = false // 设置按下后是否自动弹回
segmentedControl1.insertSegment(withTitle: "按钮5", at: 0, animated: true) // 插入新的item(文字)
segmentedControl1.insertSegment(with: UIImage(named: "image"), at: 1, animated: true) // 插入新的item(图片)
segmentedControl1.removeSegment(at: 0, animated: true) // 删除某个位置的segment
segmentedControl1.setImage(UIImage(named: "image")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal), forSegmentAt: 1) // 修改某个item的图片
segmentedControl1.setTitle("nwe", forSegmentAt: 0) // 修改某个item的标题
segmentedControl1.setWidth(8, forSegmentAt: 0) // 为segmentf每个按钮分配不同的宽度
segmentedControl1.apportionsSegmentWidthsByContent = true // 为segment每个按钮分配自定义宽度
self.view.addSubview(segmentedControl1)

UISlider

1
2
3
4
5
6
7
8
9
10
11
let slider1 = UISlider(frame: CGRect(x: 20, y: 100, width: 280, height: 30))
slider1.maximumValue = 10 // 设置滑块控件最大值
slider1.minimumValue = 0 // 设置滑块控件最小值
slider1.value = 5 // 设置滑块默认值
slider1.minimumTrackTintColor = UIColor.red // 设置滑块左侧颜色
slider1.maximumTrackTintColor = UIColor.green // 设置滑块右侧颜色
slider1.thumbTintColor = UIColor.blue // 设置滑动按钮颜色
slider1.setThumbImage(UIImage(named: "image"), for: UIControl.State.normal) // 设置滑块图片
slider1.setMaximumTrackImage(UIImage(named: "image"), for: UIControl.State.normal) // 设置滑块左侧进度图片
slider1.setMinimumTrackImage(UIImage(named: "image"), for: UIControl.State.normal) // 设置滑动块右侧进度图片
self.view.addSubview(slider1)

UISearchBar

1
2
3
4
5
6
7
8
9
10
11
12
13
let searchBar1 = UISearchBar(frame: CGRect(x: 20, y: 300, width: 280, height: 30))
searchBar1.searchBarStyle = UISearchBar.Style.minimal // 设置搜索栏风格
searchBar1.barTintColor = UIColor.red // 设置搜索框背景颜色
searchBar1.backgroundImage = UIImage(named: "image") // 设置搜索框背景图片
searchBar1.placeholder = "请输入要搜索的文字" // 设置搜索栏用户提示文字
searchBar1.prompt = "搜索" // 设置搜索栏标题
searchBar1.showsCancelButton = true // 显示搜索栏的取消按钮
searchBar1.showsBookmarkButton = true // 显示搜索栏的书库按钮
searchBar1.showsSearchResultsButton = true // 显示搜索栏的显示结果按钮
searchBar1.showsScopeBar = true // 显示控件的附件视图
searchBar1.scopeButtonTitles = ["女鞋", "男装", "男鞋", "女装", "童装"] // 设置附件视图的按钮个数和标题
searchBar1.selectedScopeButtonIndex = 0 // 设置搜索框的默认选中的附件视图按钮
self.view.addSubview(searchBar1) // 添加到当前视图

UISwitch

1
2
3
4
5
6
7
let swi = UISwitch()
swi.center = CGPoint(x: 100, y: 100) // 设置控件位置
swi.onTintColor = UIColor.green // 设置开启状态颜色
swi.tintColor = UIColor.red // 设置普通状态颜色
swi.thumbTintColor = UIColor.purple // 设置开关滑块颜色
swi.isOn = true // 设置开关初始状态
self.view.addSubview(swi) // 添加到当前视图

PageControl

1
2
3
4
5
6
7
let pageControl1 = UIPageControl(frame: CGRect(x: 20, y: 100, width: 280, height: 30))
pageControl1.numberOfPages = 10 // 设置总页数
pageControl1.backgroundColor = UIColor.red // 设置控制器背景颜色
pageControl1.pageIndicatorTintColor = UIColor.green // 设置页块背景颜色
pageControl1.currentPageIndicatorTintColor = UIColor.blue // 设置当前页块背景颜色
pageControl1.currentPage = 3 // 设置当前页码
self.view.addSubview(pageControl1)

UIDatePicker

1
2
3
let datePicker1 = UIDatePicker(frame: CGRect(x: 20, y: 100, width: 280, height: 200))
datePicker1.datePickerMode = UIDatePicker.Mode.countDownTimer
self.view.addSubview(datePicker1)

UIStepper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 创建步进器并设置样式
let stepper1 = UIStepper(frame: CGRect(x: 100, y: 300, width: 0, height: 0))
// 设置步进器颜色
stepper1.tintColor = UIColor.green
// 设置步进器最小值
stepper1.minimumValue = 0
// 设置步进器最大值
stepper1.maximumValue = 10
// 设置步进器默认值
stepper1.stepValue = 1
// 设置步进器按下不松开可连续增加
stepper1.isContinuous = true
// 设置步进器按下不松开其值可连续增加
stepper1.autorepeat = true
// 设置步进器到达终点后自动复位
stepper1.wraps = true
// 设置步进器背景图片
stepper1.setBackgroundImage(UIImage(named: "image"), for: UIControl.State.normal)
// 设置步进器分割线图片
stepper1.setDividerImage(UIImage(named: "image"), forLeftSegmentState: UIControl.State.normal, rightSegmentState: UIControl.State.normal)
// 设置步进器增加按钮图片
stepper1.setIncrementImage(UIImage(named: "image"), for: UIControl.State.normal)
// 设置步进器减少按钮图片
stepper1.setDecrementImage(UIImage(named: "image"), for: UIControl.State.normal)
self.view.addSubview(stepper1)

UIProgressView

1
2
3
4
5
6
7
8
let progressView1 = UIProgressView(progressViewStyle: UIProgressView.Style.default)
progressView1.frame = CGRect(x: 20, y: 100, width: 280, height: 10)
progressView1.progress = 0.5 // 设置进度条当前进度
progressView1.progressTintColor = UIColor.green // 设置已走过进度条的颜色
progressView1.trackTintColor = UIColor.red // 设置未走过进度的进度条颜色
progressView1.progressImage = UIImage(named: "image") // 设置已走过进度的进度条图案
progressView1.trackImage = UIImage(named: "image") // 设置未走过进度的进度条图案
self.view.addSubview(progressView1)

UIActivityIndicatorView

1
2
3
4
5
let activity1 = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.whiteLarge) // 创建指示器并设置指示器样式
activity1.color = UIColor.green // 重定义指示器颜色
activity1.center = self.view.center // 设置指示器位置
activity1.startAnimating() // 开始播放
self.view.addSubview(activity1)