programing

UIScrollView에서 스크롤 방향을 찾으십니까?

lastmoon 2023. 7. 6. 22:30
반응형

UIScrollView에서 스크롤 방향을 찾으십니까?

나는 있습니다UIScrollView가로 스크롤만 가능하며, 사용자가 스크롤하는 방향(왼쪽, 오른쪽)을 알고 싶습니다.제가 한 것은 하위 분류입니다.UIScrollView그리고 그것을 무시합니다.touchesMoved방법:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];

    UITouch *touch = [touches anyObject];
    float now = [touch locationInView:self].x;
    float before = [touch previousLocationInView:self].x;
    NSLog(@"%f %f", before, now);
    if (now > before){
        right = NO;
        NSLog(@"LEFT");
    }
    else{
        right = YES;
        NSLog(@"RIGHT");

    }

}

그런데 이사를 할 때 이 방법이 아예 불리지 않는 경우가 있습니다.당신은 어떻게 생각하나요?

방향을 결정하는 것은 매우 간단하지만, 제스처를 취하는 동안 방향이 여러 번 바뀔 수 있다는 것을 명심하십시오.예를 들어, 페이징이 설정된 상태에서 스크롤 보기를 사용할 경우 사용자가 다음 페이지로 이동하기 위해 스와이프하면 초기 방향이 오른쪽으로 이동할 수 있지만, 바운스가 설정된 경우에는 잠시 방향이 없거나 왼쪽으로 이동합니다.

방향을 결정하려면 다음을 사용해야 합니다.UIScrollView scrollViewDidScroll위임하다이 샘플에서 다음과 같은 이름의 변수를 만들었습니다.lastContentOffset현재 콘텐츠 오프셋을 이전 콘텐츠 오프셋과 비교하는 데 사용합니다.더 크면 스크롤 보기가 오른쪽으로 스크롤됩니다.왼쪽으로 .

// somewhere in the private class extension
@property (nonatomic, assign) CGFloat lastContentOffset;

// somewhere in the class implementation
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    ScrollDirection scrollDirection;

    if (self.lastContentOffset > scrollView.contentOffset.x) {
        scrollDirection = ScrollDirectionRight;
    } else if (self.lastContentOffset < scrollView.contentOffset.x) {
        scrollDirection = ScrollDirectionLeft;
    }

    self.lastContentOffset = scrollView.contentOffset.x;

    // do whatever you need to with scrollDirection here.    
}

다음 열거형을 사용하여 방향을 정의합니다.첫 번째 값을 ScrollDirectionNone으로 설정하면 변수를 초기화할 때 해당 방향을 기본값으로 설정할 수 있습니다.

typedef NS_ENUM(NSInteger, ScrollDirection) {
    ScrollDirectionNone,
    ScrollDirectionRight,
    ScrollDirectionLeft,
    ScrollDirectionUp,
    ScrollDirectionDown,
    ScrollDirectionCrazy,
};

...사용자가 스크롤하는 방향(왼쪽, 오른쪽)을 알고 싶습니다.

5에서는 iOS 5를 합니다.UIScrollViewDelegate사용자의 이동 제스처 방향을 결정합니다.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{ 
    if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) {
        // handle dragging to the right
    } else {
        // handle dragging to the left
    }
}

용사를 합니다.scrollViewDidScroll:현재 방향을 찾을 수 있는 좋은 방법입니다.

사용자가 스크롤을 마친 후 방향을 알려면 다음을 사용합니다.

@property (nonatomic) CGFloat lastContentOffset;

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

    self.lastContentOffset = scrollView.contentOffset.x;
}

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

    if (self.lastContentOffset > scrollView.contentOffset.x) {
        // moved right if last content offset is greater then current offset
    } else if (self.lastContentOffset < scrollView.contentOffset.x) {
        // moved left if last content offset is less that current offset
    } else {
        // didn't move
    }
}

이를 추적하기 위해 변수를 추가할 필요가 없습니다.사용하기만 하면 됩니다.UIScrollViewpanGestureRecognizer0이 아닌 합니다.

CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y;
if (yVelocity < 0) {
    NSLog(@"Up");
} else if (yVelocity > 0) {
    NSLog(@"Down");
} else {
    NSLog(@"Can't determine direction as velocity is 0");
}

x 성분과 y 성분의 조합을 사용하여 위, 아래, 왼쪽 및 오른쪽을 탐지할 수 있습니다.

해결책

func scrollViewDidScroll(scrollView: UIScrollView) {
     if(scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0)
     {
         print("up")
     }
    else
    {
         print("down")
    } 
}

