I’ve expandable label. After I tapped to "daha fazla" label, I present to full textual content in label. Usually it really works properly however on this case it would not work. After I present to attributed string in label, it reveals third and final lane totally different than CTFrame.
That is how textual content seems to be in my label.
Right here is my ctFrame log. After I logged, third and final lane it seems to be totally different than label.
Right here is my calculating code.
func characterIndex(at touchPoint: CGPoint) -> Int {
guard let attributedString = attributedText, bounds.comprises(touchPoint) else {
return NSNotFound
}
let textRect = self.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
if !textRect.comprises(touchPoint) {
return NSNotFound
}
// Offset faucet coordinates by textRect origin to make them relative to the origin of body
// Convert faucet coordinates (begin at high left) to CT coordinates (begin at backside left)
let level = CGPoint(x: touchPoint.x - textRect.origin.x,
y: textRect.dimension.top - (touchPoint.y - textRect.origin.y))
let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,
CFRangeMake(0, attributedString.size),
nil,
CGSize(width: textRect.width, top: CGFloat.greatestFiniteMagnitude),
nil)
let path = CGMutablePath()
path.addRect(CGRect(x: 0, y: 0, width: suggestedSize.width, top: CGFloat(ceilf(Float(suggestedSize.top)))))
let ctFrame = CTFramesetterCreateFrame(framesetter, CFRange(), path, nil)
let frameLines = CTFrameGetLines(ctFrame)
let linesCount = numberOfLines > 0 ? min(numberOfLines, CFArrayGetCount(frameLines)) : CFArrayGetCount(frameLines)
if linesCount.cgFloatValue.isZero {
return NSNotFound
}
var lineOrigins = [CGPoint](repeating: .zero, rely: linesCount)
CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, linesCount), &lineOrigins)
for (idx, lineOrigin) in lineOrigins.enumerated() {
var newLineOrigin = lineOrigin
let lineIndex = CFIndex(idx)
let line = unsafeBitCast(CFArrayGetValueAtIndex(frameLines, lineIndex), to: CTLine.self)
// Get bounding info of line
var ascent: CGFloat = 0.0
var descent: CGFloat = 0.0
var main: CGFloat = 0.0
let width = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, &main))
let yMin = CGFloat(ground(lineOrigin.y - descent))
let yMax = CGFloat(ceil(lineOrigin.y + ascent))
// Apply penOffset utilizing flushFactor for horizontal alignment to set lineOrigin since that is the horizontal offset from drawFramesetter
let flushFactor = flushFactorForTextAlignment(textAlignment: textAlignment)
let penOffset = CGFloat(CTLineGetPenOffsetForFlush(line, flushFactor, Double(textRect.dimension.width)))
newLineOrigin.x = penOffset
// Test if we have already handed the road
if level.y > yMax {
return NSNotFound
}
// Test if the purpose is inside this line vertically
if level.y >= yMin && level.x >= lineOrigin.x && level.x <= lineOrigin.x + width {
// Convert CT coordinates to line-relative coordinates
let relativePoint = CGPoint(x: level.x - lineOrigin.x, y: level.y - lineOrigin.y)
return Int(CTLineGetStringIndexForPosition(line, relativePoint))
}
}
return NSNotFound
}