텍스트를 변경할 때마다 UITextView를 맨 위로 스크롤하려면 어떻게해야합니까?


100

OK, 나는 몇 가지 문제가 있어요 UITextView. 문제는 다음과 같습니다.

나는 UITextView. 그런 다음 사용자는 두 번 클릭하여 항목을 선택합니다. 그런 다음 UITextView(위와 같이 프로그래밍 방식으로) 텍스트를 변경하고 UITextView 커서가있는 페이지 하단으로 스크롤합니다.

그러나 그것은 사용자가 클릭 한 곳이 아닙니다. UITextView사용자가 클릭 한 위치에 관계없이 항상 맨 아래로 스크롤됩니다 .

그래서 여기에 내 질문이 UITextView있습니다. 텍스트를 변경할 때마다 어떻게 강제로 맨 위로 스크롤합니까? 나는 해봤 contentOffset하고 scrollRangeToVisible. 둘 다 작동하지 않습니다.

모든 제안을 주시면 감사하겠습니다.

답변:


148
UITextView*note;
[note setContentOffset:CGPointZero animated:YES];

이것은 나를 위해 그것을합니다.

Swift 버전 (Xcode 9.3에서 iOS 11이 설치된 Swift 4.1) :

note.setContentOffset(.zero, animated: true)

13
날 도와주지 마.
Dmitry

6
이것은 작동하지만 어쨌든 이것이 필요한 이유는 무엇입니까? 애플의 스크롤 로직은 개선이 필요하며 대부분의 경우 자동으로 작동하도록하기에는 후프 점프가 너무 많습니다.
John Contarino 2015 년

4
iOS 9에서 저에게 적합하지만 viewDidAppear().
Murray Sagal 2016

4
viewDidLayoutSubviews ()에서 호출하여 viewDidAppear ()보다 일찍 호출 할 수 있습니다.
arcady bob

나는 테이블의 셀에 텍스트보기를 추가 했으므로 행에 대한 셀에 이것을 설정했지만 작동하지 않습니다
Chandni

67

사람이 아이폰 OS 8에서이 문제가 있다면, 그건 바로 설정을 발견 UITextView's한 후 호출, 텍스트 속성을 scrollRangeToVisibleNSRangelocation:0, length:0,했다. 내 텍스트보기는 편집 할 수 없었고 선택 가능과 선택 불가능을 테스트했습니다 (두 설정 모두 결과에 영향을주지 않음). 다음은 Swift의 예입니다.

myTextView.text = "Text that is long enough to scroll"
myTextView.scrollRangeToVisible(NSRange(location:0, length:0))

감사합니다. 위의 어느 것도 나를 위해 일하지 않았습니다. 당신의 샘플이 그랬습니다.
user1244109

작동하지만 비활성화해야하는 스크롤 애니메이션이 표시됩니다. 저는 @miguel이 제안한 것처럼 스크롤을 비활성화하고 다시 활성화하는 것을 선호합니다.
Warpzit

Objective-C : [myTextView scrollRangeToVisible : NSMakeRange (0, 0)];
상태 저장

이것은 더 이상 작동하지 않는 것 같습니다. iOS 9 및 Xcode 7.3.1 : /
wasimsandhu

Swift 3 Stll이 작동합니다! :) UITextFielDelegate 메서드에서이 줄을 복사합니다. `FUNC의 textViewDidEndEditing (_ 텍스트 뷰 : UITextView) {textView.scrollRangeToVisible (NSRange (위치 : 0, 길이 : 0))}`
lifewithelliott

46

그리고 여기 내 해결책이 있습니다 ...

    override func viewDidLoad() {
        textView.scrollEnabled = false
        textView.text = "your text"
    }

    override func viewDidAppear(animated: Bool) {
        textView.scrollEnabled = true
    }

