2010-11-16 3 views
8

У меня возникли проблемы с разработкой «лучшего» способа рендеринга текста в приложении.Масштабирование текста в соответствии с iPhone

Мой главный вид состоит из точки зрения текста и дизайн приложения диктует несколько вещей:

  • The (шрифт) размер текста должен быть динамичным
  • Текст кадр должен быть сосредоточенные вертикально в представлении
  • переносы должны быть автоматическими и только тогда, когда это необходимо (по возможности избегать)

на данный момент я использую UILabel и следующий код, чтобы попытаться угадать Оптимальный размер шрифта для использования количества текста:

txt = @"this is just some sample text"; 

mylabel.font = [self getFontForString:txt]; 
mylabel.adjustsFontSizeToFitWidth = YES; 
mylabel.numberOfLines = 0; 
[mylabel setText:txt]; 

И:

- (UIFont *) getFontForString:(NSString *)txt { 
    CGFloat    textLength = txt.length; 
    CGFloat    maxFontSize = 71; 
    CGFloat    minFontSize = 27; 
    CGFloat    newFontSize = 0; 

    NSArray    *chunks = [txt componentsSeparatedByString:@" "]; 
    NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"length" ascending:NO] autorelease]; 
    NSArray    *sortedChunks = [chunks sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 

    CGSize    labelSize = theThingLabel.bounds.size; 
    CGSize    projectedSize = [[sortedChunks objectAtIndex:0] sizeWithFont:[UIFont boldSystemFontOfSize:maxFontSize]]; 

    if (projectedSize.width > labelSize.width) { 
      CGFloat percentageDifference = ((projectedSize.width - labelSize.width)/labelSize.width)*100; 
      if (percentageDifference > 50) { 
       newFontSize = ((minFontSize/percentageDifference)*100) - 10; 
       if (newFontSize < minFontSize) newFontSize = minFontSize; 
      } else { 
       newFontSize = ((percentageDifference/maxFontSize)*100) - 10; 
       if(newFontSize < (maxFontSize/2)) newFontSize = maxFontSize - abs(newFontSize); 
      } 
    } else { 
      if (textLength > 11 && textLength < 255) { 
       newFontSize = (maxFontSize - ((maxFontSize - minFontSize) * ((textLength- 11)/100))); 
      } else if (textLength <= 11) { 
       newFontSize = maxFontSize; 
      } else if (textLength >= 255) { 
       newFontSize = minFontSize; 
      } 
    } 

    return [UIFont boldSystemFontOfSize:newFontSize]; 
} 

Это работает, в определенной степени, но часто падает, когда текст немного по длинной стороне, эти два примера показывают, что оказывает следующие строки:

  • «короткий объем текста»
  • «, по существу, больше количество текста, который я все еще хочу сделать хороший LY «.

short text longer text

Как вы можете видеть, как во втором примере (с гораздо более пространным текстом) существует целый ряд вопросов:

  • Начальная вдова
  • Отброшенной у
  • Отсутствует «красиво».

Итак, имея в виду, какие у меня варианты, я открыт для перехода на использование coretext, если это правильное решение, но понятия не имеет, с чего начать, также возможно, что я сделал ошибка, которую я просто не вижу в моем коде «угадывание размера шрифта».

Любой вход, который вы могли бы предложить, был бы с благодарностью получен.

Большое спасибо!

+0

