UIScrollView에서 프로그래밍 방식으로 스크롤을 강제 중지하려면 어떻게해야합니까?


81

참고 : 여기에 제공된 답변 은 저에게 적합하지 않습니다.

UIScrollView (테이블 뷰가 아니라 사용자 지정 항목)가 있으며 사용자가 특정 작업을 수행 할 때 뷰 내에서 스크롤 (끌기 또는 감속)을 종료하고 싶습니다. 예를 들어 다음과 같이 시도했습니다.

[scrollView scrollRectToVisible:CGRectInset([scrollView bounds], 10, 10) animated:NO];

이미 보이는 rect가 주어지면 스크롤은 그 위치에서 멈출 것이지만 이것은 효과가 없다는 것이 밝혀졌습니다. 분명히 스크롤 뷰는 주어진 rect가 경계에 있고 조치 없음. 내가 할 수 확실히하는 RECT 주면, 정지 스크롤을 얻을 수 밖에 현재 눈에 보이는 경계를하지만,보기의 contentSize 내부. 이로 인해 예상대로보기가 중단되는 것 같지만 다른 위치로 이동합니다. 이 작업을 합리적으로 수행하기 위해 여백에서 약간 놀아 볼 수 있지만, 작업을 수행하는 스크롤 뷰를 중지하는 깨끗한 방법을 아는 사람이 있습니까?

감사.

답변:


108

나는 당신의 원래 솔루션을 약간 가지고 놀았고 이것은 잘 작동하는 것 같습니다. 나는 당신이 거의 가지고 있다고 생각하지만 너무 많이 사용한 rect를 오프셋하고 있었고 rect를 원래 rect로 똑바로 스크롤 할 수 있다는 것을 잊었습니다.

모든 스크롤 작업에 대한 일반화 된 솔루션은 다음과 같습니다.

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    offset.x -= 1.0;
    offset.y -= 1.0;
    [scrollView setContentOffset:offset animated:NO];
    offset.x += 1.0;
    offset.y += 1.0;
    [scrollView setContentOffset:offset animated:NO];
}

[편집] iOS 4.3 (및 이전 버전)부터이 기능도 작동하는 것으로 보입니다.

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    [scrollView setContentOffset:offset animated:NO];
}

1
David : 좋습니다. 감사합니다. 나는이 방향으로 나 자신을 뒤틀었지만 스크롤 경계 바로 밖에서 1x1 직사각형을 선택하는 것에 대한 덜 사소한 계산으로 끝났습니다. 오프셋을 제안한 다음 즉시 복원 (솔직히 "결과"가 작동하지 않는 경우에도 실행되는 한 이벤트의 연속 호출이 실제로 작동하는 게시되지 않은 동작을 활용하는 것처럼 보임)은 제대로 작동합니다. 스크롤 방향에 대해 작동해야하는 일반화 된 솔루션을 포함하도록 위의 답변을 편집 할 것입니다. 감사!
Ben Zotto 2010 년

