Programatically Created Label Within Container Vie

2019-07-24 15:30发布

问题:

I have a reusable view class, with the function .addDisapearingView() when added to another view displays the text in the functions parameters. Both the label and its container view are programmatically created. When there's long text in the label, I want the label, and the view to both grow in height. When there's text too long for the label, the label doesn't grow-and the text, subsequently, doesn't clip/go to next line. I'm trying to get the container view to expand programmatically based upon the text.

I've tried an extension that detects when the label is truncated. Using that extension, I used the += operator on the label and view to expand both of them with no luck.

while label.isTruncated {
       print("printing while truncating in the while loop")
        regView.frame.size.height += 5
        label.frame.size.height += 5
    }

The interesting thing with that is, I've used that code before, with the addition of adding 5 to the height constraint of the view in the storyboard to expand the size of the label for text, and it worked. That lead me to believe that my problem might reside somewhere in editing the height constraint for the regView.

I've tried countless variations of

    label.adjustsFontSizeToFitWidth = true
    label.numberOfLines = 3
    label.lineBreakMode = .byWordWrapping
    label.translatesAutoresizingMaskIntoConstraints = false
    label.frame.size.height = regView.frame.size.height
    label.sizeToFit()
    regView.layoutSubviews()

I've tried changing the frame of the view and label, changing the constaints at the top of the code, and the answers from other questions.

Code:

Truncated Label Extension:

extension UILabel {

var isTruncated: Bool {

    guard let labelText = text else {
        return false
    }

    let labelTextSize = (labelText as NSString).boundingRect(
        with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
        options: .usesLineFragmentOrigin,
        attributes: [.font: font],
        context: nil).size

    return labelTextSize.height > bounds.size.height
}
}

View constraint changer:

extension UIView {

func updateConstraint(attribute: NSLayoutAttribute, constant: CGFloat) -> Void {
    if let constraint = (self.constraints.filter{$0.firstAttribute == attribute}.first) {
        constraint.constant = constant
        self.layoutIfNeeded()
    }
}
}

Whole function:

func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){

    regView.backgroundColor = colorView
    regView.alpha = alpha
    regView.frame = CGRect(x: toview.bounds.minX, y: toview.bounds.minY, width: toview.frame.size.width, height: height)

    toview.addSubview(regView)

    regView.translatesAutoresizingMaskIntoConstraints = false
    if #available(iOS 11.0, *) {
        let guide = toview.safeAreaLayoutGuide
        regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
        regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
        regView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
        regView.heightAnchor.constraint(equalToConstant: height).isActive = true

    } else {
        NSLayoutConstraint(item: regView,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: toview, attribute: .top,
                           multiplier: 1.0, constant: 0).isActive = true
        NSLayoutConstraint(item: regView,
                           attribute: .leading,
                           relatedBy: .equal, toItem: toview,
                           attribute: .leading,
                           multiplier: 1.0,
                           constant: 0).isActive = true
        NSLayoutConstraint(item: regView, attribute: .trailing,
                           relatedBy: .equal,
                           toItem: toview,
                           attribute: .trailing,
                           multiplier: 1.0,
                           constant: 0).isActive = true
        NSLayoutConstraint(item: regView, attribute: NSLayoutAttribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
        //regView.heightAnchor.constraint(equalToConstant: height).isActive = true
    }

    let label = UILabel(frame: CGRect(x: regView.frame.origin.x, y: regView.frame.origin.y, width: regView.frame.width, height: height))
    label.text = text
    label.font = UIFont(name: "Arial", size: 12)
    label.textColor = textColor
    label.adjustsFontSizeToFitWidth = true
    label.numberOfLines = 3
    label.lineBreakMode = .byWordWrapping
    label.translatesAutoresizingMaskIntoConstraints = false
    label.frame.size.height = regView.frame.size.height
    label.sizeToFit()
    regView.layoutSubviews()
    regView.addSubview(label)
    print("Label Height: \(label.frame.height)")
    print("Reg view height: \(regView.frame.height)")

    while label.isTruncated {
        print("label is truncated")
        regView.frame.size.height += 5
        label.frame.size.height += 5
        label.updateConstraint(attribute: NSLayoutAttribute.height, constant: regView.frame.height)
        label.updateConstraint(attribute: NSLayoutAttribute.width, constant: regView.frame.width)

        regView.layoutSubviews()
        label.sizeToFit()
        print("Label Height: \(label.frame.height)")
        print("Reg view height: \(regView.frame.height)")
    }

    //remove
    Timer.scheduledTimer(withTimeInterval: 2.8, repeats: false) { (action) in
        UIView.animate(withDuration: 2.8, animations: {
            self.regView.removeFromSuperview()
            label.removeFromSuperview()

        })
    }

}