Имел аналогичную проблему и [решил ее в некоторой степени] (http://stackoverflow.com/questions/4382976/multiline-uilabel-with-adjustsfontsizetofitwidth). Это решение не выполняет никаких переносов, но решает проблему, из-за которой 'sizeWithFont' внутренне обрезает строку перед вычислением размера. –

+0

я отправил свой ответ и доступен по следующей ссылке [Calculae размер шрифта, чтобы поместиться в Rect с NSString] [1] [1]: http://stackoverflow.com/questions/4091115/iphone-sdk-calculate-max-font-size/11810409 # 11810409 – andyPaul

ответ

2

Я нашел полезной небольшую функцию, которая принимает NSString, UIFont и CGSize, возвращая CGFloat, представляющий наибольший размер шрифта для этой строки, который будет вписываться в переданный CGSize - он использует sizeWithFont на последовательно меньших пока размер возвращаемого размера не будет соответствовать аргументу CGSize. Вы можете передать CGFLOAT_MAX либо x, либо y, если вам не важно одно измерение, например, когда вы проверяете ширину линии и будете проверять высоту позже на всей строке. Конечно, вы определяете размеры шрифта max и min.

Я хотел бы начать с разделения строки на массив слов, используя componentsSeparatedByString.Возможно, вы хотите определить слово, которое может быть перенесено в виде слова, которое несколько кратно следующему наибольшему слову, когда все слова отображаются с одинаковым размером шрифта, поэтому вы создаете этот массив для некоторого произвольного размера шрифта, и у вас есть соответствующий массив относительной ширины (или, может быть, словаря, где слово - это ключ и ширина - значение). Перед продолжением необходимо отсканировать и разделить любые слова (слова) на два слова (один с дефисом). Затем вам нужно найти размер шрифта, в котором все слова соответствуют вашему размеру, в примере, который вы указали, который является шириной, используя функцию, упомянутую выше.

Когда размер шрифта кандидата известен, вы проверяете свои другие ограничения, такие как вдова - возможно, вы определяете их с точки зрения позиций, которые они могут не встречаться (начало для одного), и пропорции ширины линии, которая делает вдову , Если вы обнаружите проблему, вы комбинируете слова в массиве для удаления вдовы и пересчета нового размера шрифта кандидата - это может привести к тому, что вы закончите с переносом в первой строке или меньшем шрифте в целом, но если ваш текст «непропорционально долго начинайте с группы небольших слов ", тогда у вас может не быть выбора.

Проблема «красивого» исчезновения не так уж трудна, вам просто нужно дважды проверить высоту отрисованного текста - возможно, вы могли бы использовать sizeWithFont:constrainedToSize после того, как вы завершили вышеуказанные процедуры в качестве окончательной проверки. Если это не удается, уменьшите максимальный размер шрифта кандидата и начните заново.

Итак:

candidateFontSize = CGFLOAT_MAX; 
while(stillRendering) 

    break string into array of words 
    make array of word widths 
    check for and divide hyphenation candidates 

    for each word 
    if max font size returned for rendered word in size constraint < canddiateFontSize 
     candidateFontSize = max font size returned 

    for each word 
    measure each word and record rendered size in candidateFontSize 

    stillRendering = NO; 

    for each word 
    check each word for problems such as widows and solve 
    if problem found 
     stillRendering = YES; 

    check entire string using sizeWithFont:constrainedToSize using width, CGFLOAT_MAX 

    if height is too large 
    stillRendering = YES; 
    candidateFontSize--; 

Это только начало, но оно должно быть работоспособным оттуда.

0
CGSize expectedLabelSize = [yourString sizeWithFont:yourLable.font]; 

     //adjust the label the the new height. 
    CGRect newFrame = yourLable.frame; 
    newFrame.size.width = expectedLabelSize.width; 
    newFrame.origin.x = x; 
    yourLable.frame = newFrame; 
3

Следующий метод будет использоваться для полного размера шрифта для конкретной строки для конкретного прямоугольника (области).

-(float) maxFontSizeThatFitsForString:(NSString*)_string inRect:(CGRect)rect withFont:(NSString *)fontName onDevice:(int)device { 
// this is the maximum size font that will fit on the device 
float _fontSize = maxFontSize; 
float widthTweak; 

// how much to change the font each iteration. smaller 
// numbers will come closer to an exact match at the 
// expense of increasing the number of iterations. 
float fontDelta = 2.0; 

// sometimes sizeWithFont will break up a word 
// if the tweak is not applied. also note that 
// this should probably take into account the 
// font being used -- some fonts work better 
// than others using sizeWithFont. 
if(device == IPAD) 
    widthTweak = 0.2; 
else 
    widthTweak = 0.2; 

CGSize tallerSize = CGSizeMake(rect.size.width-(rect.size.width*widthTweak), 100000); 
CGSize stringSize = CGSizeZero; 

    if([[UIDevice currentDevice].systemVersion floatValue]>=7.0){ 
     NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:[UIFont boldSystemFontOfSize:17] forKey: NSFontAttributeName]; 
     stringSize = [_string boundingRectWithSize: tallerSize options:NSStringDrawingUsesLineFragmentOrigin attributes:stringAttributes context:nil].size; 
    } 
    else{ 
     stringSize = [_string sizeWithFont:[UIFont fontWithName:fontName size:_fontSize] constrainedToSize:tallerSize]; 
    } 

while (stringSize.height >= rect.size.height) 
{  
    _fontSize -= fontDelta; 
    stringSize = [_string sizeWithFont:[UIFont fontWithName:fontName size:_fontSize] constrainedToSize:tallerSize]; 
} 

return _fontSize; 
} 

Используйте это и получите размер шрифта и присвойте этикетке.

С уважением,

Satya.

+1

if (device == IPAD) widthTweak = 0.2; еще widthTweak = 0.2; - разрешено ли размещать ответы SO на thedailywtf.com? ;-) –

Смежные вопросы