IT TIP

UITextField가 첫 번째 응답자가 될 때 UIScrollView 스크롤 비활성화

itqueen 2020. 12. 3. 21:31
반응형

UITextField가 첫 번째 응답자가 될 때 UIScrollView 스크롤 비활성화


UITextField에 포함 된, UIScrollView가 첫 번째 응답자가 될 때 사용자가 일부 문자를 입력 UIScrollView하면 해당 필드로 자동으로 스크롤됩니다.이를 비활성화 할 수있는 방법이 있습니까?

중복 rdar : // 16538222 이상


Moshe의 대답을 바탕으로 ...

UIScrollView를 하위 클래스로 만들고 다음 메서드를 재정의합니다.

- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated

비워 둡니다. 완료되었습니다!


나는 같은 문제로 고심하고 있었고 마침내 해결책을 찾았습니다.

콜 트레이스를 추적하여 자동 스크롤이 어떻게 수행되는지 조사한 결과 [UIFieldEditor scrollSelectionToVisible].NET Framework에 문자를 입력 할 때 내부 가 호출 되는 것을 발견했습니다 UITextField. 이 방법 UIScrollView은의 가장 가까운 조상 에서 작동하는 것으로 보입니다 UITextField.

따라서에서를 같은 크기의 new textFieldDidBeginEditing래핑하면 (즉, superview와 superview 사이에 뷰를 삽입 ) 자동 스크롤이 차단됩니다. 마지막으로이 래퍼를 .UITextFieldUIScrollViewUITextFieldtextFieldDidEndEditing

코드는 다음과 같습니다.

- (void)textFieldDidBeginEditing:(UITextField*)textField {  
    UIScrollView *wrap = [[[UIScrollView alloc] initWithFrame:textField.frame] autorelease];  
    [textField.superview addSubview:wrap];  
    [textField setFrame:CGRectMake(0, 0, textField.frame.size.width, textField.frame.size.height)]; 
    [wrap addSubview: textField];  
}  

- (void)textFieldDidEndEditing:(UITextField*)textField {  
  UIScrollView *wrap = (UIScrollView *)textField.superview;  
  [textField setFrame:CGRectMake(wrap.frame.origin.x, wrap.frame.origin.y, wrap.frame.size.width, textField.frame.size.height)];
  [wrap.superview addSubview:textField];  
  [wrap removeFromSuperview];  
}  

도움이 되었기를 바랍니다!


UITextView셀의 자동 스크롤을 비활성화하는 것과 동일한 문제가 발생했습니다 UITableView. 다음 접근 방식을 사용하여 해결할 수있었습니다.

@interface MyTableViewController : UITableViewController<UITextViewDelegate>

@implementation MyTableViewController {
    BOOL preventScrolling;
    // ...
}

// ... set self as the delegate of the text view

- (void)textViewDidBeginEditing:(UITextView *)textView {
    preventScrolling = YES;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (preventScrolling) {
        [self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:NO];
    }
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    preventScrolling = NO;
}

정의 scrollViewWillBeginDragging는 사용자가 스크롤을 시작할 때 기본 스크롤 동작을 복원하는 데 사용됩니다.


Taketo가 언급했듯이 a UITextField가 첫 번째 응답자로 만들어지면 유형 UIScrollView(있는 경우 ) 인 첫 번째 상위 뷰 가 스크롤되어 UITextField표시됩니다. 가장 쉬운 방법은 단순히 각 UITextField를 UIScrollView하나의 더미로 감싸는 것입니다 (또는 이상적으로는 모두 하나의 더미로 감싸는 것입니다 UIScrollView). 이것은 Taketo의 솔루션과 매우 유사하지만 약간 더 나은 성능을 제공해야하며 제 생각에는 코드 (또는 Interface Builder의 인터페이스)를 훨씬 깔끔하게 유지할 것입니다.


Luke의 대답을 바탕으로 그의 솔루션이 자동 스크롤을 완전히 비활성화하는 문제를 처리하기 위해 다음과 같이 선택적으로 비활성화 할 수 있습니다.

//  TextFieldScrollView
#import <UIKit/UIKit.h>

@interface TextFieldScrollView : UIScrollView

@property (assign, nonatomic) IBInspectable BOOL preventAutoScroll;

@end

@implementation TextFieldScrollView

- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
    if (self.preventAutoScroll == NO) {
        [super scrollRectToVisible:rect animated:animated];
    }
}

@end

이렇게하면 자동 스크롤을 비활성화하도록 Interface Builder에서 완전히 설정할 수 있지만 언제든지 다시 활성화 할 수있는 모든 권한을 가질 수 있습니다.


