4

UITextView在 textView 下面和之后有其他视图UIScrollView。当用户输入文本时,我会更改 textView.contentSize.height 上的 textView 框架高度。这个想法是为用户保存所有文本和其他元素的可能性。我有一些问题。当用户点击我想滚动到这一行。这必须看起来像:

在此处输入图像描述

我无法确定如何计算偏移量并始终滚动到当前插入符号。

我的初始屏幕:

在此处输入图像描述

所有视图都是 的子视图UIScrollView。每次用户输入时,@"\n"我都会更改UITextView框架:

CGRect textViewFrame = textView.frame;
CGSize textViewContentSize = textView.contentSize;
NSLog(@"textView content size: %@", NSStringFromCGSize(textViewContentSize));
textViewFrame.size.height = textViewContentSize.height;
[textView setFrame:textViewFrame];

我增加UIScrollViewcontentSize。我的问题 - 我不明白如何在键盘下滚动到 textView 的CURSOR 。我尝试做一些事情:

CGPoint cursorPosition = [textView caretRectForPosition:textView.selectedTextRange.start].origin;

CGPoint relativeCursorPoint = [textView convertPoint:cursorPosition toView:scrollView];

if(textView.isFirstResponder && relativeCursorPoint.y >= scrollViewFrame.size.height + scrollView.contentOffset.y)
{
    int offset = relativeCursorPoint.y - scrollViewFrame.size.height + 18.0f;
    //int offset = textViewRect.origin.y - scrollViewFrame.size.height + 18.0f;
    [scrollView setContentOffset:CGPointMake(0, offset) animated:YES];
}

但它没有用。

4

4 回答 4

1

在此处输入图像描述

A.) 为了实现与 Apple Notes 滚动 + 键盘关闭类似的效果,我首先在 UIScrollView 中添加了一个 UITextView。

B.) 然后添加 self 作为键盘变化的观察者:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

C.) 然后当用户点击 textview / textfield 时,调用下面的方法。您获取键盘的开始高度和结束高度,并将名为keyboardHeight 的变量设置为endHeight 值(稍后使用)。

当用户上下移动自动更正/建议栏时,下面计算的“差异”用于上下移动文本。如果您不希望这样,您可以将 textView 上的“autocorrectionType”设置为 false。

-(void)keyboardWillChangeFrame:(NSNotification *)n {

    float beginHeight = [[n.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;
    float endHeight = [[n.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    float difference = beginHeight-endHeight;
    keyBoardHeight = endHeight; //set the var

    //animate change
    if (difference != 0){ //animate frame change in your textview }
}

D.) 在 textViewDidBegin 方法上,将 UIScrollview 移动到屏幕顶部,使 textview 与顶部齐平(setContentOffset)。

您计算 textview 的高度,因为它应该在视图顶部和键盘顶部之间,下面称为“initialTVHeight”。

您应该强制 textview 启用其滚动,因此将 textView.contentSize 设置为最小尺寸 (initialTVHeight) + 一个像素 - 这会强制滚动。

-(void)textViewDidBeginEditing:(UITextView *)textView {

    //need to move the tv up to the top
    float yOff = 0;
    yOff += durationCell.frame.size.height;
    yOff += reminderCell.frame.size.height;
    yOff += fixedCell.frame.size.height;
    yOff += repeatCell.frame.size.height;
    [mainScroller setContentOffset:CGPointMake(0, yOff) animated:true];

    //resize the textview to meet the top of the keyboard
    float padding = 0; //padding between keyboard and last line in the textview
    initialTVHeight = h - 60 - keyBoardHeight - padding; //the height when text does not overflow
    textTV.frame = CGRectMake(0, textTV.frame.origin.y, w, initialTVHeight); //set the frame to that size

    //if smaller than minimum, increase (if editing existing text)
    if (textTV.contentSize.height < initialTVHeight){
       textTV.contentSize = CGSizeMake(w, initialTVHeight+1); //force initial scroll
    }
}

E.) 此方法将 textView contentSize 更新为最小高度以确保启用滚动(即,如果只有两行文本,用户仍然可以反弹滚动)。textView 内容长于初始大小的地方,让它自然增长。

-(void)textViewDidChange:(UITextView *)textView {
    //require minimum height for scroll
    if (textTV.contentSize.height < initialTVHeight){ //content height comes in under, force scroll
        textTV.contentSize = CGSizeMake(w, initialTVHeight+1); //adding one forces scroll
    }
}

F.) 添加这些方法,以确保仅通过用户拖动(而不是用户输入新行)关闭键盘

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    if ([scrollView isEqual:textTV]){
        enableDragDismiss = true;
    }
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if ([scrollView isEqual:textTV]){
        enableDragDismiss = false;
    }
}

G.) 最后,添加这个方法,如果用户拖动到键盘高度以下,它会关闭键盘。

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    if (enableDragDismiss && [scrollView isEqual:textTV]){

        float y = [textTV.panGestureRecognizer locationInView:self.view].y;
        float keyboardY = h-keyBoardHeight;

        if (y > keyboardY){
            enableDragDismiss = false; //allow only once
            [textTV resignFirstResponder];
            [UIView animateWithDuration:0.5f
                                  delay:0.0f
                 usingSpringWithDamping:1.0f
                  initialSpringVelocity:0.8f
                                options:UIViewAnimationOptionCurveEaseOut
                             animations:^{
                                 mainScroller.contentOffset = CGPointMake(0, 0);
                                 textTV.contentOffset = CGPointMake(0, 0);
                             }
                             completion:^(BOOL finished){
                             }];

            float yOff = 60;
            yOff += durationCell.frame.size.height;
            yOff += reminderCell.frame.size.height;
            yOff += fixedCell.frame.size.height;
            yOff += repeatCell.frame.size.height;
            textTV.frame = CGRectMake(0, textTV.frame.origin.y, w, h-yOff);
        }
    }
}
于 2016-04-08T15:13:06.120 回答
0