which is called by: ReusableView().addDisapearingView(toview: self.view, text: "Anonymous posts will still show up in your profile page!, more text text to test in teh view that doen't work!", textColor: UIColor.white, colorView: UIColor.darkGray, alpha: 0.9, height: 20)

The interesting thing(That I tried to fix) was that even if the height is set to 40, or a value where two lines of text could fit, the label still doesn't expand/truncate, much less if the height param is 20.

Any help would be greatly appreciated!

回答1:

I guess you completely need auto-layout and make regView expand according to the label's text without any height constraints

let regView = UIView()

func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){

regView.backgroundColor = colorView
regView.alpha = alpha
toview.addSubview(regView)

regView.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
    let guide = toview.safeAreaLayoutGuide
    NSLayoutConstraint.activate([
            regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
            regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
            regView.topAnchor.constraint(equalTo: guide.topAnchor),
           // regView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
           // regView.heightAnchor.constraint(equalToConstant: height).isActive = true
    ])
} else {
    NSLayoutConstraint(item: regView,
                       attribute: .top,
                       relatedBy: .equal,
                       toItem: toview, attribute: .top,
                       multiplier: 1.0, constant: 0).isActive = true
    NSLayoutConstraint(item: regView,
                       attribute: .leading,
                       relatedBy: .equal, toItem: toview,
                       attribute: .leading,
                       multiplier: 1.0,
                       constant: 0).isActive = true
    NSLayoutConstraint(item: regView, attribute: .trailing,
                       relatedBy: .equal,
                       toItem: toview,
                       attribute: .trailing,
                       multiplier: 1.0,
                       constant: 0).isActive = true
   // NSLayoutConstraint(item: regView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
    //regView.heightAnchor.constraint(equalToConstant: height).isActive = true
}

let label = UILabel()
label.text = text
label.font = UIFont(name: "Arial", size: 12)
label.textColor = textColor
label.numberOfLines = 3
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
regView.addSubview(label)

    NSLayoutConstraint.activate([
        label.trailingAnchor.constraint(equalTo: regView.trailingAnchor),
        label.leadingAnchor.constraint(equalTo: regView.leadingAnchor),
        label.topAnchor.constraint(equalTo: regView.topAnchor),
        label.bottomAnchor.constraint(equalTo: regView.bottomAnchor) // this is the key behind expanding 

    ])

 Timer.scheduledTimer(withTimeInterval:3, repeats: false) { (action) in
    UIView.animate(withDuration: 2.8, animations: {
        self.regView.removeFromSuperview()
    })
 }

}

Edit:

let regView = UIView()

func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){

    regView.backgroundColor = colorView
    regView.alpha = alpha
    toview.addSubview(regView)

    regView.translatesAutoresizingMaskIntoConstraints = false
    var topCon:NSLayoutConstraint!

    if #available(iOS 11.0, *) {
        let guide = toview.safeAreaLayoutGuide
        topCon = regView.bottomAnchor.constraint(equalTo: guide.topAnchor)
        topCon.isActive = true
        NSLayoutConstraint.activate([
            regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
            regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
            // regView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
            // regView.heightAnchor.constraint(equalToConstant: height).isActive = true
            ])
    } else {
        topCon =  NSLayoutConstraint(item: regView,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: toview, attribute: .top,
                           multiplier: 1.0, constant: 0)
            topCon.isActive = true
        NSLayoutConstraint(item: regView,
                           attribute: .leading,
                           relatedBy: .equal, toItem: toview,
                           attribute: .leading,
                           multiplier: 1.0,
                           constant: 0).isActive = true
        NSLayoutConstraint(item: regView, attribute: .trailing,
                           relatedBy: .equal,
                           toItem: toview,
                           attribute: .trailing,
                           multiplier: 1.0,
                           constant: 0).isActive = true
        // NSLayoutConstraint(item: regView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
        //regView.heightAnchor.constraint(equalToConstant: height).isActive = true
    }

    let label = UILabel()
    label.text = text
    label.font = UIFont(name: "Arial", size: 12)
    label.textColor = textColor
    label.numberOfLines = 3
    label.lineBreakMode = .byWordWrapping
    label.translatesAutoresizingMaskIntoConstraints = false
    regView.addSubview(label)

    NSLayoutConstraint.activate([
        label.trailingAnchor.constraint(equalTo: regView.trailingAnchor),
        label.leadingAnchor.constraint(equalTo: regView.leadingAnchor),
        label.topAnchor.constraint(equalTo: regView.topAnchor),
        label.bottomAnchor.constraint(equalTo: regView.bottomAnchor) // this is the key behind expanding

        ])


     regView.layoutIfNeeded()

    topCon.constant += self.regView.frame.height

    UIView.animate(withDuration: 2) {
        toview.layoutIfNeeded()
    }


    Timer.scheduledTimer(withTimeInterval:3, repeats: false) { (action) in
        UIView.animate(withDuration: 2.8, animations: {
            self.regView.removeFromSuperview()
        })
    }

}