ajayb ajayb -4 years ago 211
Swift Question

Adding a UIControl into title of Navbar Programmatically - Swift

I'm trying to add a custom UI Segmented control I created into my root view controller's navbar. Here's my code:

Segmented Control:

@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 = 2
layer.borderColor = UIColor(red: 2/255, green: 239/255, blue: 23/255, alpha: 1).cgColor

backgroundColor = UIColor(red: 239/255, green: 29/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: "timesnr",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]
}

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

}


My VC that I would liek to add this Segmented Control to:

class FeedViewController: UIViewController {


let feedViewSC: FeedViewSC = {
let sc = FeedViewSC()
sc.translatesAutoresizingMaskIntoConstraints = false
return sc
}()

override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(feedViewSC)
setupFeedViewSC()
}

func setupFeedViewSC() {
feedViewSC.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 5).isActive = true
feedViewSC.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
feedViewSC.heightAnchor.constraint(equalToConstant: 35).isActive = true
feedViewSC.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 60).isActive = true
feedViewSC.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -60).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.
}

}


If you can tell me how I can add my custom UIControl to my View Controller's Navigation bar title.

Answer Source

If the FeedViewController is the initial view controller of the NavigationController you can do it very simply by

let feedControl = FeedViewSC(frame: (self.navigationController?.navigationBar.bounds)!)
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(FeedViewController.changingTab), for: .valueChanged)

At least I don't see a reason that this would not work for getting it in the navigation bar.

Also not part of the question but if you are having any trouble seeing your control in IB might I suggest.

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    layer.cornerRadius = 2
    layer.borderColor = UIColor(red: 2/255, green: 239/255, blue: 23/255, alpha: 1).cgColor
    backgroundColor = UIColor(red: 239/255, green: 29/255, blue: 239/255, alpha: 1)
    setupLabels()
    insertSubview(thumbView, at: 0)
}

As for the control itself I did not test it but your events and your handling may be slightly different than value changed I am not sure.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download