How to calculate TextView height base on text

前端 未结 6 2021
無奈伤痛
無奈伤痛 2021-01-05 02:43

I am using the code below for calculate the height of text, then set this height for UILabel and UITextView

CGSize targetSize = CGS         


        
相关标签:
6条回答
  • 2021-01-05 02:59

    You don't need to calculate Height of UITextview based on text.

    Just change frame and set height like this:

    textview.size.height = textview.contentSize.height;
    

    This is easy solution. I hope this helps you.

    0 讨论(0)
  • 2021-01-05 03:07

    Swift 5

    A classic hack I've used to do this is create a function that takes the String as a parameter. Within the function it generates a label with the width required, infinite number of lines, and a height of "too much". Then apply sizeToFit() on the label and return the height of the frame.

    func calculatedHeight(for text: String, width: CGFloat) -> CGFloat {
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: width,
                                          height: .greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.text = text
        label.sizeToFit()
        return label.frame.height
    }
    

    The returned height can be applied to a UITextField height anchor. Though I do recommend calculating the width dynamically based on screen size, but that's up to you.

    0 讨论(0)
  • 2021-01-05 03:07

    self.textView.textContainerInset = UIEdgeInsets.zero self.textView.textContainer.lineFragmentPadding = 0

    In storyboard or xib mark textview height >=0.

    If you are using text view with table view. Calculate cell height according to content, textview will adjust it's space.

    0 讨论(0)
  • 2021-01-05 03:08

    There are two things you can try:

    1. Set textView.textContainerInset = UIEdgeInsetsZero
    2. Set textView.textContainer.lineFragmentPadding = 0

    With these operations you can get rid of all the padding in the textView and when its width matches with the label's one the heights are also the same.

    Here's a sample code you can place in an empty viewController and test it yourself:

    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
    
        NSString *text = @"The internet connection appears to be offline.";
        CGFloat width = 100.f;
    
        UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 20, width, 300)];
        textView.font = [UIFont fontWithName:@"AvenirNext-Regular" size:12.f];
        textView.text = text;
        [self.view addSubview:textView];
    
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20 + width, 20, width, 300)];
        label.numberOfLines = 0;
        label.font = [UIFont fontWithName:@"AvenirNext-Regular" size:12.f];
        label.text = text;
        [self.view addSubview:label];
    
        // Getting rid of textView's padding
        textView.textContainerInset = UIEdgeInsetsZero;
        textView.textContainer.lineFragmentPadding = 0;
    
        // Setting height of textView to its contentSize.height
        CGRect textViewFrame = textView.frame;
        textViewFrame.size = textView.contentSize;
        textView.frame = textViewFrame;
    
        // Setting height of label accorting to it contents and width
        CGRect labelFrame = label.frame;
        labelFrame.size = [label sizeThatFits:CGSizeMake(width, HUGE_VALF)];
        labelFrame.size.width = width;
        label.frame = labelFrame;
    
        NSLog(@"Label bounds: %@", NSStringFromCGRect(label.bounds));
        NSLog(@"TextView bounds: %@", NSStringFromCGRect(textView.bounds));
    
        // Visualizing final effect with borders
        textView.layer.borderColor = [UIColor redColor].CGColor;
        textView.layer.borderWidth = 1.f;
        label.layer.borderColor = [UIColor greenColor].CGColor;
        label.layer.borderWidth = 1.f;
    }
    

    Console output:

    2016-09-01 14:29:06.118 stack39268477[943:243243] Label bounds: {{0, 0}, {100, 66}}
    2016-09-01 14:29:06.119 stack39268477[943:243243] TextView bounds: {{0, 0}, {100, 66}}
    
    0 讨论(0)
  • 2021-01-05 03:09

    Most of the answers here are hints into the right direction :-)

    So, just to sum it all up...

    UITextView uses a NSTextContainer (inside a private API _UITextContainerView) to do the real layout work. This NSTextContainer(View) may have insets to the surrounding UITextView, which are set by UITextView's textContainerInset property. The defaults for this insets seem to be:

    • top: 8
    • left: 0
    • bottom: 8
    • right: 0

    The NSTextContainer itself may have additional left and right insets for the text itself. These insets are set in NSTextContainer's lineFragmentPadding property.

    • The default for this is 5.0.

    As a result, when calculating the optimum frame size for a UITextView based on the boundingRect for some text inside that UITextView, we have to take all these insets into account:

    CGSize reservedSpace = CGSizeMake((textView.textContainerInset.left + (2.0 * textView.textContainer.lineFragmentPadding) + textView.textContainerInset.right),
                                      (textView.textContainerInset.top + textView.textContainerInset.bottom));
    CGSize targetSize = CGSizeMake((300.0 - reservedSpace.width), CGFLOAT_MAX);
    NSString* message = @"The Internet connection appears to be offline.";
    
    NSStringDrawingContext* context = [[NSStringDrawingContext alloc] init];
    CGSize boundingBox = [message boundingRectWithSize:targetSize
                                                  options:NSStringDrawingUsesLineFragmentOrigin
                                               attributes:@{NSFontAttributeName:FontOpenSanWithSize(14)}
                                                  context:context].size;
    
    CGSize size = CGSizeMake(ceil(boundingBox.width),
                             (ceil(boundingBox.height) + reservedSpace.height));
    

    Good luck :-)

    0 讨论(0)
  • 2021-01-05 03:13

    This calculates the size of any string, whether or not you put them in a text view.

    let frame = NSString(string: yourText).boundingRect(
        with: CGSize(width: yourDesiredWidth, height: .infinity),
        options: [.usesFontLeading, .usesLineFragmentOrigin],
        attributes: [.font : yourFont],
        context: nil)
    
    let height = frame.size.height
    
    0 讨论(0)
提交回复
热议问题