我正在研究用UITextFields替换占位符的text view。我将包含占位符标记的多个实例的文本传递给对象(结构或字典)。该词典还包含一个我们要从中收集数据的字段数组。我的目标是在整个文本中放置UITextFields(或其他 View ),并隐藏标记。
使用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
}
// ...
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
}
在这一点上,我有三个问题:
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
}
}
现在,我计算出的头寸都返回0、0。这不是我们想要的。可以理解的是,添加排除路径会使计算的位置无效,但是每个rect方法返回0、0都无济于事。
添加排除路径或隐藏字形后,如何要求布局管理器重新计算字形在屏幕上的位置?
编辑:根据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
}
最佳答案
我只能在TextKit刚接触时就提出建议,但是您的代码中有些刺眼的东西给我,我想我会提到它以防万一。
在createAndAssignExclusionPathsForInputTextFields函数中,您正在按self.textFields数组的顺序处理字段。
当您在函数末尾设置self.textContainer.exclusionPaths的值时,布局管理器将(可能)在所有排除项附近重排文本,从而使您执行的某些计算无效,而没有考虑其他因素的影响排除。
解决此问题的方法是对self.textFields数组进行排序,以便它们与文本流相对应(我可能无法确定它们的顺序)。然后,您必须清除self.textContainer.exclusionPaths中的所有排除项,并将它们一个接一个地添加回去,以便在计算下一个排除项之前,布局管理器已围绕先前添加的排除项对文本进行了重排。 (我相信每次您设置排除对象时都会这样做,但如果没有设置,则可能需要调用layoutManager的sureLayoutForManager函数)
您必须按文本流顺序执行此操作,以便将每个排除项添加到不会使以前的任何排除项无效的文本区域中。
也可以进行优化以避免完全清除/重建排除项,但是我建议在尝试之前达到工作基准。
关于ios - 使用Text Kit插入带有UITextView的UITextFields?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34296583/