UITextfield를 포함하는 UIScrollview처럼 보이며 콘텐츠 오프셋을 자동으로 조정합니다. 텍스트 필드가 첫 번째 응답자가 될 때. 이 문제는 먼저 동일한 크기의 scrollview에 텍스트 필드를 추가 한 다음 메인 스크롤 뷰에 추가하여 해결할 수 있습니다. 기본 scrollview에 직접 추가하는 대신

    // Swift

    let rect = CGRect(x: 0, y: 0, width: 200, height: 50)

    let txtfld = UITextField()
    txtfld.frame = CGRect(x: 0, y: 0, width: rect.width, height: rect.height)

    let txtFieldContainerScrollView = UIScrollView()
    txtFieldContainerScrollView.frame = rect
    txtFieldContainerScrollView.addSubview(txtfld)
    // Now add this txtFieldContainerScrollView in desired UITableViewCell, UISCrollView.. etc
    self.mainScrollView.addSubview(txtFieldContainerScrollView)

    // Am33T

이것이 내가하는 방법입니다.

매우 간단합니다. scrollRectToVisible에 대해 자신의 contentOffset을 반환합니다.

이렇게하면 정상적인 동작과 사물의 흐름에 해를 끼치 지 않고 동일한 채널에서 동일한 기능을 제공하고 자신의 개선 사항을 개선 할 수 있습니다.

#import <UIKit/UIKit.h>

@protocol ExtendedScrollViewDelegate <NSObject>

- (CGPoint)scrollView:(UIScrollView*)scrollView offsetForScrollingToVisibleRect:(CGRect)rect;

@end

@interface ExtendedScrollView : UIScrollView

@property (nonatomic, unsafe_unretained) id<ExtendedScrollViewDelegate> scrollToVisibleDelegate;

@end

#import "ExtendedScrollView.h"

@implementation ExtendedScrollView

- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
{
    if (_scrollToVisibleDelegate && [_scrollToVisibleDelegate respondsToSelector:@selector(scrollView:offsetForScrollingToVisibleRect:)])
    {
        [self setContentOffset:[_scrollToVisibleDelegate scrollView:self offsetForScrollingToVisibleRect:rect] animated:animated];
    }
    else
    {
        [super scrollRectToVisible:rect animated:animated];
    }
}

@end

@TaketoSano의 대답을 시도했지만 작동하지 않는 것 같습니다. 제 경우에는 스크롤 뷰가없고 여러 텍스트 필드가있는 뷰만 있습니다.

그리고 마지막으로 해결 방법이 있습니다. 필요한 키보드에 대한 두 가지 기본 알림 이름이 있습니다.

  • UIKeyboardDidShowNotification 키보드가 표시되었을 때;
  • UIKeyboardWillHideNotification when the keyboard will hide.

Here's the sample code I used:

- (void)viewDidLoad {
  [super viewDidLoad];

  ...

  NSNotificationCenter * notificationCetner = [NSNotificationCenter defaultCenter];
  [notificationCetner addObserver:self
                         selector:@selector(_keyboardWasShown:)
                             name:UIKeyboardDidShowNotification
                           object:nil];
  [notificationCetner addObserver:self
                         selector:@selector(_keyboardWillHide:)
                             name:UIKeyboardWillHideNotification
                           object:nil];
}

- (void)_keyboardWasShown:(NSNotification *)note {
  [self.view setFrame:(CGRect){{272.f, 55.f}, {480.f, 315.f}}];
}

- (void)_keyboardWillHide:(NSNotification *)note {
  [self.view setFrame:(CGRect){{272.f, 226.5f}, {480.f, 315.f}}];
}

Here, the (CGRect){{272.f, 226.5f}, {480.f, 315.f}} is view's default frame when keyboard is hidden. And (CGRect){{272.f, 55.f}, {480.f, 315.f}} is view's frame when keyboard did show.

And b.t.w., the view's frame changing will be applied animation automatically, this's really perfect!


I have a collection view with a text field at the very top, mimicking the UITableView.tableHeaderView. This text field is located in the negative content offset space so that it doesn't interfere with the rest of the collection view. I basically am detecting whether or not the user is performing the scrolling in the scroll view and whether or not the text field is first responder and if the scroll view is being scrolled beyond the top of the scroll view's content inset. This exact code won't necessarily help anyone but they could manipulate it to fit their case.

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

    // This is solving the issue where making the text field first responder
    // automatically scrolls the scrollview down by the height of the search bar.
    if (!scrollView.isDragging && !scrollView.isDecelerating &&
        self.searchField.isFirstResponder &&
        (scrollView.contentOffset.y < -scrollView.contentInset.top)) {

        [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, -scrollView.contentInset.top) animated:NO];
    }
}

I don't know of any property of UIScrollView that would allow that. It would be poor user experience to be able to disable that, IMHO.

That said, it may be possible to subclass UIScrollView and override some of its methods to check that the UITextfield is not a first responder before scrolling.


An easier way to stop the scrollview scrolling when you select a textField is in your viewController::viewWillAppear() DO NOT call [super viewWillAppear];

You can then control the scroll as you wish.

참고URL : https://stackoverflow.com/questions/4585718/disable-uiscrollview-scrolling-when-uitextfield-becomes-first-responder

반응형