스위프트 4:

수평 스크롤의 경우 다음 작업을 간단히 수행할 수 있습니다.

if scrollView.panGestureRecognizer.translation(in: scrollView.superview).x > 0 {
   print("left")
} else {
   print("right")
}

수직 스크롤 변경의 경우.x와 함께.y

iOS8 Swift에서 저는 다음 방법을 사용했습니다.

override func scrollViewDidScroll(scrollView: UIScrollView){

    var frame: CGRect = self.photoButton.frame
    var currentLocation = scrollView.contentOffset.y

    if frame.origin.y > currentLocation{
        println("Going up!")
    }else if frame.origin.y < currentLocation{
        println("Going down!")
    }

    frame.origin.y = scrollView.contentOffset.y + scrollHeight
    photoButton.frame = frame
    view.bringSubviewToFront(photoButton)

}

사용자가 스크롤할 때 위치가 변경되는 동적 보기를 사용하여 보기가 화면의 동일한 위치에 유지된 것처럼 보일 수 있습니다.나는 또한 사용자가 언제 오르거나 내리는지 추적하고 있습니다.

다음은 다른 방법입니다.

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if targetContentOffset.memory.y < scrollView.contentOffset.y {
        println("Going up!")
    } else {
        println("Going down!")
    }
}

이것이 제게 도움이 되었습니다(목표-C).

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

        NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)?@"up":@"down";
        NSLog(@"%@",direction);
    }
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

    CGPoint targetPoint = *targetContentOffset;
    CGPoint currentPoint = scrollView.contentOffset;

    if (targetPoint.y > currentPoint.y) {
        NSLog(@"up");
    }
    else {
        NSLog(@"down");
    }
}

신속하게:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 {
        print("down")
    } else {
        print("up")
    }
}

스크롤 보기DidScroll에서도 이 작업을 수행할 수 있습니다.

또는 키 경로 "contentOffset"을 관찰할 수 있습니다.이 기능은 스크롤 보기의 대리자를 설정/변경할 수 없는 경우에 유용합니다.

[yourScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

관찰자를 추가한 후 다음 작업을 수행할 수 있습니다.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    CGFloat newOffset = [[change objectForKey:@"new"] CGPointValue].y;
    CGFloat oldOffset = [[change objectForKey:@"old"] CGPointValue].y;
    CGFloat diff = newOffset - oldOffset;
    if (diff < 0 ) { //scrolling down
        // do something
    }
}

필요할 때 관찰자를 제거해야 합니다. 예를 들어 관찰자를 보기에 추가할 수 있습니다. 보기에 표시 및 제거할 수 있습니다. 사라질 것입니다.

여기 @followben 답변과 같은 동작에 대한 나의 해결책이 있지만, 느린 시작과 함께 손실이 없습니다(dy가 0일 때).

@property (assign, nonatomic) BOOL isFinding;
@property (assign, nonatomic) CGFloat previousOffset;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    self.isFinding = YES;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.isFinding) {
        if (self.previousOffset == 0) {
            self.previousOffset = self.tableView.contentOffset.y;

        } else {
            CGFloat diff = self.tableView.contentOffset.y - self.previousOffset;
            if (diff != 0) {
                self.previousOffset = 0;
                self.isFinding = NO;

                if (diff > 0) {
                    // moved up
                } else {
                    // moved down
                }
            }
        }
    }
}
//Vertical detection
    var lastVelocityYSign = 0
            func scrollViewDidScroll(_ scrollView: UIScrollView) {
                let currentVelocityY =  scrollView.panGestureRecognizer.velocity(in: scrollView.superview).y
                let currentVelocityYSign = Int(currentVelocityY).signum()
                if currentVelocityYSign != lastVelocityYSign &&
                    currentVelocityYSign != 0 {
                    lastVelocityYSign = currentVelocityYSign
                }
                if lastVelocityYSign < 0 {
                    print("SCROLLING DOWN")
                } else if lastVelocityYSign > 0 {
                    print("SCOLLING UP")
                }
            }

Mos6y의 답변 https://medium.com/ @Mos6yCanSwift/swift-ios-결정-스크롤-방향-d48a2327a004

스위프트 5

▁▁clean▁more보enum세로 스크롤용입니다.

enum ScrollDirection {
    case up, down
}

var scrollDirection: ScrollDirection? {
    let yTranslation = scrollView.panGestureRecognizer.translation(in: scrollView.superview).y

    if yTranslation > 0 {
        return .up
    } else if yTranslation < 0 {
        return .down
    } else {
        return nil
    }
}