好的,如果您尝试将 UITextView 滚动到键盘“上方”,那么您可以-[UITextView textViewDidBeginEditing:]在初始触摸时使用来修改 scrollView 的内容偏移量,但是如果您想在每次用户添加换行符或类似内容时滚动你应该可以使用-[UITextView shouldChangeTextInRange:]如下。

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    if ([text isEqualToString:@"\n"]) {
        // User has pressed 'return' and entered a new line
        // change the content offset + height of line text
        self.textView.contentOffset = CGPointMake(x, y);


        return NO;
    }

    return YES;
}

UITextView继承自,UIScrollView因此您可以像在UIScrollView.

于 2013-08-08T09:55:15.633 回答
0

试试这个,它对我有用

- (void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    return YES;
}    

- (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        activeField=textField;
    }

    -(void)keyboardWasShown:(NSNotification *)notification{
        float viewWidth = 1024;
        float viewHeight = 654;
        NSDictionary *keyboardInfo = [notification userInfo];
        CGSize keyboardSize = [[keyboardInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
        float keyboardHeight = keyboardSize.width;
        CGRect viewableAreaFrame = CGRectMake(0.0, 0.0, viewWidth, viewHeight - keyboardHeight);
        CGRect txtDemoFrame = [activeField.superview convertRect:activeField.frame toView:self.view];
        if (!CGRectContainsRect(viewableAreaFrame, txtDemoFrame)) {
            // We need to calculate the new Y offset point.
            //float scrollPointY = viewHeight - keyboardHeight;
            // Don't forget that the scroller should go to its original position
            // so store the current Y point of the content offset.
            self.originalScrollerOffsetY = self.SCRVMain.contentOffset.y;
            // Finally, scroll.
            [self.SCRVMain setContentOffset:CGPointMake(0.0, [activeField.superview convertPoint:activeField.frame.origin toView:self.view].y-200) animated:YES];
        }
    }
    -(void)keyboardWillHide:(NSNotification *)notification{
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        self.SCRVMain.contentInset = contentInsets;
        self.SCRVMain.scrollIndicatorInsets = contentInsets;
        [self.SCRVMain setContentOffset:CGPointMake(0.0, self.originalScrollerOffsetY) animated:YES];
    }
于 2013-08-08T10:16:25.423 回答
0

在我的 textViewDidChange: 我已经实现了这样的解决方案(为非常原始的代码道歉;)):

NSString* substringToSelection = [textView.text substringToIndex:textView.selectedRange.location];
UIFont* textFont = textView.font;

CGRect boundingRect = [substringToSelection boundingRectWithSize:CGSizeMake(textView.frame.size.width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : textFont} context:nil];
CGRect translatedRect = [textView convertRect:boundingRect toView:self.scrollView];

if (!CGRectContainsPoint(self.scrollView.bounds, CGPointMake(CGRectGetMaxX(translatedRect), CGRectGetMaxY(translatedRect))))
{
    [self.scrollView scrollRectToVisible:translatedRect animated:YES];
}
于 2013-11-26T23:11:52.013 回答