-2

I'm creating UIKit objects programmatically, like UIButton, UIView, UILabels, etc.
Sometimes, I need to use the same view with same properties multiple times.

Example:

If I need to create a border line around a textField, I create an instance of UIView:

let textFieldTopViewSeparator: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.gray
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

Then, set its constraints:

func textFieldTopViewSeparatorConstraints() {
    textFieldTopViewSeparator.heightAnchor.constraint(equalToConstant: 1).isActive = true
    textFieldTopViewSeparator.topAnchor.constraint(equalTo: self.textField.topAnchor).isActive = true
    textFieldTopViewSeparator.widthAnchor.constraint(equalTo: self.textField.widthAnchor).isActive = true
    textFieldTopViewSeparator.centerXAnchor.constraint(equalTo: self.textField.centerXAnchor).isActive = true
}

And call both in viewDidLoad():

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.addSubview(textFieldTopViewSeparator)
    textFieldTopViewSeparatorConstraints()
}

That's only will create a border at the top of the textField, then to create a bottom one, I need to create another view, give it constraints, and call them again in viewDidLoad()

So my question is, is there a way to create only one instance of the view and use it multiple times with different constraints? Even with a different way to do create the view.

Ennabah
  • 2,303
  • 2
  • 20
  • 39
  • If you want to add two labels then you need to create two `UILabel` instances. – rmaddy Apr 22 '17 at 15:41
  • But that kind of redundant to create the same instance maybe 6 times in 1 view controller. – Ennabah Apr 22 '17 at 15:43
  • Why? You need unique instances. A view can only have one frame. – rmaddy Apr 22 '17 at 15:44
  • I'm setting that in a different way, I only create the view and set its property. Then, in another function, I create the constraints, and in the `viewDidLoad()`, I add the view as a subview, and call the constraints function. See this: http://stackoverflow.com/questions/26569371/how-do-you-create-a-uiimage-view-programmatically-swift/41329257#41329257 – Ennabah Apr 22 '17 at 15:47
  • OK, so what's your question here? Update this question with relevant code and clearly explain what you having an issue with. – rmaddy Apr 22 '17 at 15:48
  • 1
    *"is there a way to create only one instance of the view and use it multiple times with different constraints?"* - No. – rmaddy Apr 22 '17 at 15:59
  • @rmaddy Thanks, I have updated the question with extra details. – Ennabah Apr 22 '17 at 16:01
  • 1
    *"Even with a different way to do create the view.*" - No. A given view can only appear once at any given time. Period. End of discussion. You want two labels, two separator views, or two "whatever" views at the same time? Then you MUST create two label, separator view, or "whatever" instances. – rmaddy Apr 22 '17 at 16:09
  • Thank you @rmaddy I hope that's clear enough to understand for everybody! – mcd Apr 22 '17 at 16:11
  • Ok there is a way to avoid more than one border view. Create a larger background and set your view on top of it, voila only one border view. If you need transparency, mask the inner part of the border view to achieve it. ;) – ObjectAlchemist Apr 22 '17 at 16:15

2 Answers2

1

It seems to me that you just want to have a border at the top and bottom of your UITextField. You are approaching this wrong. I would suggest a different solution.

Objective-C code:

CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(0.0f, self.frame.size.height - 1, self.frame.size.width, 1.0f);
bottomBorder.backgroundColor = [UIColor blackColor].CGColor;
[myTextField.layer addSublayer:bottomBorder];

Swift code:

var bottomBorder = CALayer()
bottomBorder.frame = CGRectMake(0.0, textField.frame.size.height - 1, textField.frame.size.width, 1.0);
bottomBorder.backgroundColor = UIColor.blackColor().CGColor
textField.layer.addSublayer(bottomBorder)

You can also do the top line this way.

But this answer by "Aviel Gross" should fit your needs the best:

class FramedTextField: UITextField {

    @IBInspectable var linesWidth: CGFloat = 1.0 { didSet{ drawLines() } }

    @IBInspectable var linesColor: UIColor = UIColor.blackColor() { didSet{ drawLines() } }

    @IBInspectable var leftLine: Bool = false { didSet{ drawLines() } }
    @IBInspectable var rightLine: Bool = false { didSet{ drawLines() } }
    @IBInspectable var bottomLine: Bool = false { didSet{ drawLines() } }
    @IBInspectable var topLine: Bool = false { didSet{ drawLines() } }



    func drawLines() {

        if bottomLine {
            add(CGRectMake(0.0, frame.size.height - linesWidth, frame.size.width, linesWidth))
        }

        if topLine {
            add(CGRectMake(0.0, 0.0, frame.size.width, linesWidth))
        }

        if rightLine {
            add(CGRectMake(frame.size.width - linesWidth, 0.0, linesWidth, frame.size.height))
        }

        if leftLine {
            add(CGRectMake(0.0, 0.0, linesWidth, frame.size.height))
        }

    }

    typealias Line = CGRect
    private func add(line: Line) {
        let border = CALayer()
        border.frame = line
        border.backgroundColor = linesColor.CGColor
        layer.addSublayer(border)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        drawLines()
    }

}

You find more informations on this topic here: UITextField Only Top And Bottom Border

Community
  • 1
  • 1
mcd
  • 706
  • 4
  • 25
0

A UIView is only allowed to have one parent view. So no it isn't possible to use a UIView more than once.

See Apple Documentation of addSubview():

Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.

mcd
  • 706
  • 4
  • 25
ObjectAlchemist
  • 1,109
  • 1
  • 9
  • 18
  • This doesn't address the question since all of the views in question do have the same parent. – rmaddy Apr 22 '17 at 15:56
  • ? I don't understand your comment. How else then adding to a parent is a view used? Every time you add it to another view (and you have to if you wanna display it) the previous connection ist lost. So it answer the question exactly in my opinion. – ObjectAlchemist Apr 22 '17 at 16:02
  • The OP wants to create a single instance of a view and then add it multiple times to a single parent view. Of course that isn't possible. But your answer implies that it isn't possible because a view can't have more than one parent. In the OP's case, that isn't the limiting factor since they already plan to have just one parent view. But you still can't add a single view to a single parent multiple times. – rmaddy Apr 22 '17 at 16:04
  • Thats the same in my opinion. A view can only have one frame, change it and it's somewhere else, simple logic. So adding it again was the only option for me to think about. But who cares, the question is answered. I'm off. – ObjectAlchemist Apr 22 '17 at 16:10