Mos*_*she 13 layout uitextview ios textkit
我正在开发一个文本视图,用UITextFields替换占位符.我传递了一个对象(结构或字典),其中包含多个占位符令牌实例的文本.该字典还包含我们想要从中收集数据的字段数组.我的目标是在我的文本中放置UITextFields(或其他视图),并隐藏令牌.
使用NSLayoutManager方法计算文本容器中占位符标记的位置,我将这些点转换为CGRects然后排除路径到文本字段周围.这是看起来像:
func createAndAssignExclusionPathsForInputTextFields () {
var index = 0
let textFieldCount = self.textFields.count
var exclusionPaths : [UIBezierPath] = []
while index < textFieldCount {
let textField : AgreementTextField = self.textFields[index]
let location = self.calculatePositionOfPlaceholderAtIndex(index)
let size = textField.intrinsicContentSize()
textField.frame = CGRectMake(location.x, location.y, size.width, size.height)
exclusionPaths.append(textField.exclusionPath())
index = index + 1
}
self.textContainer.exclusionPaths = exclusionPaths
}
Run Code Online (Sandbox Code Playgroud)
// ...
func calculatePositionOfPlaceholderAtIndex(textIndex : NSInteger) -> CGPoint {
let layoutManager : NSLayoutManager = self.textContainer.layoutManager!
let delimiterRange = self.indices[textIndex]
let characterIndex = delimiterRange.location
let glyphRange = self.layoutManager.glyphRangeForCharacterRange(delimiterRange, actualCharacterRange:nil)
let glyphIndex = glyphRange.location
let rect = layoutManager.lineFragmentRectForGlyphAtIndex(glyphIndex, effectiveRange: nil, withoutAdditionalLayout: true)
let remainingRect : UnsafeMutablePointer<CGRect> = nil
let textContainerRect = self.textContainer.lineFragmentRectForProposedRect(rect, atIndex: characterIndex, writingDirection: .LeftToRight, remainingRect: remainingRect)
let position = CGPointMake(textContainerRect.origin.x, textContainerRect.origin.y)
return position
}
Run Code Online (Sandbox Code Playgroud)
此时,我有三个问题:
calculatePositionOfPlaceholderAtIndex方法给了我很好的y值,但x值都是0.因此,为了解决我的列表中的第一个问题,我尝试在计算下一个问题之前添加排除路径,方法是createAndAssignExclusionPathsForInputTextFields:
func createAndAssignExclusionPathsForInputTextFields () {
var index = 0
let textFieldCount = self.textFields.count
while index < textFieldCount {
let textField : AgreementTextField = self.textFields[index]
let location = self.calculatePositionOfPlaceholderAtIndex(index)
let size = textField.intrinsicContentSize()
textField.frame = CGRectMake(location.x, location.y, size.width, size.height)
self.textContainer.exclusionPaths.append(textField.exclusionPath())
index = index + 1
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我的计算位置都返回0,0.不是我们想要的.可以理解地添加排除路径会使计算的位置无效,但是每个rect方法返回0,0都没有用.
在添加排除路径或隐藏字形后,如何让布局管理器重新计算屏幕上字形的位置?
编辑: Per Alain T的答案,我尝试了下面没有运气:
func createAndAssignExclusionPathsForInputTextFields () {
var index = 0
let textFieldCount = self.textFields.count
var exclusionPaths : [UIBezierPath] = []
while index < textFieldCount {
let textField : AgreementTextField = self.textFields[index]
let location = self.calculatePositionOfPlaceholderAtIndex(index)
let size = textField.intrinsicContentSize()
textField.frame = CGRectMake(location.x, location.y, size.width, size.height)
exclusionPaths.append(textField.exclusionPath())
self.textContainer.exclusionPaths = exclusionPaths
self.layoutManager.ensureLayoutForTextContainer(self.textContainer)
index = index + 1
}
self.textContainer.exclusionPaths = exclusionPaths
}
Run Code Online (Sandbox Code Playgroud)
我只能提出建议,因为我自己是 TextKit 的新手,但你的代码中有些东西让我感到震惊,我想我会提到它,以防它能有所帮助。
在 createAndAssignExclusionPathsForInputTextFields 函数中,您按照 self.textFields 数组的顺序处理字段。
当您在函数末尾设置 self.textContainer.exclusionPaths 的值时,布局管理器将(可能)重新排列所有排除项周围的文本,从而使您执行的某些计算无效,而无需考虑其他计算的影响排除。
解决这个问题的方法是对 self.textFields 数组进行排序,以便它们与文本流相对应(它们可能已经按这个顺序排列,我不知道)。然后,您必须清除 self.textContainer.exclusionPaths 中的所有排除项,并将它们一一添加回来,以便在计算下一个排除项之前,布局管理器已重新排列先前添加的排除项周围的文本。(我相信每次设置排除时它都会执行此操作,但如果没有,您可能需要调用layoutManager的ensureLayoutForManager函数)
您必须按文本流顺序执行此操作,以便将每个排除项添加到不会使任何先前排除项无效的文本区域上。
对此进行优化以避免完全清除/重建排除也是可能的,但我建议在尝试之前先达到工作基线。