由于 UITextView 中的自定义行距,文本选择不正确

Posted

技术标签:

【中文标题】由于 UITextView 中的自定义行距,文本选择不正确【英文标题】:Text selection not happening properly because of custom line spacing in UITextView 【发布时间】:2016-11-07 01:32:02 【问题描述】:

我有一个自定义的UITextView 应用了自定义行距。当我尝试选择文本时,selectionRect 是错误的。 Check this image 突出显示正确,但 selectionRange 开始和结束处的句柄大小错误。该特定行应用了 50px 的 beforeSpacing 和 10px 的 afterSpacing。

相反,我希望它表现得像 this

我使用caretRectForPosition:修改了光标大小,并通过更改其矩形来修改光标的位置和大小,但不幸的是这不会影响选择期间的手柄。

如何根据我应用的字体大小和行距修改 selectionRect 或选择句柄的大小?

【问题讨论】:

经过大量研究,我发现我们可以覆盖-(NSArray*)selectionRectsForRange:(UITextRange *)range,并通过继承UITextSelectionView,我们可以为范围设置自定义selectionRect 【参考方案1】:

TL;DR: 您可以使用-(NSArray *)selectionRectsForRange,它的行为很奇怪并且没有很好地记录。 UITextView 在调用-(NSArray *)selectionRectsForRange 时返回的最后两个矩形宽度为零,它们决定了开始和结束光标的高度。创建一个子类,重写方法,调用 super 并修改最后两个矩形的高度。为了能够修改它们,您需要创建UITextSelectionRect 的子类,因为原始版本不可写(请参阅此答案的末尾)。

加长版: 这个方法在UITextView 中实现的方式很奇怪。这是我通过反复试验得出的结论:

如果你继承 UITextView,并像这样重写方法:

- (NSArray *)selectionRectsForRange:(UITextRange *)range

    NSArray* result = [super selectionRectsForRange:range];
    NSLog(@"%@", result);
    return result;

您将看到该方法返回一组跨越所选内容的矩形,还有两个宽度为零的矩形,它们与光标的位置重合。

有趣的是,改变数组的顺序对选择或光标位置没有任何影响,所以没有必要把这些矩形放在最后两个,而是苹果实现的一个细节。将它们全部删除会产生更有趣的效果:光标不会消失,任何选择矩形也不会消失。相反,光标采用相邻矩形的高度。选择整段文本时,这会导致光标跨越整个段落的高度。我的结论是,光标将自己定位到选择中左上角/右下角矩形的高度和位置,而苹果对-(NSArray *)selectionRectsForRange 的实现通过插入零宽度矩形来欺骗该系统。这绝不是确定的,并且系统可能存在一些更复杂的问题,涉及文本方向和其他怪癖。我在设备和模拟器上测试了我在 ios 8 和 10 上的假设。

奖励这是我的可变 UITextSelectionRect 子类:

@interface RichTextSelectionRect : UITextSelectionRect

//Prefix everything with _ because the original names are marked as readonly in the superclass
@property (nonatomic) CGRect _rect;
@property (nonatomic) UITextWritingDirection _writingDirection;
@property (nonatomic) BOOL _containsStart; // Returns YES if the rect contains the start of the selection.
@property (nonatomic) BOOL _containsEnd; // Returns YES if the rect contains the end of the selection.
@property (nonatomic) BOOL _isVertical; // Returns YES if the rect is for vertically oriented text.

@end

@implementation RichTextSelectionRect

- (CGRect)rect
    return __rect;


- (UITextWritingDirection)writingDirection
    return __writingDirection;


- (BOOL)containsStart

    return __containsStart;


- (BOOL)containsEnd

    return __containsEnd;


- (BOOL)isVertical

    return __isVertical;


@end

【讨论】:

谢谢 :) 我想通了

以上是关于由于 UITextView 中的自定义行距,文本选择不正确的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 列出多个自定义行编辑选项

列表视图自定义行

尤里卡中的自定​​义行

使用批处理/powershell 脚本设置自定义行分隔符

iOS之富文本

xlform 使用笔尖的自定义行