5
나는이 솔루션이 마음에 들지 않지만 적어도 iOS 9 베타 5부터는 나에게 적합한 유일한 방법입니다. 다른 솔루션의 대부분은 텍스트보기가 이미 표시되어 있다고 가정하고 있습니다. 제 경우에는 항상 사실이 아니므로 스크롤이 나타날 때까지 스크롤을 계속 비활성화해야합니다.
robotspacer

1
이것은 나에게도 효과가 있었던 유일한 것입니다. 편집 불가능한 textview를 사용하는 iOS 9.
SeanR

1
이것은 속성 문자열이있는 iOS 8 편집 불가능한 텍스트 뷰에서 작동합니다. viewWillAppear에서 - 작동하지 않습니다
티나 조이

@robotspacer에 동의합니다. 이 솔루션은 여전히 ​​저에게 적합한 유일한 솔루션입니다.
lerp90

저에게이 솔루션은 짧은 (기여 된) 텍스트로만 작동했습니다. 더 긴 텍스트가있을 때 UITextView 스크롤 버그는 계속 살아 있습니다. :-) 내 (조금 못생긴) 해결책은 dispatch_after를 사용하여 스크롤을 다시 활성화하기 위해 2 초 지연을 사용하는 것입니다. UITextView는 ... 그 텍스트 레이아웃을 할 시간의 작은 금액을 필요로하는 것
LaborEtArs

38

부름

scrollRangeToVisible(NSMakeRange(0, 0))

작동하지만 전화

override func viewDidAppear(animated: Bool)

4
나는 그것이 viewDidAppear에서만 나에게 효과적이라고 고백합니다.
에릭 f.

2
이것은 나를 위해 일하는 유일한 것입니다. 고마워. 하지만 약간 짜증나는 애니메이션을 어떻게 비활성화합니까?
rockhammer

이것이 작동하지만, 나는 @Maria의 솔루션이 더 낫습니다. 그 이유는 짧은 "점프"를 보여주지 않기 때문입니다.
Sipke Schoorstra

1
마지막 댓글을 다시 가져옵니다. 마리아의 대답은 아이폰 OS (11)에 잘 작동하지 않습니다 @ 반면이 모두 아이폰 OS (10)와 아이폰 OS (11)에 작동하기 때문에이 나를 위해 최선의 답변입니다
Sipke Schoorstra

@SipkeSchoorstra, 점프없이 작동하도록 아래 내 대답을 참조하십시오 (KVO 사용).
Terry

29

HTML에서 편집 할 수없는 텍스트보기로 attributeString을 사용했습니다. 콘텐츠 오프셋 설정도 나에게 효과적이지 않았습니다. 이것은 나를 위해 일했습니다 : 스크롤 활성화를 비활성화하고 텍스트를 설정 한 다음 스크롤을 다시 활성화하십시오.

[yourTextView setScrollEnabled:NO];
yourTextView.text = yourtext;
[yourTextView setScrollEnabled:YES];

tableViewCell 안에 textView가 있습니다. 이 경우 textView가 약으로 스크롤되었습니다. 50 %. 이 솔루션은 논리적으로 간단합니다. 감사합니다
Julian F. Weinert 2015-08-13

1
@ JulianF.Weinert iOS10에서 작동하지 않는 것 같습니다. tableViewCell의 textView를 사용하는 것과 동일한 상황이 있습니다. textView의 편집 기능을 사용하고 있지 않습니다. 스크롤 가능한 텍스트를 원합니다. 그러나 textView는 항상 약 50 %로 스크롤됩니다. 이 게시물에서 setContentOffset 및 scrollRangeToVisible을 설정하여 다른 모든 제안을 시도했습니다. 작동하지 않습니다. 이 작업을 수행하기 위해 수행 한 다른 작업이 있습니까?
JeffB6688

@ JeffB6688 죄송합니다. 정말 오래 전 일입니다. "새로운"iOS 릴리스의 또 다른 특징일까요?
Julian F. Weinert 2017 년

