如何在用户输入时为UITextView设置光标位置?

7

我希望能够得到一个简单的答案来解决这个问题...

我有一个UITextView,用户可以在其中开始输入并单击“完成”按钮以退出键盘。

当用户再次想要编辑它时,我希望光标(闪烁的线)位于textView的第一个位置,而不是在textView末尾。 (像占位符一样)

我尝试在textViewDidBeginEditing上使用具有NSMakeRange(0,0)setSelectedRange,但它不起作用。

更多信息:

可以看到...当用户点击textView时,光标出现在用户点击textView的位置。

textViewDidBeginEditing时,我希望它始终闪烁在起始位置。


请看这个链接是否有帮助 - https://dev59.com/93I_5IYBdhLWcg3wK_o6 - tipycalFlow
@tipycalFlow:谢谢,但我已经检查过了。这与我的问题无关。 - Legolas
6个回答

19

属性selectedRange不能在"任何地方"赋值,要使其起作用,您需要实现方法- (void)textViewDidChangeSelection:(UITextView *)textView,在您的情况下:

- (void)textViewDidChangeSelection:(UITextView *)textView
{
    [textView setSelectedRange:NSMakeRange(0, 0)];
}

您需要检测用户何时开始编辑或选择文本


3
这是我目前发现的最佳解决方案。这真的应该是最佳答案! - Andy Poes
运行得非常好!谢谢! - Mike Critchley
传说!在Stack Overflow上搜索总比阅读文档快 :) - Jacopo Penzo

11

我的解决方案:

- (void) viewDidLoad {
    UITextView *textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, 200, 200)];
    textView.text = @"This is a test";
    [self.view addSubview: textView];
    textView.delegate = self;
    [textView release];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(tapped:)];
    [textView addGestureRecognizer: tap];
    [tap release];
}
- (void) tapped: (UITapGestureRecognizer *) tap {
    [textView becomeFirstResponder];
} 

- (void) textViewDidBeginEditing:(UITextView *)textView {
    textView.selectedRange = NSMakeRange(0, 0);
}

我猜这是UITextView内部机制,用于在用户点击它时设置光标。我们需要通过附加一个tap手势识别器并调用 becomeFirstResponder 来覆盖它。


您发布的链接无效 - 未知的粘贴ID! - Legolas
你好,我的代码使用自定义键盘时没有显示输入光标,请帮忙解决一下? - Ramani Hitesh

7
我遇到了同样的问题-基本上在成为第一响应者时会有延迟,这不允许你在任何textView * BeginEditing:方法中更改selectedRange。如果您尝试延迟setSelectedRange:(假设使用performSelector:withObject:afterDelay:),它会显示难看的抖动。
解决方案实际上非常简单-检查委托方法的顺序会给您提示:
  1. textViewShouldBeginEditing:
  2. textViewDidBeginEditing:
  3. textViewDidChangeSelection:
在最后一个方法(3)中设置selectedRange就可以解决问题,您只需要确保仅在UITextView成为第一响应者时重新定位光标,因为每次更新内容时都会调用该方法(3)。
shouldChangeTextInRange:中设置BOOL变量并在(3)中检查该变量应该解决问题...只是不要忘记在重新定位后重置变量以避免不断重置光标:)。
希望能帮到您!
编辑
经过几轮测试后,我决定在shouldChangeTextInRange:中设置BOOL标志,而不是(2)或(3),因为它被证明更加通用。看看我的代码:
@interface MyClass
{
    /** A flag to determine whether caret should be positioned (YES - don't position caret; NO - move caret to beginning). */
    BOOL _isContentGenerated;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    // deleting
    if([text length] == 0)
    {
        // deleting last character
        if(range.length == [[textView text] length])
        {
            // reached beginning
            /** 
             code to show placeholder and reset caret to the beginning 
            */
            _isContentGenerated = NO;
        }
    }
    else
    {
        // adding
        if(range.location == 0)
        {
            /** 
             code to hide placeholder
            */
            _isContentGenerated = YES;
        }
    }
    return YES;
}

- (void)textViewDidChangeSelection:(UITextView *)textView
{
    if(!_isContentGenerated)
    {
        [textView setSelectedRange:NSMakeRange(0, 0)];
    }
}

很好的回答,但可以通过添加代码来改进。 - meaning-matters
@meaning-matters 现在,这才是我所说的圣诞节 :D 谢谢! - David Jirman

1

我对此还没有足够的经验来完全帮助你,但是当您尝试使用不同的selectedRange时会发生什么呢?比如,如果您执行[... setSelectedRange:[NSMakeRange(0,1)]]或者[... setSelectedRange:[NSMakeRange(1,0)]],它是否会移动光标?


嗯,就像我在问题中所述的那样。它不起作用。光标位置=用户点击的位置。 - Legolas
如果它没有改变行为,那么它似乎根本没有调用您的 setSelectedRange。在调用上设置断点并跟踪它? - Argent
它确实调用了它。我的担忧是,那并没有解决问题。 - Legolas

0
所以我最后在UITextView上添加了一个UILabel,它充当textView的占位符。点击UILabel会将动作传递给textView并成为第一响应者。一旦开始输入,隐藏标签。

2
这看起来非常笨拙。为什么不用UIView代替UILabel呢? - fatuhoku
1
@fatuhoku:“...在UITextView上放置一个UILabel,作为textView的占位符。” - ghr

-4
[_detailAreaView setTextContainerInset:UIEdgeInsetsMake(8, 11, 8, 11)];

1
这并不涉及问题,这只是展示如何创建一个插入,从而在textview内移动文本位置。 - Elliot Blackburn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接