如何在 Swift 中创建自定义细分控件
How to create a custom segment control in Swift
我想创建一个像屏幕截图中那样工作的段控件。
所选段应根据段标题文本加下划线。我已经搜索过了,但没有找到任何第三方解决方案。
那么如何开发这种类型的段控件呢?
在这里你可以看到底部的线只延伸到选定的线段。
import UIKit
extension UIView {
func constraintsEqualToSuperView() {
if let superview = self.superview {
NSLayoutConstraint.activate(
[
self.topAnchor.constraint(
equalTo: superview.topAnchor
),
self.bottomAnchor.constraint(
equalTo: superview.bottomAnchor
),
self.leadingAnchor.constraint(
equalTo: superview.leadingAnchor
),
self.trailingAnchor.constraint(
equalTo: superview.trailingAnchor
)
]
)
}
}
}
protocol ButtonsViewDelegate: class {
func didButtonTap(buttonView: ButtonsView, index: Int)
}
class ButtonsView: UIView {
fileprivate let stackView = UIStackView()
fileprivate var array = [String]()
fileprivate var buttonArray = [UIButton]()
fileprivate let baseTag = 300
weak var delegate: ButtonsViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupUI () {
setupStackView()
setupButton()
}
convenience init(buttons: [String]) {
self.init()
array = buttons
setupUI()
//selectButton(atIndex: 0)
}
fileprivate func setupStackView() {
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.distribution = .fillEqually
stackView.constraintsEqualToSuperView()
}
fileprivate func setupButton() {
for (i,string) in array.enumerated() {
let button = UIButton()
button.setTitle(string.uppercased(), for: .normal)
// button.backgroundColor = UIColor.lightBackgroundColor().lightened(by: 0.2)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(
self,
action: #selector(buttonClicked(sender:)),
for: .touchUpInside
)
button.setTitleColor(
.black,
for: .normal
)
button.titleLabel?.font = UIFont.systemFont(
ofSize: 14,
weight: UIFont.Weight.bold
)
// let view = UIView.init(frame: CGRect.init(x: 0, y: button.frame.size.height - 1, width: button.frame.size.width, height: 1))
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.clear
view.tag = baseTag + i
button.addSubview(view)
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(
equalTo: button.leadingAnchor
),
view.trailingAnchor.constraint(
equalTo: button.trailingAnchor
),
view.bottomAnchor.constraint(
equalTo: button.bottomAnchor
),
view.heightAnchor.constraint(
equalToConstant: 1
)
])
stackView.addArrangedSubview(button)
buttonArray.append(button)
}
}
func selectButton(atIndex index: Int) {
if index <= buttonArray.count {
buttonClicked(sender: buttonArray[index])
}
}
@objc private func buttonClicked(sender: UIButton) {
for button in buttonArray {
if button == sender {
button.setTitleColor(
UIColor.darkGray,
for: .normal
)
setUpBottomLine(button: button)
}else{
button.setTitleColor(
.black,
for: .normal
)
hideBottomLine(button: button)
}
}
if let index = buttonArray.index(of: sender) {
delegate?.didButtonTap(buttonView: self, index: index)
}
}
private func setUpBottomLine(button: UIButton) {
if let index = buttonArray.index(of: button) {
if let view = button.viewWithTag(baseTag + index) {
view.backgroundColor = UIColor.red
}
}
}
private func hideBottomLine(button: UIButton) {
if let index = buttonArray.index(of: button) {
if let view = button.viewWithTag(baseTag + index) {
view.backgroundColor = .clear
}
}
}
}
//how to use
let durationBtns = ButtonsView(buttons: [
NSLocalizedString(
"day",
comment: ""
),
NSLocalizedString(
"week",
comment: ""
),
NSLocalizedString(
"month",
comment: ""
),
NSLocalizedString(
"year",
comment: ""
)
])
durationButtons = durationBtns
durationButtons.selectButton(atIndex: 0)
durationBtns.delegate = self
//handle buttton tap
extension viewController: ButtonsViewDelegate {
func didButtonTap(buttonView: ButtonsView, index: Int) {
print(index.description)
}
}
GitHub
中有一个名为 PageMenu
的开源项目。请看,你甚至可以自定义源文件CAPSPageMenu
。
https://github.com/PageMenu/PageMenu
要更新选择发线的宽度,请启用以下 属性。
menuItemWidthBasedOnTitleTextWidth
代码:
let parameters: [CAPSPageMenuOption] = [
...
.menuItemWidthBasedOnTitleTextWidth(true),
....]
// Initialize scroll menu
pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: self.view.frame.height), pageMenuOptions: parameters)
请在项目中尝试 PageMenuDemoStoryboard
demo 并更新 parameters
如上代码所示。
我想创建一个像屏幕截图中那样工作的段控件。 所选段应根据段标题文本加下划线。我已经搜索过了,但没有找到任何第三方解决方案。 那么如何开发这种类型的段控件呢?
在这里你可以看到底部的线只延伸到选定的线段。
import UIKit
extension UIView {
func constraintsEqualToSuperView() {
if let superview = self.superview {
NSLayoutConstraint.activate(
[
self.topAnchor.constraint(
equalTo: superview.topAnchor
),
self.bottomAnchor.constraint(
equalTo: superview.bottomAnchor
),
self.leadingAnchor.constraint(
equalTo: superview.leadingAnchor
),
self.trailingAnchor.constraint(
equalTo: superview.trailingAnchor
)
]
)
}
}
}
protocol ButtonsViewDelegate: class {
func didButtonTap(buttonView: ButtonsView, index: Int)
}
class ButtonsView: UIView {
fileprivate let stackView = UIStackView()
fileprivate var array = [String]()
fileprivate var buttonArray = [UIButton]()
fileprivate let baseTag = 300
weak var delegate: ButtonsViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupUI () {
setupStackView()
setupButton()
}
convenience init(buttons: [String]) {
self.init()
array = buttons
setupUI()
//selectButton(atIndex: 0)
}
fileprivate func setupStackView() {
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.distribution = .fillEqually
stackView.constraintsEqualToSuperView()
}
fileprivate func setupButton() {
for (i,string) in array.enumerated() {
let button = UIButton()
button.setTitle(string.uppercased(), for: .normal)
// button.backgroundColor = UIColor.lightBackgroundColor().lightened(by: 0.2)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(
self,
action: #selector(buttonClicked(sender:)),
for: .touchUpInside
)
button.setTitleColor(
.black,
for: .normal
)
button.titleLabel?.font = UIFont.systemFont(
ofSize: 14,
weight: UIFont.Weight.bold
)
// let view = UIView.init(frame: CGRect.init(x: 0, y: button.frame.size.height - 1, width: button.frame.size.width, height: 1))
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.clear
view.tag = baseTag + i
button.addSubview(view)
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(
equalTo: button.leadingAnchor
),
view.trailingAnchor.constraint(
equalTo: button.trailingAnchor
),
view.bottomAnchor.constraint(
equalTo: button.bottomAnchor
),
view.heightAnchor.constraint(
equalToConstant: 1
)
])
stackView.addArrangedSubview(button)
buttonArray.append(button)
}
}
func selectButton(atIndex index: Int) {
if index <= buttonArray.count {
buttonClicked(sender: buttonArray[index])
}
}
@objc private func buttonClicked(sender: UIButton) {
for button in buttonArray {
if button == sender {
button.setTitleColor(
UIColor.darkGray,
for: .normal
)
setUpBottomLine(button: button)
}else{
button.setTitleColor(
.black,
for: .normal
)
hideBottomLine(button: button)
}
}
if let index = buttonArray.index(of: sender) {
delegate?.didButtonTap(buttonView: self, index: index)
}
}
private func setUpBottomLine(button: UIButton) {
if let index = buttonArray.index(of: button) {
if let view = button.viewWithTag(baseTag + index) {
view.backgroundColor = UIColor.red
}
}
}
private func hideBottomLine(button: UIButton) {
if let index = buttonArray.index(of: button) {
if let view = button.viewWithTag(baseTag + index) {
view.backgroundColor = .clear
}
}
}
}
//how to use
let durationBtns = ButtonsView(buttons: [
NSLocalizedString(
"day",
comment: ""
),
NSLocalizedString(
"week",
comment: ""
),
NSLocalizedString(
"month",
comment: ""
),
NSLocalizedString(
"year",
comment: ""
)
])
durationButtons = durationBtns
durationButtons.selectButton(atIndex: 0)
durationBtns.delegate = self
//handle buttton tap
extension viewController: ButtonsViewDelegate {
func didButtonTap(buttonView: ButtonsView, index: Int) {
print(index.description)
}
}
GitHub
中有一个名为 PageMenu
的开源项目。请看,你甚至可以自定义源文件CAPSPageMenu
。
https://github.com/PageMenu/PageMenu
要更新选择发线的宽度,请启用以下 属性。
menuItemWidthBasedOnTitleTextWidth
代码:
let parameters: [CAPSPageMenuOption] = [
...
.menuItemWidthBasedOnTitleTextWidth(true),
....]
// Initialize scroll menu
pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: self.view.frame.height), pageMenuOptions: parameters)
请在项目中尝试 PageMenuDemoStoryboard
demo 并更新 parameters
如上代码所示。