사용.

switch scrollDirection {
case .up:   print("up")
case .down: print("down")
default:    print("no scroll")
}

답변 중 일부를 확인하고 UIScrollView 카테고리에서 모든 것을 한 방울씩 포장하여 AnswerBot 답변에 대해 자세히 설명했습니다."last Content Offset"은 대신 uiscrollview에 저장되며 호출만 하면 됩니다.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
  [scrollView setLastContentOffset:scrollView.contentOffset];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
  if (scrollView.scrollDirectionX == ScrollDirectionRight) {
    //Do something with your views etc
  }
  if (scrollView.scrollDirectionY == ScrollDirectionUp) {
    //Do something with your views etc
  }
}

https://github.com/tehjord/UIScrollViewScrollingDirection 의 소스 코드

Swift 2.2 단방향 다중방향을 손실 없이 추적하는 간단한 솔루션.

  // Keep last location with parameter
  var lastLocation:CGPoint = CGPointZero

  // We are using only this function so, we can
  // track each scroll without lose anyone
  override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    let currentLocation = scrollView.contentOffset

    // Add each direction string
    var directionList:[String] = []

    if lastLocation.x < currentLocation.x {
      //print("right")
      directionList.append("Right")
    } else if lastLocation.x > currentLocation.x {
      //print("left")
      directionList.append("Left")
    }

    // there is no "else if" to track both vertical
    // and horizontal direction
    if lastLocation.y < currentLocation.y {
      //print("up")
      directionList.append("Up")
    } else if lastLocation.y > currentLocation.y {
      //print("down")
      directionList.append("Down")
    }

    // scrolled to single direction
    if directionList.count == 1 {
      print("scrolled to \(directionList[0]) direction.")
    } else if directionList.count > 0  { // scrolled to multiple direction
      print("scrolled to \(directionList[0])-\(directionList[1]) direction.")
    }

    // Update last location after check current otherwise,
    // values will be same
    lastLocation = scrollView.contentOffset
  }

저는 @memmons의 대답을 바탕으로 필터링을 하는 것을 선호합니다.

목표 C:

// in the private class extension
@property (nonatomic, assign) CGFloat lastContentOffset;

// in the class implementation
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    if (fabs(self.lastContentOffset - scrollView.contentOffset.x) > 20 ) {
        self.lastContentOffset = scrollView.contentOffset.x;
    }

    if (self.lastContentOffset > scrollView.contentOffset.x) {
        //  Scroll Direction Left
        //  do what you need to with scrollDirection here.
    } else {
        //  omitted 
        //  if (self.lastContentOffset < scrollView.contentOffset.x)

        //  do what you need to with scrollDirection here.
        //  Scroll Direction Right
    } 
}

에 테트한 경우스에서 했을 때- (void)scrollViewDidScroll:(UIScrollView *)scrollView:

NSLog(@"lastContentOffset: --- %f,   scrollView.contentOffset.x : --- %f", self.lastContentOffset, scrollView.contentOffset.x);

img

self.lastContentOffset값의 차이는 거의 0.5f입니다.

그건 필요 없다.

그리고 때로는 정확한 상태에서 처리할 때 방향을 잃을 수도 있습니다.(가끔 설명문을 건너뜁니다.)

예:

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

    CGFloat viewWidth = scrollView.frame.size.width;

    self.lastContentOffset = scrollView.contentOffset.x;
    // Bad example , needs value filtering

    NSInteger page = scrollView.contentOffset.x / viewWidth;

    if (page == self.images.count + 1 && self.lastContentOffset < scrollView.contentOffset.x ){
          //  Scroll Direction Right
          //  do what you need to with scrollDirection here.
    }
   ....

Swift 4에서:

var lastContentOffset: CGFloat = 0

func scrollViewDidScroll(_ scrollView: UIScrollView) {

     if (abs(lastContentOffset - scrollView.contentOffset.x) > 20 ) {
         lastContentOffset = scrollView.contentOffset.x;
     }

     if (lastContentOffset > scrollView.contentOffset.x) {
          //  Scroll Direction Left
          //  do what you need to with scrollDirection here.
     } else {
         //  omitted
         //  if (self.lastContentOffset < scrollView.contentOffset.x)

         //  do what you need to with scrollDirection here.
         //  Scroll Direction Right
    }
}

