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];

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

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)。

テキストビューの高さは、ビューの上部とキーボードの上部の間にある必要があるため、以下で「initialTVHeight」と呼ばれます。

textview のスクロールを強制的に有効にする必要があるため、textView.contentSize を最小サイズ (initialTVHeight) + 1 ピクセルに設定します。これによりスクロールが強制されます。

-(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 を最小の高さに更新して、スクロールが有効になるようにします (つまり、テキストが 2 行しかない場合でも、ユーザーはスクロールをバウンスできます)。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

私の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 に答える
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 に答える