Как расположить текст в обратном направлении, используя Core Text? - PullRequest
2 голосов
/ 10 марта 2012

Для размещения длинной строки на страницах я могу использовать CTFramesetterCreateFrame, чтобы создать CTFrameRef, а затем перейти к начальному индексу в строке для создания следующей CTFrameRef. Это легко, поскольку начальный индекс движется вперед, а API-интерфейсы Core Text изначально поддерживают этот тип макета.

Теперь я застрял в ситуации, когда хочу перейти на предыдущую страницу .

Например, длина длинной строки равна 1000, теперь начальный индекс текущей страницы (или CTFrameRef) равен 500, и я хочу перейти на предыдущую страницу, как узнать, какой индекс нужно запустить ? Я не могу кэшировать все индексы для каждой страницы или вычислить с начала строки, потому что строка может быть очень длинной, которая не помещается в памяти (мне нужно будет прочитать строку из файла блок за блоком) , Я отсканировал CT* API, нет такого API, который поддерживает разметку текста в обратном направлении.

Есть идеи по этому поводу?

1 Ответ

1 голос
/ 15 марта 2012

Причина, по которой нет API для этого, заключается в том, что не существует эффективного независимого от контекста способа сделать это, кроме попытки набрать всю страницу методом проб и ошибок, чтобы найти лучший начальный индекс, который, как вы можете себе представить, был бы интенсивная операция.

Если каждая страница вашего текста имеет заданную ширину и является просто прямоугольным CTFrame, вот как вы можете это сделать:

  1. «Оценить» диапазон строк для предыдущей страницы (например, предположить, что он имеет ту же длину, что и текущая страница.
  2. Превышение, которое оценивается по разумно большому коэффициенту (например, в 1,5 / 2 раза) до разумного. Выберите диапазон превышения, чтобы он начинался в начале абзаца.
  3. Создайте рамку с таким диапазоном, как обычно, но сделайте рамку намного больше, чем обычно.
  4. Получить информацию о строке из кадра и с конца начать подсчет высоты, возвращаясь строка за строкой.
  5. Вы можете найти фактическую предыдущую страницу, начиная с индекса первой подходящей строки, и использовать ее для создания фактического CTFrame.

Хотя это должно сработать, я все же рекомендую вам попытаться найти способ избежать этого, если это возможно. Обратите внимание, что это выходит из строя, как только у вас есть более сложный алгоритм разбиения на страницы, и даже в этом случае он использует 1,5 / 2x памяти. Вот несколько советов о том, как вы можете это сделать:

  1. Кэшируйте индексы (по крайней мере, до текущей позиции.) Каждая страница может содержать ~ 1000 символов, поэтому размер вашего кэша будет составлять 0,1% от размера всего текста, и вы должны сделать это в хотя бы один раз в первый раз вы показываете текст. Вы можете сделать кэш еще меньше, сохранив индексы для каждой n страницы.

  2. Если это применимо, разбейте вашу строку на логические подстроки, например, на основе разрыва страницы или разрыва раздела, затем введите для каждой подстроки целое для диапазона страниц.

...