removing the highlighted selected segment

99 Views Asked by At

can u guys tell me how to remove that highlight it has? i cant find a way to do it.

this is how it is working:

one two

1

There are 1 best solutions below

0
DonMag On BEST ANSWER

As I commented when you posted about this previously - heading over to Google (or your favorite search engine) and searching along the lines of swift custom uisegmentedcontrol ... returns many, many examples, discussions, tutorials, etc. You could almost certainly find a pre-built one.

It appears you want a segmented control with only an underline -- no borders or highlight or separator line at all.

However, here is a quick, very simple example that looks like what you're trying to do.

We'll create a custom view class, with an embedded UISegmentedControl and an "underline" view. This gives us all the advantages of the UISegmentedControl without messing with its internal view structure:

class MyCustomSegmentedControlView: UIView {
    
    public var underlineColor: UIColor = .black {
        didSet { underlineView.backgroundColor = underlineColor }
    }
    
    public let segCtrl = UISegmentedControl()
    
    public func setSegmentTitles(_ titles: [String]) {
        segCtrl.removeAllSegments()
        titles.reversed().forEach { str in
            segCtrl.insertSegment(withTitle: str, at: 0, animated: false)
        }
        segCtrl.selectedSegmentIndex = 0
        moveUnderline(animated: false)
    }
    
    private let underlineView = UIView()
    private var segCtrlCurrentSize: CGSize = .zero

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        
        segCtrl.translatesAutoresizingMaskIntoConstraints = false
        addSubview(segCtrl)
        addSubview(underlineView)
        
        NSLayoutConstraint.activate([
            segCtrl.topAnchor.constraint(equalTo: topAnchor),
            segCtrl.leadingAnchor.constraint(equalTo: leadingAnchor),
            segCtrl.trailingAnchor.constraint(equalTo: trailingAnchor),
            segCtrl.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
        
        underlineView.backgroundColor = underlineColor

        // this will "remove" the highlight frame
        //  not really remove... just make it clear
        segCtrl.selectedSegmentTintColor = .clear
        
        segCtrl.addTarget(self, action: #selector(segChanged(_:)), for: .valueChanged)
    }
    
    @objc func segChanged(_ sender: UISegmentedControl) {
        moveUnderline(animated: true)
    }
    
    private func moveUnderline(animated: Bool) {
        // make sure selectedSegmentIndex is valid
        //  if not, hide the underline view
        guard segCtrl.selectedSegmentIndex > -1,
              segCtrl.selectedSegmentIndex < segCtrl.numberOfSegments
        else {
            underlineView.isHidden = true
            return
        }
        underlineView.isHidden = false
        // put the underline view at the bottom of the selected segment
        //  same width as the segment, 2-points height
        var r = segCtrl.subviews[segCtrl.selectedSegmentIndex].frame
        r.origin.y = r.height - 2.0
        r.size.height = 2.0
        if animated {
            UIView.animate(withDuration: 0.3, animations: {
                self.underlineView.frame = r
            })
        } else {
            self.underlineView.frame = r
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // if the segmented control frame has changed
        if segCtrlCurrentSize != segCtrl.frame.size {
            segCtrlCurrentSize = segCtrl.frame.size
            
            // background and divider images are stretched
            //  horizontally / vertically respectively
            // so we can use a single 1 x controlHeight image for both
            let sz: CGSize = .init(width: 1.0, height: segCtrlCurrentSize.height)
            var img = UIGraphicsImageRenderer(size: sz).image { rendererContext in
                UIColor.white.setFill()
                rendererContext.fill(CGRect(origin: .zero, size: sz))
            }
            segCtrl.setBackgroundImage(img, for: [], barMetrics: .default)
            segCtrl.setDividerImage(img, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
            
            moveUnderline(animated: false)
        }
    }
}

and asimple example controller class:

class ViewController: UIViewController {
    
    let mySeg = MyCustomSegmentedControlView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        mySeg.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(mySeg)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            mySeg.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            mySeg.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            mySeg.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            // no height or bottom - it will use the segmented control's intrinsic height
        ])
        
        mySeg.setSegmentTitles(["Cart", "Wishlist"])
        mySeg.underlineColor = .orange
        
        // we could use:
        //  protocol/delegate pattern, or
        //  closure
        // for simplicity, we'll add another target to the segmented control
        mySeg.segCtrl.addTarget(self, action: #selector(segChanged(_:)), for: .valueChanged)
    }
    
    @objc func segChanged(_ sender: UISegmentedControl) {
        print("Seg Control Changed to:", sender.selectedSegmentIndex)
    }

}

It looks like this:

enter image description here

Note that it will also work with more than 2 segments.