그러나 불행히도 iOS 11.2에서는 완벽하지 않습니다. 모두 아이폰 OS (10)와 아이폰 OS (11)에 Onlu @RyanTCB의 응답 작품
Sipke Schoorstra

이것은 아이폰 OS 9, 10, 11에 지금까지 나를 위해 잘 작동합니다,하지만 난 그것을 가능하게했던 viewDidAppear수정의 폭 넓은 심각한의 일환으로
MadProgrammer

19

이러한 솔루션 중 어느 것도 저에게 효과가 없었고 솔루션을 결합하는 데 너무 많은 시간을 낭비했기 때문에 마침내 해결되었습니다.

override func viewWillAppear(animated: Bool) {
    dispatch_async(dispatch_get_main_queue(), {
        let desiredOffset = CGPoint(x: 0, y: -self.textView.contentInset.top)
        self.textView.setContentOffset(desiredOffset, animated: false)
    })
}

이 컨트롤의 기본 동작이 아니라는 것은 정말 어리석은 일입니다.

이 정보가 다른 사람에게 도움이되기를 바랍니다.


2
이것은 매우 도움이되었습니다! 또한 다음을 추가해야했습니다. self.automaticallyAdjustsScrollViewInsets = NO; UITextView가 포함 된 뷰에 추가하여 완전히 작동하도록합니다.
jengelsma

나는 단지 또 다른 오프셋 CALC로, SWIFT 3 일 만든 self.textView.contentOffset.y이 답변에 따라 stackoverflow.com/a/25366126/1736679
Efren

Swift 3의 최신 구문에 적응하면 저를 위해 일했습니다
hawmack13

이것이 얼마나 미친 짓인지 완전히 동의합니까? 솔루션에 대한 감사
ajonno

17

질문을 이해했는지 확실하지 않지만 단순히보기를 맨 위로 스크롤하려고합니까? 만약 그렇다면

[textview scrollRectToVisible:CGRectMake(0,0,1,1) animated:YES];


1
@SamStewart 링크가 끊어진 것 같습니다. 항상 내 계정 페이지 (이미 로그인)로 연결됩니다. 그들이 제공하는 솔루션에 대한 자세한 정보를 제공 할 수 있습니까?
uliwitness

@uliwitness 이것은 이제 매우 오래된 정보입니다. 8 년 된 게시물 대신 더 현대적인 리소스를 시도하는 것이 좋습니다. iOS API는 그 8 년 동안 극적으로 변했습니다.
Benjamin Sussman