(편집 내용이 마음에 들지 않았
으면 좋겠습니다

멋지네요 ... 그런데 당신이 있던 곳으로 어떻게 돌아가나요? 그것을 죽이기 전에 오프셋을 저장하고 거기로 돌아 오나요?
Lior Frenkel

2
iOS 7에서 scrollView가 Decelerating이면 최상위 솔루션 만 작동합니다 (+ = 1,-= 1 솔루션).
Sahil

1
이 솔루션은 개선 될 수 있습니다. + = 1 대신 + = 0.1을 사용하므로 단일 호출 setContentOffset로 충분합니다. 스크롤보기는 콘텐츠 오프셋을 자동으로 반올림합니다.
kelin 2015-06-01

91

일반적인 대답은,이다 [scrollView setContentOffset:offset animated:NO]동일하지[scrollView setContentOffset:offset]!

  • [scrollView setContentOffset:offset animated:NO] 실제로 실행중인 애니메이션을 중지합니다.
  • [scrollView setContentOffset:offset] 실행중인 애니메이션을 중지하지 않습니다.
  • 동일 scrollView.contentOffset = offset: 실행중인 애니메이션을 중지하지 않습니다.

이는 어디에도 문서화되어 있지 않지만 iOS 6.1 및 iOS 7.1에서 테스트 한 동작입니다.

따라서 실행중인 애니메이션 / 감속을 중지하는 솔루션 은 다음과 같이 간단합니다.

[scrollView setContentOffset:scrollView.contentOffset animated:NO];

기본적으로 David Liu가 편집 한 답변에서 말한 것. 하지만이 두 API를 것을, 명확하게하고 싶어 하지 동일 .

스위프트 3 :

scrollView.setContentOffset(scrollView.contentOffset, animated:false)

11
그럼 우리 사이 "이유 구직자"에 대한 설명에서 수행 (:
Aviel 총

3
이것은 좀 슬프게 만듭니다.
DCMaxxx 2015

2
이 물건은 urggggghh ... 문서화되지 않는 이유 이해가 안 돼요
user1105951

(적어도) iOS 11.3 및 11.4에서 더욱 흥미로운 점은 다음과 같습니다. contentOffset이 예를 들어 (300, 0)으로 애니메이션되면 애니메이션이 계속 실행되는 동안 "contentOffset = (300, 0)"이 할당되면 contentOffset이 다음으로 재설정 될 수 있습니다. (0, 0)! 이것은 버그 일 것입니다!

68

나를 위해 David Lui의 대답 은 나를 위해 작동하지 않았습니다. 이것이 내가 한 일입니다.

- (void)killScroll {
    self.scrollView.scrollEnabled = NO;
    self.scrollView.scrollEnabled = YES;
}

그만한 가치를 위해 iOS 6.0 iPhone Simulator를 사용하고 있습니다.


2
당신이 말한 것처럼 +1, 다른 하나는 나에게도 효과가 없었지만이 솔루션은 훌륭하게 작동했습니다!
brenjt 2013

1
훌륭 supportedInterfaceOrientations합니다. 사용자가 스크롤하는 동안 기기를 회전하는 경우 스크롤 이벤트가 계속되는 것을 방지하기 위해 완벽하게 작동 하며 , 이는 수행중인 작업에 따라 때때로 엉망이됩니다.
cprcrack

21

이것은 스크롤 뷰 및 기타 모든 관련 하위 클래스에 대해 수행하는 작업입니다.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
 {
    *targetContentOffset = scrollView.contentOffset;
 }

이 설정한다 targetContentOffset받는 scrollView가 목표에 도달하기 때문에의 오프셋 전류가 정지하므로 스크롤링하기. 실제로 사용자가 대상을 설정할 수있는 방법을 사용하는 것이 합리적 contentOffset입니다.

빠른

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee = scrollView.contentOffset
}

이것은 개발자가 사용해야하는 사과처럼 보입니다. 다른 모든 것들은 어느 시점에서 버그로 이어지기 때문입니다. 나는 이것이 받아 들여지는 대답이 아니라는 것에 놀랐습니다.
OlDor

이것이 바로이 델리게이트 메소드입니다. 좋은 대답입니다.
라이언

제 생각에 이것은 Apple이 문서에서 말한 것처럼 가장 우아한 솔루션입니다. "애플리케이션은 targetContentOffset 매개 변수의 값을 변경하여 scrollview가 스크롤 애니메이션을 완료하는 위치를 조정할 수 있습니다." 나를 위해 아주 잘 일했습니다
Macistador

이것이 정답입니다. 위의 어느 것도 나를 위해 일하지
않았습니다

20

신속하게 스크롤을 중지하십시오 .

scrollView.setContentOffset(scrollView.contentOffset, animated: false)

16

사실 ... 가장 "현대적인"방법은->

scrollview.panGestureRecognizer.enabled = false;
scrollview.panGestureRecognizer.enabled = true;

이렇게하면 현재 터치를 종료하는 잠시 스크롤을 담당하는 제스처 인식기가 비활성화됩니다. 사용자가 다시 스크롤을 시작하려면 손가락을 뗀 후 다시 내려 놓아야합니다.

편집 : 이것은 실제로 사용자의 현재 드래그를 죽이지 만 scrollview가 현재이 상태에 있으면 감속을 즉시 중지하지 않습니다. 이를 위해 허용되는 답변 편집은 xD가 가장 좋은 방법입니다.

[scrollview setContentOffset: scrollview.contentOffset animated:false];

글쎄, 나는 이것을 내 앱에서 사용하고 OP에서 요구하는 것을 정확하게 수행합니다. 좀 더 맥락을 말씀해 주시겠습니까? 작동하지 않는 항목 또는 이유는 무엇입니까?
Xatian

아 죄송합니다 ... 알 것 같아요 ... 제가 찾고 있던 질문의 일부에 대답했습니다 ... 제가 간과 한 두 번째 부분 ... :-)-> 편집했습니다.
Xatian 2014

