使用View自定义SegmentControl
为了能让大家更好的学习自定义控件,我将详细讲解每一步,闲话少说进入今天的主题!
基本步骤及每步的思想如下:
首先我们要确定我们要实现的功能及效果,"分段选择器"类似于系统的UISegmentControl
效果图如下:
(被选中的水果选项其字体变为橙色下方的橙色线条也移动到相应的位置)
首先,我们需要考虑用哪些系统控件来实现这样的效果,看图分析,我们需要(1)创建底部视图,(2)水果标签及(3)标签下的黄色细线,综合考虑,我们(1)使用UIScrollView,(2)使用UILabel,(3)使用UIView
1.创建一个新类,基类选择UIView
2.实现init(frame:)方法
class MangoJPageViewControl: UIView {
init(frame : CGRect){
super.init(frame : frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
3.初始化控件 设置属性 定义协议 设置代理
使用代理 获得所选标签
// MARK:- 代理1
protocol PageTitleViewDelegate :class{
func pageTitleView(_ titleView : MCustomPageTitleView, selectedIndex index : Int)
}
class MangoJPageViewControl: UIView {
//MARK:- 代理2
weak var delegate : PageTitleViewDelegate?
fileprivate var titles :[String] = []
fileprivate lazy var titleLabels : [UILabel] = [UILabel]()
fileprivate lazy var scrollView:UIScrollView = UIScrollView()
fileprivate lazy var scrollLine : UIView = UIView()
fileprivate var currentLabelIndex :Int = 0
init(frame: CGRect,titles:[String]) {
super.init(frame: frame)
self.titles = titles
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
4.设置控件布局
extension MangoJPageViewControl{
func setupUI() {
setupScrollView()
setupTitleLabels()
setupLineView()
setupBottomAndLine()
}
fileprivate func setupScrollView() {
scrollView.showsHorizontalScrollIndicator = false
scrollView.frame = bounds
scrollView.scrollsToTop = false
scrollView.isPagingEnabled = false
scrollView.bounces = false
}
fileprivate func setupTitleLabels(){
let label_W :CGFloat = frame.width / CGFloat(titles.count)
let label_H :CGFloat = frame.height - kScrollLineH
let label_Y :CGFloat = 0
for (index,title) in titles.enumerated() {
let label = UILabel()
label.text = title
label.tag = index
label.font = UIFont.systemFont(ofSize: 15)
label.textColor = UIColor(r: kNormalColor.0, g: kNormalColor.1, b: kNormalColor.2)
label.textAlignment = .center
let label_X :CGFloat = label_W * CGFloat(index)
label.frame = CGRect(x: label_X, y: label_Y, width: label_W, height: label_H)
scrollView.addSubview(label)
titleLabels.append(label)
//给label添加手势
label.isUserInteractionEnabled = true
let tapGes = UITapGestureRecognizer(target: self, action: #selector(titleLabelClick))
label.addGestureRecognizer(tapGes)
}
}
fileprivate func setupLineView(){
scrollLine.backgroundColor = UIColor.orange
//设置默认选中的第一个
guard let firstLabel = titleLabels.first else { return }
firstLabel.textColor = UIColor(r: kSelectColor.0, g: kSelectColor.1, b: kSelectColor.2)
scrollView.addSubview(scrollLine)
scrollLine.frame = CGRect(x: firstLabel.frame.origin.x+firstLabel.frame.width*0.1, y: frame.height-kScrollLineH, width: firstLabel.frame.width*0.8, height: kScrollLineH)
}
fileprivate func setupBottomAndLine(){
let bottomLine = UIView()
bottomLine.backgroundColor = UIColor.lightGray
bottomLine.frame = CGRect(x: 0, y: frame.height - lineH, width: frame.width, height: lineH)
addSubview(bottomLine)
}
}
extension MangoJPageViewControl{
@objc fileprivate func titleLabelClick(tap:UITapGestureRecognizer){
guard let currentLabel = tap.view as? UILabel else {
return
}
if currentLabel.tag == currentLabelIndex {
return
}
let oldLabel = titleLabels[currentLabelIndex]
currentLabel.textColor = UIColor(r: kSelectColor.0, g: kSelectColor.1, b: kSelectColor.2)
oldLabel.textColor = UIColor(r: kNormalColor.0, g: kNormalColor.1, b: kNormalColor.2)
currentLabelIndex = currentLabel.tag
let scrollLinePosition = currentLabel.frame.origin.x
scrollLine.frame.size.width = currentLabel.frame.width * 0.8
UIView.animate(withDuration: 0.2, animations: {
self.scrollLine.frame.origin.x = scrollLinePosition//X
})
//MARK:- 代理3
delegate?.pageTitleView(self, selectedIndex: currentLabelIndex)
}
}
//公开给外面调用的FUNC
extension MangoJPageViewControl{
func setTitleWithProgress(_ progress:CGFloat,sourceIndex : Int,targetIndex : Int){
let sourceLabel = titleLabels[sourceIndex]
let targetLabel = titleLabels[targetIndex]
let moveTotalX = targetLabel.frame.origin.x - sourceLabel.frame.origin.x
let moveX = moveTotalX * progress
scrollLine.frame.origin.x = sourceLabel.frame.origin.x + sourceLabel.frame.width*0.1 + moveX
let colorDelta = (kSelectColor.0 - kNormalColor.0,kSelectColor.1 - kNormalColor.1,kSelectColor.2 - kNormalColor.2)
sourceLabel.textColor = UIColor(r: kSelectColor.0 - colorDelta.0 * progress, g: kSelectColor.1 - colorDelta.1 * progress, b: kSelectColor.2 - colorDelta.2 * progress)
targetLabel.textColor = UIColor(r: kNormalColor.0 + colorDelta.0 * progress, g: kNormalColor.1 + colorDelta.1 * progress, b: kNormalColor.2 + colorDelta.2 * progress)
//
currentLabelIndex = targetIndex
}
}
自定义控件完成
简单的调用如下:
import UIKit
class ViewController: UIViewController,PageTitleViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let pageView :MangoJPageViewControl
let titles = ["香蕉","苹果","橘子","大鸭梨"]
pageView = MangoJPageViewControl(frame: CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 40), titles: titles)
pageView.delegate = self
view.addSubview(pageView)
}
//设置代理方法
func pageTitleView(_ titleView: MangoJPageViewControl, selectedIndex index: Int) {
//可以获取到所选项的index
}
}