1
새로운 정보를 찾으려고 노력했습니다. 어디서 찾을 수 있는지 아시면 감사하겠습니다. 여전히 같은 문제 :( 것 같다
uliwitness

13

iOS 10 및 Swift 3의 경우 다음을 수행했습니다.

override func viewDidLoad() {
    super.viewDidLoad()
    textview.isScrollEnabled = false
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    textView.isScrollEnabled = true
}

나를 위해 일했지만 최신 버전의 Swift 및 iOS에 문제가 있는지 확실하지 않습니다.


따라야 할 완벽한 솔루션!
iChirag

UIPageViewController에 의해 제어되는 UIView의 UITextView에 스크롤 문제가 있습니다. (이 페이지는 내 도움말 / 정보 화면을 표시합니다.) 솔루션은 첫 번째 페이지를 제외한 모든 페이지에서 작동합니다. 임의의 페이지로 스 와이프하고 첫 번째 페이지로 돌아 가면 해당 첫 페이지의 스크롤 위치가 고정됩니다. 다른 .isScrollEnabled = False를 viewWillAppear에 추가하려고 시도했지만 효과가 없었습니다. 첫 페이지가 나머지 페이지와 다르게 작동하는 이유가 궁금합니다.
Wayne Henderson

[업데이트] 방금 해결했습니다! .isScrollEnabled = true 트리거 전에 0.5 초의 지연을 도입하면 첫 번째로드 문제가 해결됩니다.
Wayne Henderson

아주 좋아. . .
Maysam R

매력처럼 작동했습니다. 나를 위해 일하는 유일한 솔루션. 당신은 남자입니다.
Lazy Ninja

10

사용자가 스크롤 애니메이션을 경험하지 않고 textview가 올바르게 표시되도록 업데이트 된 답변이 있습니다.

override func viewWillAppear(animated: Bool) {
    dispatch_async(dispatch_get_main_queue(), {
        self.introductionText.scrollRangeToVisible(NSMakeRange(0, 0))
    })

왜 메인 대기열에서하는지, 사인 viewWillAppear가 메인 대기열에서 실행되고 있습니까?
karthikPrabhu Alagu

1
기억하기에는 너무 오래 전이지만 여기에 주소가 지정되어 있습니다. stackoverflow.com/a/17490329/4750649
MacInnis

8

이것은 화면에 나타나기 전에 textView가 맨 위로 스크롤되도록 iOS 9 Release에서 작동 한 방식입니다.

- (void)viewDidLoad
{
    [super viewDidLoad];
    textView.scrollEnabled = NO;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    textView.scrollEnabled = YES;
}

1
이것은 트릭을했다. 덧붙여서, 그것은 나에게 매우 중요한 것을 가르쳐주었습니다. 'viewwillappear'의 'view'는 self.view를 가리키는 것이 아니라 분명히 모든 뷰를 가리 킵니다. 아니?
Sjakelien

8

그렇게 했어요

스위프트 4 :

extension UITextView {

    override open func draw(_ rect: CGRect)
    {
        super.draw(rect)
        setContentOffset(CGPoint.zero, animated: false)
    }

 }

이것은 나에게 최상의 결과를 제공하는 유일한 방법입니다. 나는 찬성합니다.
smoothBlue

7

이것은 나를 위해 일했습니다.

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    DispatchQueue.main.async {
      self.textView.scrollRangeToVisible(NSRange(location: 0, length: 0))
    }
  }

이것은 매우 이상합니다. 대부분의 장치에서 전화를 래핑 할 DispatchQueue.main.async(...필요는 없지만 어떤 이유로 인해 (예 : iPhone 5s (iOS 12.1)에서는 발송하지 않는 한 작동하지 않습니다. 하지만 디버거의 호출 스택에 의해보고 된대로 모든 경우 viewWillAppear() 에 이미 메인 대기열 에서 실행 중입니다 ...-WTF, Apple ???
Nicolas Miari

2
또한 메인 큐에서 모든 이벤트를 실행하고 있는데도 메인 큐에서 명시 적으로 디스패치해야하는 이유가 궁금합니다. 하지만 이것은 나를 위해 일했습니다
Ankit garg

6

커서를 텍스트의 맨 위로 이동하려면 이것을 시도하십시오.

NSRange r  = {0,0};
[yourTextView setSelectedRange:r];

어떻게되는지보세요. 모든 이벤트가 시작되었거나 수행중인 모든 작업이 완료된 후에 이것을 호출해야합니다.


그것을 시도했다, 운이 없다. firstResponder와 관련된 것 같습니다. 다른 제안이 있습니까?
Sam Stewart

커서 위치와 동일한 문제가 있습니다.
Dhaval 2013

나는 아래에서 위로 애니메이션을 얻었지만 그것을 제거하는 방법을 요구하지 않았습니다.
Dhaval

2
맨 위로 스크롤되지 않습니다 (몇 픽셀에서 더 적음).
Dmitry

6

내 문제는 view가 나타날 때 textView를 맨 위로 스크롤하도록 설정하는 것입니다. iOS 10.3.2 및 Swift 3.

해결책 1 :

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // It doesn't work. Very strange.
    self.textView.setContentOffset(CGPoint.zero, animated: false)
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // It works, but with an animation effection.
    self.textView.setContentOffset(CGPoint.zero, animated: false)
}

해결책 2 :

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // It works.       
    self.textView.contentOffset = CGPoint.zero
}

5

이전 답변을 결합하면 이제 작동합니다.

talePageText.scrollEnabled = false
talePageText.textColor = UIColor.blackColor()
talePageText.font = UIFont(name: "Bradley Hand", size: 24.0)
talePageText.contentOffset = CGPointZero
talePageText.scrollRangeToVisible(NSRange(location:0, length:0))
talePageText.scrollEnabled = true

나를 위해 일했던 유일한 것은 얼마나 어리석은가. scrollRangeToVisible그래도 제거 할 수있었습니다 .
Jordan H

NSRange (0,0)를 NSMakeRange (0,0)로 대체해야합니다
RobP

5
[txtView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];

이 코드 줄은 저에게 효과적입니다.


5

이 코드를 사용할 수 있습니다.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    textView.scrollRangeToVisible(NSMakeRange(0, 0))
}

