Одна вещь, которую я нашел полезной, - это небольшая функция, которая принимает 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--;
Это только начало, но оно должно быть работоспособным.