缩放文本以适合iPhone

cra*_*zie 8 iphone layout text uilabel core-text

我在制作应用程序中文本的"最佳"方法时遇到了一些麻烦.

我的主视图包含一个文本视图,应用程序的设计决定了一些事情:

  • 文本的(字体)大小应该是动态的
  • 文本框应在视图中垂直居中
  • 连字应该是自动的,并且仅在需要时(如果可能的话,避免使用)

目前我正在使用UILabel和以下代码来尝试猜测用于文本量的最佳字体大小:

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

mylabel.font = [self getFontForString:txt];
mylabel.adjustsFontSizeToFitWidth = YES;
mylabel.numberOfLines = 0;
[mylabel setText:txt];
Run Code Online (Sandbox Code Playgroud)

和:

- (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];
}
Run Code Online (Sandbox Code Playgroud)

这在某种程度上起作用,但是当文本有点偏长时,这通常会失败,这两个示例显示它呈现以下字符串:

  • "短文"
  • "我仍然想要很好地渲染大量文本."

简短的文字 更长的文字

正如您在第二个示例中所看到的(文本长得多),存在许多问题:

  • 最初的寡妇
  • 丢了y
  • 失踪的"很好".

所以考虑到所有这些,我有什么选择,如果这是正确的解决方案,我愿意继续使用coretext,但不知道从哪里开始,我也可能犯了一个错误,我只能'请参阅我的"字体大小猜测"代码.

Ada*_*ach 1

我发现有用的一件事是一个小函数,它接受一个 NSString、一个 UIFont 和一个 CGSize,返回一个 CGFloat 表示该字符串的最大字体大小,该字符串将适合传递的 CGSize - 它使用连续sizeWithFont较小的点大小,直到大小返回的值符合 CGSize 参数。你可以通过CGFLOAT_MAX如果您不关心一维,例如当您检查一条线的宽度并稍后检查整个字符串的高度时,您可以作为 x 或 y 传递当然,您可以定义最大和最小字体大小。

我首先使用 . 将字符串分成单词数组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--;
Run Code Online (Sandbox Code Playgroud)

这只是一个开始,但从那里开始应该是可行的。