首页 > 解决方案 > Swift iOS - 如何实现不同字体大小的多行SegmentedControl

问题描述

我有 2 行的 SegmentedControl 使用:

// AppDelegate  
UILabel.appearanceWhenContainedInInstancesOfClasses([UISegmentedControl.self]).numberOfLines = 0

在此处输入图像描述

问题是线条字体的大小完全相同。我需要更改每一行的 titleTextAttributes 以使第二行小于第一行。

我知道我可以将它用于两条线:

segmentedControl.setTitleTextAttributes([NSAttributedStringKey.font : UIFont.systemFont(ofSize: 17))

我怎样才能做到这一点?

// The SegmentedControl
let segmentedControl: UISegmentedControl = {
    let segmentedControl = UISegmentedControl(items: ["Pizza\n123.1K", "Turkey Burgers\n456.2M", "Gingerale\n789.3B"])
    segmentedControl.translatesAutoresizingMaskIntoConstraints = false
    segmentedControl.tintColor = UIColor.orange
    segmentedControl.backgroundColor = .white
    segmentedControl.isHighlighted = true
    segmentedControl.addTarget(self, action: #selector(selectedIndex(_:)), for: .valueChanged)
    return segmentedControl
}()

标签: iosswiftnsattributedstringuisegmentedcontrol

解决方案


您需要通过继承 UIControl 来创建自定义控件。这是一个简单的例子:

CustomSegmentedControl.swift

import UIKit
import CoreImage

public class CustomSegmentedControl: UIControl {

    public var borderWidth: CGFloat = 1.0
    public var selectedSegementIndex = 0 {
        didSet {
            self.styleButtons()
        }
    }

    public var numberOfSegments: Int {
        return self.segments.count
    }

    private var buttons: [UIButton] = []
    private var stackView = UIStackView(frame: CGRect.zero)
    private var stackBackground = UIView(frame: CGRect.zero)
    private var segments: [NSAttributedString] = [] {
        didSet {
            for subview in self.stackView.arrangedSubviews {
                subview.removeFromSuperview()
            }
            self.buttons = []
            for i in 0..<segments.count {
                let segment = segments[i]
                self.createAndAddSegmentButton(title: segment)
            }
            self.styleButtons()
        }
    }

    override public init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    private func setup() {

        self.addSubview(stackBackground)
        self.stackBackground.constrainToBounds(of: self)
        self.addSubview(stackView)
        self.stackView.constrainToBounds(of: self)
        self.stackView.axis = .horizontal
        self.stackView.distribution = .fillEqually
        self.stackView.spacing = borderWidth

        self.layer.cornerRadius = 5.0
        self.layer.borderWidth = borderWidth
        self.clipsToBounds = true
        self.stackBackground.backgroundColor = tintColor
    }

    private func createAndAddSegmentButton(title: NSAttributedString) {
        let button = createSegmentButton(title: title)
        self.buttons.append(button)
        self.stackView.addArrangedSubview(button)
    }

    private func createSegmentButton(title: NSAttributedString) -> UIButton {
        let button = UIButton(frame: CGRect.zero)
        button.titleLabel?.numberOfLines = 0
        button.titleLabel?.textAlignment = .center
        button.setAttributedTitle(title, for: .normal)
        button.addTarget(self, action: #selector(self.actSelected(button:)), for: .touchUpInside)
        return button
    }

    override public var tintColor: UIColor! {
        willSet {
            self.layer.borderColor = newValue.cgColor
            self.stackBackground.backgroundColor = newValue
        }
    }

    public func setSegments(_ segments: [NSAttributedString]) {
        self.segments = segments
    }

    @objc private func actSelected(button: UIButton) {
        guard let index = self.buttons.index(of: button) else {
            print("invalid selection should never happen, would want to handle better than this")
            return
        }
        self.selectedSegementIndex = index
        self.sendActions(for: .valueChanged)
    }

    private func styleButtons() {
        for i in 0..<self.buttons.count {
            let button = self.buttons[i]
            if i == selectedSegementIndex {
                button.backgroundColor = self.tintColor
                button.titleLabel?.textColor = self.backgroundColor ?? .white
            } else {
                button.backgroundColor = self.backgroundColor
                button.titleLabel?.textColor = self.tintColor
            }
        }
    }
}

extension UIView {
    func constrainToBounds(of view: UIView) {
        self.translatesAutoresizingMaskIntoConstraints = false
        let attrs: [NSLayoutAttribute] = [.leading, .top, .trailing, .bottom]
        let constraints = attrs.map { (attr) -> NSLayoutConstraint in
            return NSLayoutConstraint(item: self,
                                      attribute: attr,
                                      relatedBy: .equal,
                                      toItem: view,
                                      attribute: attr,
                                      multiplier: 1.0,
                                      constant: 0)
        }
        NSLayoutConstraint.activate(constraints)
    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var customSegment: CustomSegmentedControl!
    private var segments: [NSAttributedString] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.customSegment.backgroundColor = .white
        self.customSegment.tintColor = .orange

        let pizza = createText(title: "Pizza", subTitle: "123K")
        let turkey = createText(title: "Turkey Burgers", subTitle: "456.2M")
        let gingerAle = createText(title: "Gingerale", subTitle: "789.3B")
        self.segments = [pizza, turkey, gingerAle]
        self.customSegment.setSegments(self.segments)

        self.customSegment.addTarget(self, action: #selector(self.segmentSelectionChanged(control:)), for: .valueChanged)
    }

    @objc private func segmentSelectionChanged(control: CustomSegmentedControl) {
        let segment = self.segments[control.selectedSegementIndex]
        print("selected segment = \(segment.string)")
    }

    func createText(title: String, subTitle: String) -> NSAttributedString {
        let titleStr = NSMutableAttributedString(string: "\(title)\n", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)])
        let subStr = NSAttributedString(string: subTitle, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 10)])
        titleStr.append(subStr)
        return titleStr
    }

}

在此处输入图像描述


推荐阅读