Ctframegetvisiblestringrange эквивалент программирования iOS?
-
27-10-2019 - |
Вопрос
Мне нужен такой метод, как ctframegetvisiblestringrange, который может дать мне текст, который будет отображаться в заданном размере, поставляемом с режимом разрыва линии (т.е. обертка Word). Например, у меня есть длинная линия текста ... и у меня есть данный прямоугольник, чтобы нарисовать текст, обернутый в него, но где бы текст подвергается переходу, я продолжаю отображать его в другой области, где он остановился. Так что мне нужен метод, как:
NSString * text = "The lazy fox jumped over the creek";
[text drawAtPoint:CGPointMake(0, 0) forWidth:20 withFont:[UIFont fontWithName:@"Arial" size:10] lineBreakMode:UILineBreakModeWordWrap];
// now I do I know how much it drew before it stopped rendering?
У кого -нибудь есть идеи?
** Отредактировано: Пожалуйста, смотрите мое решение.
Решение
У меня была похожая проблема, и я использовал решение, которое разместил Майк.
Оказалось, однако, что trimToWord
часто давал мне слишком много слов, чем могло бы поместиться на моем указанном размере Uilabel. Я обнаружил, что если я изменил оператор цикла Whis while на> = не просто>, это сработало отлично.
Я также добавил несколько ivars (chopIndex
а также remainingBody
), что я использовал, чтобы получить оставшуюся строку, чтобы я мог отобразить ее в своей следующей Uilabel.
Вот решение, которое я использовал.
-(NSString*) rewindOneWord:(NSString*) str{
// rewind by one word
NSRange lastspace = [str rangeOfString:@" " options:NSBackwardsSearch];
if (lastspace.location != NSNotFound){
int amount = [str length]-lastspace.location;
chopIndex -= amount;
return [str substringToIndex:lastspace.location];
}else {
// no spaces, lets just rewind 2 characters at a time
chopIndex -= 2;
return [str substringToIndex:[str length]-2];
}
}
// returns only how much text it could render with the given stipulations
-(NSString*) trimToWord:(NSString*)str sizeConstraints:(CGSize)availableSize withFont:(UIFont*)font{
if(str == @"")
return str;
CGSize measured = [str sizeWithFont:font constrainedToSize:CGSizeMake(availableSize.width, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
// 'guess' how much we will need to cut to save on processing time
float choppedPercent = (((double)availableSize.height)/((double)measured.height));
if(choppedPercent >= 1.0){
//entire string can fit in availableSize
remainingBody = @"";
return str;
}
chopIndex = choppedPercent*((double)[str length]);
str = [str substringToIndex:chopIndex];
// rewind to the beginning of the word in case we are in the middle of one
do{
str = [self rewindOneWord:str];
measured = [str sizeWithFont:font constrainedToSize:availableSize lineBreakMode:UILineBreakModeWordWrap];
}while(measured.height>=availableSize.height);
//increment past the last space in the chopIndex
chopIndex++;
//update the remaining string
remainingBody = [remainingBody substringFromIndex:chopIndex];
return str;
}
Другие советы
Вот решение. Это довольно быстро. Он «угадывает», где сначала нарезать, а затем откатывает слово по слову. Звонки Sizewithfont довольно дороги, поэтому этот интенсивный шаг «угадайте» важен. Основным методом является Trimtoword: SizeConstraints: WithFont.
Не стесняйтесь комментировать, как я мог бы улучшить это.
-(NSString*) rewindOneWord:(NSString*) str{
// rewind by one word
NSRange lastspace = [str rangeOfString:@" " options:NSBackwardsSearch];
if (lastspace.location != NSNotFound){
int amount = [str length]-lastspace.location;
return [str substringToIndex:lastspace.location];
}else {
// no spaces, lets just rewind 2 characters at a time
return [str substringToIndex:[str length]-2];
}
}
// returns only how much text it could render with the given stipulations
-(NSString*) trimToWord:(NSString*) str sizeConstraints:(CGSize) avail withFont:(UIFont*) font{
CGSize measured = [str sizeWithFont:font constrainedToSize:CGSizeMake(avail.width, 1000000) lineBreakMode:UILineBreakModeWordWrap];
// 'guess' how much we will need to cut to save on processing time
float choppedPercent = (((double)avail.height)/((double)measured.height));
if (choppedPercent >= 1.0){
return str;
}
int chopIndex = choppedPercent*((double)[str length]);
str = [str substringToIndex:chopIndex];
// rewind to the beginning of the word in case we are in the middle of one
str = [self rewindOneWord:str];
measured = [str sizeWithFont:font constrainedToSize:avail lineBreakMode:UILineBreakModeWordWrap];
while (measured.height>avail.height){
str = [self rewindOneWord:str];
measured = [str sizeWithFont:font constrainedToSize:avail lineBreakMode:UILineBreakModeWordWrap];
}
return str;
}
Я не думаю, есть субсизий для CTFrameGetVisibleStringRange
, Хотя мы можем получить то же самое с использованием метода ниже.
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Яблочная документация
Отредактировано: приведенный ниже код показывает мой подход
NSString * text = "The lazy fox jumped over the creek";
NSArray* m_Array = [text componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@" "]];
CGSize mySize = CGSizeMake(300,180);
NSMutableString* myString = [[NSMutableString alloc] initWithString:@""];
//The below code till the end of the while statement could be put in separate function.
CGSize tempSize = CGSizeMake(0,0);
NSInteger index = 0 ;
do
{
[myString appendString:[m_Array objectAtIndex:index]];
tempSize = [myString sizeWithFont:myfont constrainedToSize:
CGSizeMake(mySize.width, CGFLOAT_MAX) lineBreakMode: UILineBreakModeWordWrap];
index++;
}while(tempSize.height < mySize.height && index <= [m_Array count])
//Remove the string items from m_Array till the (index-1) index,
[self RemoveItems:m_Array tillIndex:(index-1)];//Plz define you own
//you have the myString which could be fitted in CGSizeMake(300,180);
//Now start with remaining Array items with the same way as we have done above.
}