Кажется, это либо ошибка 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
нашим новым значением.
Вероятно, это будет немного медленнее, но только на долю миллисекунды.