自定义分段控件不切换视图

Custom Segmented Control Not Switching Views

我做了一个自定义的 UIControl:

import UIKit

    @IBDesignable class FeedViewSC: UIControl {

    fileprivate var labels = [UILabel]()
    var thumbView = UIView()

    var items: [String] = ["Tab1", "Tab2"] {
        didSet {
            setupLabels()
        }

    }

    var selectedIndex : Int = 0 {
        didSet{
            displayNewSelectedIndex()
        }
    }

    @IBInspectable var font : UIFont! = UIFont.systemFont(ofSize: 13) {
        didSet {
            setFont()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    func setupView() {

        layer.cornerRadius = 5
        layer.borderColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1).cgColor
        layer.borderWidth = 2

        backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1)

        setupLabels()

        insertSubview(thumbView, at: 0)

    }


    func setupLabels() {
        for label in labels {
            label.removeFromSuperview()
        }

        labels.removeAll(keepingCapacity: true)

        for index in 1...items.count {
            let label = UILabel(frame: CGRect.zero)
            label.text = items[index-1]
            label.textAlignment = .center
            label.font = UIFont(name: "Nunito",size: 17)
            label.textColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
            self.addSubview(label)
            labels.append(label)
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        var selectFrame = self.bounds
        let newWidth = selectFrame.width / CGFloat(items.count)
        selectFrame.size.width = newWidth
        thumbView.frame = selectFrame
        thumbView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
        thumbView.layer.cornerRadius = 5

        let labelHeight = self.bounds.height
        let labelWidth = self.bounds.width / CGFloat(labels.count)

        for index in 0...labels.count - 1 {

            let label = labels[index]

            let xPosition = CGFloat(index) * labelWidth
            label.frame = CGRect(x: xPosition, y: 0, width: labelWidth, height: labelHeight)
        }

    }

    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        let location = touch.location(in: self)

        var calculatedIndex: Int?
        for (index, item) in labels.enumerated() {
            if item.frame.contains(location){
                calculatedIndex = index
            }
        }
        if calculatedIndex != nil {
            selectedIndex = calculatedIndex!
            sendActions(for: .valueChanged)
        }

        return false

    }


    func displayNewSelectedIndex (){

        if(self.selectedIndex == -1){
            self.selectedIndex = self.items.count-1
        }

        let label = labels[selectedIndex]


        UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.90, initialSpringVelocity: 0.8, options: [], animations: {

            self.thumbView.frame = label.frame

        }, completion: nil)
    }

    func setFont(){
        for item in labels {
            item.font = font
        }
    }

}

我将它嵌入到我的 ViewController 中并尝试让它以编程方式在两个视图之间切换:

import UIKit

    class FeedViewController: UIViewController {

    let feedViewSC = FeedViewSC()

    let firstView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.red
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    let secondView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.blue
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    let (width, height) = UIScreen.main.bounds.wh

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white
        view.addSubview(firstView)
        view.addSubview(secondView)

        setupContainerViews()

        firstView.isHidden = false
        secondView.isHidden = true

        myTravel.selectedIndex = 0

        let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
        feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]

        self.navigationController?.navigationBar.addSubview(feedControl)
        feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
    }

    func segmentedControlSwitch(_ sender: FeedViewSC) {
        switch feedViewSC.selectedIndex {

        case 0:
            firstView.isHidden = false
            secondView.isHidden = true

        case 1:
            firstView.isHidden = true
            secondView.isHidden = false


        default:
            break;
        }
    }

    func setupContainerViews() {

        firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
        firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
        firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

        secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
        secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
        secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

    }

    override func viewDidAppear(_ animated: Bool) {
        let img = UIImage()
        self.navigationController?.navigationBar.shadowImage = img
        self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

extension CGRect {
    var wh: (w: CGFloat, h: CGFloat) {
        return (size.width, size.height)
    }
}

我不确定我在做什么错了。由于某种原因,代码不会在 firstView 和 secondView 之间切换。目前,它只是显示第一个视图。请记住,我是在没有情节提要的情况下以编程方式进行的。

问题似乎出现在 segmentedControlSwitch 方法中。您应该在 switch case 中使用 sender 而不是可能未初始化的局部变量。

func segmentedControlSwitch(_ sender: myTripsSC) {
    switch sender.selectedIndex {

    case 0:
        firstView.isHidden = false
        secondView.isHidden = true

    case 1:
        firstView.isHidden = true
        secondView.isHidden = false


    default:
        break;
    }
}

编辑: 你的 vc 应该是这样的:

import UIKit

class FeedViewController: UIViewController {

let feedViewSC = FeedViewSC()

let firstView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.red
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let secondView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.blue
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let (width, height) = UIScreen.main.bounds.wh

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.white
    view.addSubview(firstView)
    view.addSubview(secondView)

    setupContainerViews()

    firstView.isHidden = false
    secondView.isHidden = true

    //myTravel.selectedIndex = 0

    let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
    feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]

    self.navigationController?.navigationBar.addSubview(feedControl)
    feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
}

func segmentedControlSwitch(_ sender: FeedViewSC) {
    switch sender.selectedIndex {

    case 0:
        firstView.isHidden = false
        secondView.isHidden = true

    case 1:
        firstView.isHidden = true
        secondView.isHidden = false


    default:
        break;
    }
}

func setupContainerViews() {

    if #available(iOS 9.0, *) {
        firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }

    if #available(iOS 9.0, *) {
        secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }
    if #available(iOS 9.0, *) {
        secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    } else {
        // Fallback on earlier versions
    }

}

override func viewDidAppear(_ animated: Bool) {
    let img = UIImage()
    self.navigationController?.navigationBar.shadowImage = img
    self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

extension CGRect {
    var wh: (w: CGFloat, h: CGFloat) {
        return (size.width, size.height)
    }
}