감속을 멈추지 않습니다.
Rudolf Adamkovič 2015

5

가장 깨끗한 방법은 UIScrollView를 서브 클래 싱하고 자신 만의 setContentOffset 메소드를 제공하는 것입니다. 부울 속성을 설정 하지 않은 경우 에만 메시지를 전달해야 freeze합니다.

이렇게 :

BOOL freeze; // and the @property, @synthesize lines..

-(void)setContentOffset:(CGPoint)offset
{
    if ( !freeze ) [super setContentOffset:offset];
}

그런 다음 고정하려면 :

scrollView.freeze = YES;

1
감사. 이로 인해 눈에 보이는 스크롤이 중지되지만 실제로 내부 감속이 중지되지는 않습니다. 이 기능을 켜고 잠시 후에 다시 끄면 스크롤이 일시 중지 된 다음 앞으로 이동하여 계속 감속합니다. 따라서 scrollview의 내부 상태는 여전히 스크롤됩니다. 따라서 감속이 멈췄다는 것을 알 때까지 멈춰야합니다. 대의원과 협력하여 수행 할 수 있지만 저에게는 약간 바보 같은 느낌이 듭니다. 나는 실제로 감속을 즉시 멈출 수있는 무언가를 기대하고 있습니다 (예 : 화면에서 한 번 탭하는 효과가 있음).
Ben Zotto 2010 년

좋아, 이런 종류의 문제는 이전 경험에서 익숙한 것처럼 들립니다 ... decelerationRate = 1e10;while freeze == YES를 설정하여 감속을 줄여 보는 것은 어떻습니까?
mvds 2010-08-05

(내부 수학을 알지 못함, 10 * UIScrollViewDecelerationRateFast는 1e10보다 현명한 선택 일 수 있음)
mvds

흥미로운 아이디어! 불행히도이 값은 고정 된 것 같습니다. 시도해 보았지만 감속이 즉시 중지되는 값이없는 것 같습니다. 내가 할 수있는 최선은 그것을 느리게 만드는 것입니다. :)
Ben Zotto 2010 년

그런 다음 계획 B는 잠시 동안 스크롤을 비활성화하는 것입니다. 어쨌든 setContentOffset을 차단하고 있으므로 부작용이 스크롤을 비활성화하는 것을 막기 때문에 벗어날 수 있습니다.
mvds 2010-08-05


3

스크롤 사용자 상호 작용을 비활성화합니다. (빠른)

scrollView.isScrollEnabled = false

드래그 후 스크롤 애니메이션 중에는 비활성화합니다. (빠른)

var scrollingByVelocity = false

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
    if !scrollingByVelocity {
        scrollView.setContentOffset(scrollView.contentOffset, animated: false)
    }
}

0

collectionview에서이 방법을 시도했습니다.

self.collectionView.collectionViewLayout.finalizeCollectionViewUpdates()


0

이것은 Swift 4.2 에서 저에게 효과적입니다 .

   func killScroll() {
    self.scrollView.isScrollEnabled = false;
    self.scrollView.isScrollEnabled = true;
}

... 확장자 :

extension UIScrollView {
    func killScroll() {
        self.isScrollEnabled = false;
        self.isScrollEnabled = true;

    }
}

0

스크롤 뷰 내의 특정 UIView가 스 와이프하는 동안 터치의 소스 인 경우에만 스크롤을 비활성화하고 싶었습니다. 복잡한 뷰 계층 구조가 있었기 때문에 UIView를 UIScrollView 외부로 이동하려면 상당한 리팩토링이 필요했습니다.

해결 방법으로 스크롤을 방지하려는 하위보기에 단일 UIPanGestureRecognizer를 추가했습니다. 이 UIPanGestureRecognizer는cancelsTouchesInView UIScrollView의 panGesture가 활성화되는 것을 방지합니다.

약간의 '해킹'이지만 매우 쉬운 변경이며 XIB 또는 스토리 보드를 사용하는 경우 팬 제스처를 문제의 하위보기로 드래그하기 만하면됩니다.


0

SWift 5+

Extension을 사용하여

extension UIScrollView  {
    
    func stopDecelerating() {
        let contentOffset = self.contentOffset
        self.setContentOffset(contentOffset, animated: false)
    }
}

사용하다

    myScrollView.stopDecelerating()
    // your stuff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.