确定UIScrollVIew中UITextView的滚动偏移量

时间:2013-08-08 09:20:14

标签: ios objective-c uiscrollview uitextview

我在UITextView中的textView之后和之后有UIScrollView和其他观点。 当用户输入文本时,我在textView.contentSize.height上更改textView框架高度。 这个想法是节省用户查看所有文本和其他元素的可能性。 我有一些问题。当用户点击我想滚动到这一行。这看起来似乎是:

enter image description here

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

我的初始屏幕:

enter image description here

所有观看次数均为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];

我增加UIScrollView contentSize。 我的问题 - 我不明白如何在键盘下滚动到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 个答案:

答案 0 :(得分:1)

enter image description here

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与top(setContentOffset)齐平。

您可以计算文本视图的高度,因为它应该位于视图顶部和键盘顶部之间,在下面称为“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);
        }
    }
}

答案 1 :(得分: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中一样更改内容偏移。

答案 2 :(得分: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];
    }

答案 3 :(得分: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];
}