I'm trying to calculate the height of my UILabel to make the page scrollable. The label contains attributedText to display HTML content.
I'm using this function to get my HTML content to the UILabel:
func stringFromHTML( string: String?) -> NSAttributedString
{
do{
let pStyle = NSMutableParagraphStyle()
pStyle.lineSpacing = 4
pStyle.paragraphSpacingBefore = 10
let str = try NSMutableAttributedString(data:string!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true
)!, options:[NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSNumber(unsignedLong: NSUTF8StringEncoding)], documentAttributes: nil)
str.addAttribute(NSParagraphStyleAttributeName, value: pStyle, range: NSMakeRange(0, str.length))
str.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica Neue", size: 16.0)!, range: NSMakeRange(0, str.length))
return str
} catch
{
print("html error\n",error)
}
return NSAttributedString(string: "")
}
I'm a newbie. So, I make a research and find this extention to get the height of the UILabel. It returns a value but I guess it's not true. My UIScrollView doesn't seem to work:
extension UILabel{
func requiredHeight() -> CGFloat{
let label:UILabel = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = self.font
label.text = self.text
label.sizeToFit()
return label.frame.height
}
}
And this is my code in the viewDidLoad() method for the constraints:
// Set ContentView height
let activityTitleHeight:CGFloat = self.activityTitle.requiredHeight() + 20
let activityDescHeight:CGFloat = self.activityDesc.requiredHeight() + 20
let totalContentHeight:CGFloat = activityDescHeight + activityTitleHeight + 345
// There is an image view and a navigation, their total height: 345
let contentViewHeight:NSLayoutConstraint = NSLayoutConstraint(item: self.contentView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: totalContentHeight)
self.contentView.addConstraint(contentViewHeight)
Thanks in advance!
Since you want entire page to become scrollable once the HTML content is larger than the size of the application's window, I presume your top level view is UIScrollView
.
The main trick here is to set height constraint of the label displaying the HTML to 0
and then update it programmatically once you calculate the height of the HTML text it contains.
If the text being displayed is too long, then the scroll view will start scrolling automatically provided that you set all vertical constraints correctly.
By the way, it is an overkill to create a UILabel
just to calculate the height of a string. As of iOS7, we have NSAttributedString.boundingRect(size:options:context)
method which calculates the minimum rect needed for drawing the text with given options:
string.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesFontLeading, .UsesLineFragmentOrigin], context: nil)
Going back to your question, you should create an ivar of NSLayoutConstraint
type representing the height of the label in question:
class ViewController: UIViewController {
@IBOutlet weak var htmlLabel: UILabel!
private var labelHeightConstraint: NSLayoutConstraint!
...
and set its constant
property to 0
as we said earlier:
override func viewDidLoad() {
super.viewDidLoad()
...
htmlLabel.text = stringFromHTML(htmlText)
labelHeightConstraint = NSLayoutConstraint(item: htmlLabel, attribute: .Height, relatedBy: .Equal,
toItem: nil, attribute: .NotAnAttribute, multiplier: 0, constant: 0)
scrollView.addConstraint(labelHeightConstraint)
}
Then calculate the height of the label:
(Since we don't have the exact width of any superview in viewDidLoad
, viewDidAppear
is a good place to do such calculation.)
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let maxSize = CGSizeMake(CGRectGetWidth(scrollView.frame), CGFloat.max)
let textSize = htmlLabel.attributedText!.boundingRectWithSize(maxSize, options: [.UsesFontLeading, .UsesLineFragmentOrigin], context: nil)
labelHeightConstraint.constant = ceil(textSize.height)
}
I created a test project for you showing what I did above. You can download it from here.
It's better way to put such a text into the UITextView. This element serves as a text container with:
.
let textField = UITextField()
textField.text = "Your long text from HTML source ..."
textField.frame = CGRect(x: 0, y: 0, width: 375, height: 200)
self.contentView.addSubview(textField)
Even if you don't use storyboard, I post just a small screenshot, what attributes this UI element brings to the place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With