CTRunGetImageBounds возвращает неверную координату х на iOS 10 и ниже - PullRequest
0 голосов
/ 27 августа 2018

Я работаю с CoreText и пытаюсь добавить поддержку ссылок для пользовательской метки на iOS 11/12, однако мне также нужно поддерживать более старые версии программного обеспечения.Для этого я проверяю, пересекается ли касание пользователя и границы текста ссылки.

Чтобы получить границы, я просто звоню CTRunGetImageBounds(run, context, CFRangeMake(0, 0)).Это прекрасно работает на iOS 11 и 12, но не работает на 9 и 10. Я получаю прямоугольник по линии (250,8,1,100,30) на iOS 11, но на iOS 9, однако, тот же вызов функции возвращает (0.1,8.1,100,30).Кажется, координата X относится к трассе, а не к фактическому кадру.Поскольку координаты недействительны, ссылки на iOS 9/10 нельзя правильно щелкнуть, что является проблемой по очевидным причинам.

Я включил картинку, сравнивающую эти две.Ожидаемое поведение - ссылки должны быть выделены зелеными прямоугольниками.Обратите внимание, что симулятор iOS 12 делает это правильно, в то время как в 9.3 все прямоугольники захлопнуты влево из-за почти нулевой координаты x.

iOS 12 simulator iOS 9.3 simulator

1 Ответ

0 голосов
/ 27 августа 2018

Fixed iOS 9.3

Кажется, это либо ошибка CoreText, либо какое-то поведение Apple, измененное без документирования.На iOS 9 CTRunGetImageBounds возвращает значение x относительно себя, а не большего кадра.Это означает, что в то время как высота и ширина верны, возвращаемая координата x просто бесполезна.Так как это на давно мертвой прошивке, она не будет исправлена, но я все равно нашел обходной путь!

Swift 4

/// Get the CoreText relative frame for a given CTRun. This method works around an iOS <=10 CoreText bug in CTRunGetImageBounds
///
/// - Parameters:
///   - run: The run
///   - context: Context, used by CTRunGetImageBounds
/// - Returns: A tight fitting, CT rect that fits around the run
func getCTRectFor(run:CTRun,context:CGContext) -> CGRect {
    let imageBounds = CTRunGetImageBounds(run, context, CFRangeMake(0, 0))
    if #available(iOS 11.0, *) {
        //Non-bugged iOS, can assume the bounds are correct
        return imageBounds
    } else {
        //<=iOS 10 has a bug with getting the frame of a run where it gives invalid x positions
        //The CTRunGetPositionsPtr however works as expected and returns the correct position. We can take that value and substitute it
        let runPositionsPointer = CTRunGetPositionsPtr(run)
        if let runPosition = runPositionsPointer?.pointee {
            return CGRect.init(x: runPosition.x, y: imageBounds.origin.y, width: imageBounds.width, height: imageBounds.height)
        }else {
            //FAILED TO OBTAIN RUN ORIGIN? FALL BACK.
            return imageBounds
        }
    }
}

В то время как CTRunGetImageBounds возвращает неверную координату x,мы можем использовать CTRunGetPositionsPtr, чтобы исправить это, потому что он возвращает правильное origin для прогона.Чтобы получить полный, правильный кадр для диапазона, нам просто нужно заменить значение x из CTRunGetImageBounds нашим новым значением.

Вероятно, это будет немного медленнее, но только на долю миллисекунды.

...