4

Swift 2 답변 :

textView.scrollEnabled = false

/* Set the content of your textView here */

textView.scrollEnabled = true

이렇게하면 설정 후 textView가 텍스트 끝으로 스크롤되는 것을 방지 할 수 있습니다.


4

Swift 3 :

  • viewWillLayoutSubviews 는 변경할 수있는 곳입니다. viewWillAppear도 작동해야하지만 논리적으로 레이아웃viewWillLayoutSubviews 에서 수행되어야합니다 .

  • 메서드와 관련하여 scrollRangeToVisiblesetContentOffset 이 모두 작동합니다. 그러나 setContentOffset을 사용하면 애니메이션을 끄거나 켤 수 있습니다.

UITextView 이름이 yourUITextView 라고 가정합니다 . 코드는 다음과 같습니다.

// Connects to the TextView in the interface builder.
@IBOutlet weak var yourUITextView: UITextView!

/// Overrides the viewWillLayoutSubviews of the super class.
override func viewWillLayoutSubviews() {

    // Ensures the super class is happy.
    super.viewWillLayoutSubviews()

    // Option 1:
    // Scrolls to a range of text, (0,0) in this very case, animated.
    yourUITextView.scrollRangeToVisible(NSRange(location: 0, length: 0))

    // Option 2:
    // Sets the offset directly, optional animation.
    yourUITextView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}

viewWillLayoutSubviews는 모든보기 크기 조정시 호출됩니다. 그것은 일반적으로 당신이 원하는 것이 아닙니다.
uliwitness jul.

4

viewDidLayoutSubviews 내부에서 다음을 호출해야했습니다 (viewDidLoad 내부 호출이 너무 이르렀습니다).

    myTextView.setContentOffset(.zero, animated: true)

모든 시나리오에서 작동하지 않음
Raja Saad

3

이것은 나를 위해 일했습니다. RyanTCB의 답변을 기반으로하지만 동일한 솔루션의 Objective-C 변형입니다.

- (void) viewWillAppear:(BOOL)animated {
    // For some reason the text view, which is a scroll view, did scroll to the end of the text which seems to hide the imprint etc at the beginning of the text.
    // On some devices it is not obvious that there is more text when the user scrolls up.
    // Therefore we need to scroll textView to the top.
    [self.textView scrollRangeToVisible:NSMakeRange(0, 0)];
}

3
-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    [textview setContentOffset:CGPointZero animated:NO];
}

viewWillLayoutSubviews는 모든보기 크기 조정시 호출됩니다. 그것은 일반적으로 당신이 원하는 것이 아닙니다.
uliwitness jul.

3
-(void) viewDidAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}

- (void)viewWillAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}
  • ViewWillappear사용자가 눈치 채기 전에 즉시 수행하지만 ViewDidDisappear섹션은 느리게 애니메이션합니다.
  • [mytextView setContentOffset:CGPointZero animated:YES]; 때때로 작동하지 않으므로 (이유를 모르겠습니다) 대신 scrollrangetovisible을 사용하십시오.