페이징이 켜져 있으면 이 코드를 사용할 수 있습니다.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    self.lastPage = self.currentPage;
    CGFloat pageWidth = _mainScrollView.frame.size.width;
    self.currentPage = floor((_mainScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    if (self.lastPage < self.currentPage) {
        //go right
        NSLog(@"right");
    }else if(self.lastPage > self.currentPage){
        //go left
        NSLog(@"left");
    }else if (self.lastPage == self.currentPage){
        //same page
        NSLog(@"same page");
    }
}

코드 자체가 설명이 되는 것 같아요.CGFloat difference1 및 difference2가 동일한 클래스 전용 인터페이스에 선언되었습니다.contentSize가 동일하게 유지되면 좋습니다.

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

        CGFloat contentOffSet = scrollView.contentOffset.y;
        CGFloat contentHeight = scrollView.contentSize.height;

        difference1 = contentHeight - contentOffSet;

        if (difference1 > difference2) {
            NSLog(@"Up");
        }else{
            NSLog(@"Down");
        }

        difference2 = contentHeight - contentOffSet;

       }

이 구현은 매우 효과적입니다.

@property (nonatomic, assign) CGPoint lastContentOffset;


- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    _lastContentOffset.x = scrollView.contentOffset.x;
    _lastContentOffset.y = scrollView.contentOffset.y;

}


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

    if (_lastContentOffset.x < (int)scrollView.contentOffset.x) {
        // moved right
        NSLog(@"right");
    }
    else if (_lastContentOffset.x > (int)scrollView.contentOffset.x) {
        // moved left
        NSLog(@"left");

    }else if (_lastContentOffset.y<(int)scrollView.contentOffset.y){
        NSLog(@"up");

    }else if (_lastContentOffset.y>(int)scrollView.contentOffset.y){
        NSLog(@"down");
        [self.txtText resignFirstResponder];

    }
}

그러면 text가 실행됩니다. 드래그가 끝난 후 해제하려면 View(View to dismiss)

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
NSLog(@"px %f py %f",velocity.x,velocity.y);}

스크롤 뷰의 위임 방법을 사용합니다.

속도 좌표가 +ve이면 보기가 아래로 스크롤되고 -ve이면 보기가 위로 스크롤됩니다.마찬가지로 x 좌표를 사용하여 왼쪽 및 오른쪽 스크롤을 감지할 수 있습니다.

속도 값이 0보다 크면 왼쪽으로 스크롤하고 오른쪽으로 스크롤하는 것이 Short & Easy입니다.

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    var targetOffset = Float(targetContentOffset.memory.x)
    println("TargetOffset: \(targetOffset)")
    println(velocity)

    if velocity.x < 0 {
        scrollDirection = -1 //scrolling left
    } else {
        scrollDirection = 1 //scrolling right
    }
}

UIScrollView 및 UIPageControl로 작업하는 경우, 이 방법은 PageControl의 페이지 보기도 변경합니다.

  func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    let targetOffset = targetContentOffset.memory.x
    let widthPerPage = scrollView.contentSize.width / CGFloat(pageControl.numberOfPages)

    let currentPage = targetOffset / widthPerPage
    pageControl.currentPage = Int(currentPage)
}

@Esq의 Swift 코드 감사합니다.

모든 상위 답변에서 문제를 해결하는 두 가지 주요 방법은 다음과 같습니다.panGestureRecognizer또는contentOffset두 방법 모두 장단점이 있습니다.

방법 1: 팬 제스처 인식기

사용할 때panGestureRecognizer@followben이 제안한 것처럼 스크롤 보기를 프로그래밍 방식으로 스크롤하지 않으려면 제대로 작동합니다.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{ 
    if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) {
        // handle dragging to the right
    } else {
        // handle dragging to the left
    }
}

단점

그러나 다음 코드로 스크롤 보기를 이동하면 상위 코드가 인식할 수 없습니다.

setContentOffset(CGPoint(x: 100, y: 0), animation: false)

방법 2: 내용 오프셋

var lastContentOffset: CGPoint = CGPoint.zero

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (self.lastContentOffset.x > scrollView.contentOffset.x) {
        // scroll to right
    } else if self.lastContentOffset.x < scrollView.contentOffset.x {
        // scroll to left
    }
    self.lastContentOffset = self.scrollView.contentOffset
}

단점

무한 스크롤을 만들 때와 같이 스크롤하는 동안 프로그래밍 방식으로 contentOffset을 변경하려는 경우 변경할 수 있으므로 이 방법이 문제가 됩니다.contentOffset내용 보기 위치를 변경하는 동안 오른쪽 또는 왼쪽으로 스크롤하는 상위 코드가 점프합니다.

언급URL : https://stackoverflow.com/questions/2543670/finding-the-direction-of-scrolling-in-a-uiscrollview

반응형