Home > Software engineering >  Custom Segment Control with UIView, only the first button works
Custom Segment Control with UIView, only the first button works

Time:10-08

I realized a Custom Segment Control with UIView, only the first button works.

When I click on the other buttons, they don't change color, and the first button stays with the active background color.

I would like to give the buttons an on / off effect, but only the first button remains on. I believe the problem is inside the method:

func didSelectButton (at index: Int) {

but I can't find what's missing

import UIKit

@IBDesignable class CustomSegmentedView: UIView {
    
    
    @IBInspectable var selectedBackgroundColor = Colors.colorViolet1 {
        didSet {
            self.slideView.backgroundColor = selectedBackgroundColor
        }
    }
    
    @IBInspectable var selectedTextColor: UIColor = UIColor.white
    
    @IBInspectable var buttonText1: String = ConstantFile.buttonMonitoring {
        didSet {
            self.buttonTitles[0] = buttonText1
        }
    }
    
    @IBInspectable var buttonText2: String = ConstantFile.buttonAlert {
        didSet {
            self.buttonTitles[1] = buttonText2
        }
    }
    
    @IBInspectable var buttonText3: String = ConstantFile.buttonActivities {
        didSet {
            self.buttonTitles[2] = buttonText3
        }
    }
    
    @IBInspectable var buttonText4: String = ConstantFile.buttonSettings {
        didSet {
            self.buttonTitles[3] = buttonText4
        }
    }
    
    @IBInspectable var image1: UIImage = UIImage() {
        didSet {
            self.buttonImages[0] = image1
        }
    }
    
    @IBInspectable var image2: UIImage = UIImage() {
        didSet {
            self.buttonImages[1] = image2
        }
    }
    
    @IBInspectable var image3: UIImage = UIImage() {
        didSet {
            self.buttonImages[2] = image3
        }
    }
    
    @IBInspectable var image4: UIImage = UIImage() {
        didSet {
            self.buttonImages[3] = image4
        }
    }
    
    @IBInspectable var image1Selected: UIImage = UIImage() {
        didSet {
            self.buttonSelectImages[0] = image1Selected
        }
    }
    
    @IBInspectable var image2Selected: UIImage = UIImage() {
        didSet {
            self.buttonSelectImages[1] = image2Selected
        }
    }
    
    @IBInspectable var image3Selected: UIImage = UIImage() {
        didSet {
            self.buttonSelectImages[2] = image3Selected
        }
    }
    
    @IBInspectable var image4Selected: UIImage = UIImage() {
        didSet {
            self.buttonSelectImages[3] = image4Selected
        }
    }
    
    @IBInspectable var startingIndex: Int = 0 {
        didSet {
            if startingIndex > 3 {
                startingIndex = 3
                self.didSelectButton(at: startingIndex)
            } else if startingIndex < 0 {
                startingIndex = 0
                self.didSelectButton(at: startingIndex)
            } else {
                self.didSelectButton(at: startingIndex)
            }
            
        }
    }
    
    
    lazy var button1: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("", for: .normal)
        button.titleLabel?.font = UIFont.fontHelveticaBold14
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
        return button
    }()
    
    lazy var button2: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("", for: .normal)
        button.titleLabel?.font = UIFont.fontHelveticaBold14
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
        return button
    }()
    
    lazy var button3: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("", for: .normal)
        button.titleLabel?.font = UIFont.fontHelveticaBold14
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
        return button
    }()
    
    lazy var button4: UIButton = {
        let button = UIButton(type: .custom)
        button.setTitle("", for: .normal)
        button.titleLabel?.font = UIFont.fontHelveticaBold14
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
        return button
    }()
    
    lazy var stackView: UIStackView = UIStackView(arrangedSubviews: [])
    
    lazy var slideView: UIView = {
        var view = UIView(frame: CGRect.zero)
        view.backgroundColor = self.selectedBackgroundColor
        return view
    }()
    
    private var currentIndex: Int = 0
    private var buttons: [UIButton] = []
    private lazy var buttonTitles:[String] = [buttonText1, buttonText2, buttonText3, buttonText4]
    private lazy var buttonImages:[UIImage] = [image1, image2, image3, image4]
    private lazy var buttonSelectImages:[UIImage] = [image1Selected, image2Selected, image3Selected, image4Selected]
    
    var delegate: CustomSegmentedViewDelegate?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        self.buttons = [button1, button2, button3, button4]
        self.buttonTitles = [buttonText1, buttonText2, buttonText3, buttonText4]
        self.buttonImages = [image1, image2, image3, image4]
        self.buttonSelectImages = [image1Selected, image2Selected, image3Selected, image4Selected]
        
        button1.sizeToFit()
        button2.sizeToFit()
        button3.sizeToFit()
        button4.sizeToFit()
        
        stackView.addArrangedSubview(button1)
        stackView.addArrangedSubview(button2)
        stackView.addArrangedSubview(button3)
        stackView.addArrangedSubview(button4)
        stackView.axis = .horizontal
        stackView.distribution = .fillProportionally
        stackView.alignment = .fill
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        self.addSubview(slideView)
        self.addSubview(stackView)
        stackView.pinEdges(to: self)
        
        button1.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
        button2.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
        button3.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
        button4.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
        
        button1.setTitle("", for: .normal)
        button2.setTitle("", for: .normal)
        button3.setTitle("", for: .normal)
        button4.setTitle("", for: .normal)

    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        button1.setImage(buttonImages[0], for: .normal)
        button2.setImage(buttonImages[1], for: .normal)
        button3.setImage(buttonImages[2], for: .normal)
        button4.setImage(buttonImages[3], for: .normal)
        
        self.setupFirstSelection()
    }
    
    
    @objc func buttonTapped(sender :UIButton!) {
        switch sender {
        case button1:
            didSelectButton(at: 0)
            break
        case button2:
            didSelectButton(at: 1)
            break
        case button3:
            didSelectButton(at: 2)
            break
        case button4:
            didSelectButton(at: 3)
            break
        default:
            break
        }
    }
    
    func didSelectButton(at index: Int) {
        

        self.delegate?.didSelectPage(index: index)
        
        let oldButton = self.buttons[self.currentIndex]
  
        let newButton = self.buttons[index]
 
        
        newButton.alpha = 0.0
        

        oldButton.setImage(self.buttonImages[self.currentIndex], for: .normal)
        newButton.setImage(self.buttonSelectImages[index], for: .normal)
        
 
        UIView.animate(withDuration: 0.1) {
            oldButton.setTitle("", for: .normal)
            newButton.setTitle(self.buttonTitles[index], for: .normal)
            self.stackView.layoutSubviews()
            self.layoutIfNeeded()
            newButton.alpha = 1.0
        }
        

        UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {
            self.slideView.frame = newButton.frame
            self.layoutIfNeeded()
        }, completion: nil)
        
        
        self.currentIndex = index
        
    }
    
    func setupFirstSelection() {
        let index = self.startingIndex
        let newButton = self.buttons[index]
        newButton.setTitle(self.buttonTitles[index], for: .normal)
        newButton.setImage(self.buttonSelectImages[index], for: .normal)
        
        self.stackView.layoutSubviews()
        self.slideView.frame = newButton.frame
        self.slideView.layer.cornerRadius = self.slideView.frame.height/2.0
        
        
        self.currentIndex = index
        
    }
    
}

extension UIView {
    func pinEdges(to other: UIView) {
        leadingAnchor.constraint(equalTo: other.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: other.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: other.topAnchor).isActive = true
        bottomAnchor.constraint(equalTo: other.bottomAnchor).isActive = true
    }
}

protocol CustomSegmentedViewDelegate {
    func didSelectPage(index: Int)
}

CodePudding user response:

issue is in your layoutSubviews() you call every time when you call layoutSubviews() this function automatically set first self.setupFirstSelection()

replace layoutSubviews() by commenting self.setupFirstSelection()

override func layoutSubviews() {
    super.layoutSubviews()
    
    button1.setImage(buttonImages[0], for: .normal)
    button2.setImage(buttonImages[1], for: .normal)
    button3.setImage(buttonImages[2], for: .normal)
    button4.setImage(buttonImages[3], for: .normal)
    
    //self.setupFirstSelection()
}
  • Related