String length with given font to fit UITextView

后端 未结 4 729
遇见更好的自我
遇见更好的自我 2021-01-01 00:17

I need to move text that the user has entered into a large multi-line UITextView into a smaller (but still multi-line) UITextView*. If the user has

相关标签:
4条回答
  • 2021-01-01 00:50

    I would suggest taking a slightly different approach and seeing if you can use a UILabel instead of the smaller UITextView.

    UILabels can be setup to be multi-line like a UITextView through their numberOfLines property.

    UILabels also have a lineBreakMode property and I believe that the default value of that property will do the exact truncation effect that you are looking for.

    0 讨论(0)
  • 2021-01-01 00:54

    This isn't actually a fix but it does provide a good starting poing for the calculation.

    If you use NSString's sizeWithFont: constrainedToSize: lineBreakMode: you get a vertical height for your text. If you divide that by your font's leading height, you get the number of lines in the whole string. Dividing [NSString count] by that number gives you an approximation to number of characters per line. This assumes the string is homogeneuous and will be inaccurate if someone types (e.g.) 'iiiiiiiiiii..." as oposed to "MMMMMMMMM...".

    You can also divide you bounding box by the relevent font's leading height to get the number of lines that fit within your bounding box.

    Multiplying characters per line by number of lines gives you a starting point for finding text that fits.

    You could calculate the margin for error in this figure by doing the same calculation for those 'iiiiii...' and "MMMMMM...'" strings.

    0 讨论(0)
  • 2021-01-01 01:06

    I wrote the following recursive method and public API to do this properly. The ugly fudge factor is the subject of this question.

    #define kFudgeFactor 15.0
    #define kMaxFieldHeight 9999.0
    
    // recursive method called by the main API
    -(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax
    {
    if ((aMax-aMin) <= 1)
        {
        NSString* subString = [aString substringToIndex:aMin];
        return subString;
        }
    
    int mean = (aMin + aMax)/2; 
    NSString* subString = [aString substringToIndex:mean];
    
    CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
    CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
    
    if (stringSize.height <= self.frame.size.height)
        return [self sizeStringToFit:aString min:mean max:aMax]; // too small
    else    
            return [self sizeStringToFit:aString min:aMin max:mean];// too big
    }
    
    -(NSString*)sizeStringToFit:(NSString*)aString
    {
    
    CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
    CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
    
    // if it fits, just return
    if (stringSize.height < self.frame.size.height)
        return aString; 
    
    // too big - call the recursive method to size it       
    NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]];
    return smallerString;   
    }
    
    0 讨论(0)
  • 2021-01-01 01:08

    I think Jonathan was on to something about the UILabel...

    So, the user finishes editing the UITextView, you get the string of text and pass it to the UILabel. You change the alpha of the UITextView to 0 and/or remove it from superview. Possibly store the untruncated full text in an ivar.

    UILabels are not "editable", however you can detect a touch with a UILabel (or it's superview). When you detect the touch on the UILabel, you simply restore the hidden UITextView and restore the string you saved.

    Sometimes the SDK is a pain, but it almost always wins the fight. Many times, it is better to adjust your design to UIKit conventions

    0 讨论(0)
提交回复
热议问题