3

해결 된 문제 : iOS = 10.2 Swift 3 UITextView

다음 줄을 사용했습니다.

displayText.contentOffset.y = 0

1
작동했습니다 (iOS 10.3)! viewDidLayoutSubviews화면이 회전 할 때 발생하도록 내부에 추가했습니다 . 그렇지 않으면 콘텐츠 오프셋이 잘못 정렬됩니다.
Pup

2
[self.textView scrollRectToVisible:CGRectMake(0, 0, 320, self.textView.frame.size.height) animated:NO];

자세한 내용으로 편집하십시오.
Schemetrical

2

문제가 있었지만 제 경우에는 textview가 일부 사용자 정의 뷰의 하위 뷰이며 ViewController에 추가했습니다. 어떤 해결책도 나를 위해 일하지 않았습니다. 문제를 해결하기 위해 0.1 초 지연을 추가 한 다음 스크롤을 활성화했습니다. 그것은 나를 위해 일했습니다.

textView.isScrollEnabled = false
..
textView.text = // set your text here

let dispatchTime = DispatchTime.now() + 0.1
DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
   self.textView.isScrollEnabled = true
}

1

나를 위해이 코드는 잘 작동합니다.

    textView.attributedText = newText //or textView.text = ...

    //this part of code scrolls to top
    textView.contentOffset.y = -64
    textView.scrollEnabled = false
    textView.layoutIfNeeded() //if don't work, try to delete this line
    textView.scrollEnabled = true

정확한 위치로 스크롤하여 화면 상단에 표시하려면 다음 코드를 사용합니다.

    var scrollToLocation = 50 //<needed position>
    textView.contentOffset.y = textView.contentSize.height
    textView.scrollRangeToVisible(NSRange.init(location: scrollToLocation, length: 1))

contentOffset.y를 설정하면 텍스트 끝으로 스크롤 한 다음 scrollRangeToVisible은 scrollToLocation 값까지 스크롤합니다. 따라서 필요한 위치가 scrollView의 첫 번째 줄에 나타납니다.


1

iOS 9에서 나를 위해 scrollRangeToVisible 메소드를 사용하여 속성 문자열로 작동하지 않았습니다 (1 행은 굵은 글꼴로 다른 행은 일반 글꼴로)

그래서 다음을 사용해야했습니다.

textViewMain.attributedText = attributedString
textViewMain.scrollRangeToVisible(NSRange(location:0, length:0))
delay(0.0, closure: { 
                self.textViewMain.scrollRectToVisible(CGRectMake(0, 0, 10, 10), animated: false)
            })

지연은 다음과 같습니다.

func delay(delay:Double, closure:()->Void) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

1

이 두 줄 솔루션을 사용해보십시오.

view.layoutIfNeeded()
textView.contentOffset = CGPointMake(textView.contentInset.left, textView.contentInset.top)

이것은 나를 위해 일했습니다. 내 UITextView는 UICollectionVewCell 안에있었습니다. 레이아웃이 제대로 계산하지 않는 한 내가 잘못 자리에 그 scrollRangeToVisible 스크롤을 의심
존 파울러 (John Fowler)을

1

여기 내 코드가 있습니다. 잘 작동합니다.

class MyViewController: ... 
{
  private offsetY: CGFloat = 0
  @IBOutlet weak var textView: UITextView!
  ...

  override viewWillAppear(...) 
  {
      ...
      offsetY = self.textView.contentOffset.y
      ...
  }
  ...
  func refreshView() {
      let offSetY = textView.contentOffset.y
      self.textView.setContentOffset(CGPoint(x:0, y:0), animated: true)
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
        [unowned self] in
        self.textView.setContentOffset(CGPoint(x:0, y:self.offSetY), 
           animated: true)
        self.textView.setNeedsDisplay()
      }
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.