2013-04-10 1 views
13

내 앱에서 Safari 탭 또는 App Store 검색과 같은 "카드"를 구현하고 싶습니다.UICollectionView : Safari 탭 또는 App Store 검색과 같은 페이징

화면 중앙에 한 장의 카드를 표시하고 왼쪽 및 오른쪽 옆에있는 이전 및 다음 카드의 일부를 표시합니다.

나는 UICollectionView을 사용하기로 결정했으며, 페이지 크기를 변경하거나 (방법을 찾지 못했거나) 자신의 레이아웃 서브 클래스를 구현해야합니다 (어떻게해야할지 모르십니까).

도움이 필요하십니까?

답변

26

다음은이 효과를 얻는 가장 간단한 방법입니다. 그것은 당신의 콜렉션 뷰와 여분의 비밀 스크롤 뷰를 포함합니다.

은 컬렉션 뷰 컬렉션 뷰와 모든 데이터 소스 방법을 설정

  • 을 설정합니다.
  • 콜렉션보기 프레임. 보이는 너비에 걸쳐 있어야합니다.
  • 설정 컬렉션 뷰의 contentInset이 제대로 세포를 상쇄하는 데 도움이

    _collectionView.contentInset = UIEdgeInsetsMake(0, (self.view.frame.size.width-pageSize)/2, 0, (self.view.frame.size.width-pageSize)/2); 
    

.

당신이 원하는 위치를 배치하는있는 ScrollView 만들기

  • 비밀있는 ScrollView을 설정합니다. 원하는 경우 hidden으로 설정할 수 있습니다.
  • 스크롤 뷰의 경계 크기를 원하는 페이지 크기로 설정하십시오.
  • 자신을 스크롤 뷰의 대리자로 설정하십시오.
  • contentSize을 컬렉션보기의 예상 콘텐츠 크기로 설정하십시오.

  • 컬렉션보기로 비밀있는 ScrollView의 제스처 인식기를 추가하여 제스처 인식기 이동하고 수집 뷰의 제스처 인식 비활성화 :

    [_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; 
    _collectionView.panGestureRecognizer.enabled = NO; 
    

위임을

- (void) scrollViewDidScroll:(UIScrollView *)scrollView { 
    CGPoint contentOffset = scrollView.contentOffset; 
    contentOffset.x = contentOffset.x - _collectionView.contentInset.left; 
    _collectionView.contentOffset = contentOffset; 
} 

스크롤 뷰가 이동하면 오프셋을 가져 와서 컬렉션보기의 오프셋으로 설정합니다.

나는 여기에 대해 블로그, 그래서 업데이트이 링크를 확인하십시오 http://khanlou.com/2013/04/paging-a-overflowing-collection-view/

+0

이를하지만, 전달하지 않습니다하겠습니다. 어떤 아이디어? – eanticev

+1

iOS7에서 (적어도 전에는 사실 일 수 있음) 스크롤 뷰가 필요하지 않습니다. 왼쪽 및 오른쪽 슬쩍 제스처를 감지하여 컬렉션보기 1 페이지 앞으로/뒤로 오프셋을 설정하는 데 사용하십시오. – buildsucceeded

+3

나는 내 인생이 iOS7에서 작동하도록 할 수는 없다. "비밀"스크롤 뷰의'scrollViewDidScroll'은 전달되지 않습니다. –

-6

이전, 그래서 그냥이 수행 UICollectionView가있는 UIScrollView의 하위 클래스, 매우 복잡하다 :

[self.collectionView setPagingEnabled:YES]; 

당신은 모두를 갈 준비.

이 부분은 detailed tutorial입니다.

+7

사파리 탭이나 앱 스토어 검색과 같이 페이징하는 동안 왼쪽 및 오른쪽에 내용이 표시되는 문제는 해결되지 않습니다. –

1

나를 위해 트릭을 한 Soroush 대답에 대한 약간의 편집. 내가 대신 제스처를 사용하지 않도록 만들어진 유일한 편집 : collectionview에

[_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; 
_collectionView.panGestureRecognizer.enabled = NO; 

I 장애인 스크롤 :

_collectionView.scrollEnabled = NO; 

뿐만 아니라 비밀있는 ScrollView 제스처를 비활성화 제스처를 사용하지 않도록한다.

6

당신은 UICollectionViewFlowLayout를 서브 클래스 화해과 같이 재정의 할 수

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)contentOffset 
           withScrollingVelocity:(CGPoint)velocity 
{ 
    NSArray* layoutAttributesArray = 
    [self layoutAttributesForElementsInRect:self.collectionView.bounds]; 

    if(layoutAttributesArray.count == 0) 
     return contentOffset; 


    UICollectionViewLayoutAttributes* candidate = 
    layoutAttributesArray.firstObject; 

    for (UICollectionViewLayoutAttributes* layoutAttributes in layoutAttributesArray) 
    { 
     if (layoutAttributes.representedElementCategory != UICollectionElementCategoryCell) 
      continue; 


     if((velocity.x > 0.0 && layoutAttributes.center.x > candidate.center.x) || 
      (velocity.x <= 0.0 && layoutAttributes.center.x < candidate.center.x)) 
      candidate = layoutAttributes; 


    } 

    return CGPointMake(candidate.center.x - self.collectionView.bounds.size.width * 0.5f, contentOffset.y); 
} 

이는 속도에 따라 다음 또는 이전 셀을 얻을 것이다 ... 그것은 그러나 현재 셀에 스냅되지 않습니다.

+0

이 위임 메서드를 통해 오프셋에 대해 다른 'CGPoint'를 반환하면 아주 잘 작동합니다. 세포에서 멈추기위한 전이는 아주 부드럽습니다. – Andrei

+0

또한 전환 뷰가 'decelerationRate'를'UIScrollViewDecelerationRateFast'로 설정하면 스크롤 뷰를 * snap *으로 가져 오는 것이 트릭입니다. 빠른 스냅 샷의 경우,'decelerationRate'를 0.990000보다 작은 값으로 설정하면 (현재 'UIScrollViewDecelerationRateFast' 인 것처럼 보입니다.) 약간의 효과가있는 것처럼 보입니다. – Andrei

0

다른 해결책을 추가하겠습니다. 스냅 기능이 완벽하지는 않습니다 (페이징 기능이 설정된 경우만큼 좋지는 않지만 충분히 잘 작동합니다).

나는 Soroush의 솔루션을 구현하려했지만 나에게 적합하지 않습니다.

UICollectionView은 그것이 중요한 UIScrollViewDelegate 방법에 응답 할 것입니다 UIScrollView의 서브 클래스이기 때문에 :

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView 
        withVelocity:(CGPoint)velocity 
       targetContentOffset:(inout CGPoint *)targetContentOffset 

targetContentOffset (AN 포인터 입출력)를 사용하면 컬렉션 뷰의 정지 점을 재정의 할 수있는 (가로로 스 와이프하면이 경우 x).

변수의 몇 가지에 대한 빠른 노트는 아래의 발견 :

  • self.cellWidth -이 컬렉션 뷰 셀의 폭 (당신이 원하는 경우에 당신도 거기에 하드 코드 수)입니다

  • self.minimumLineSpacing - 이것은 셀 사이에 설정하는 최소 줄 간격입니다.

  • self.scrollingObjects은 컬렉션보기에 포함 된 개체의 배열입니다.

그래서, 생각과 같이 컬렉션 뷰의 위임에이 방법을 구현하는 것입니다) 스크롤을 중지 할 때 알고, 수 :

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView 
        withVelocity:(CGPoint)velocity 
       targetContentOffset:(inout CGPoint *)targetContentOffset 
{  
    if (self.currentIndex == 0 && velocity.x < 0) { 
     // we have reached the first user and we're trying to go back 
     return; 
    } 

    if (self.currentIndex == (self.scrollingObjects.count - 1) && velocity.x > 0) { 
     // we have reached the last user and we're trying to go forward 
     return; 
    } 

    if (velocity.x < 0) { 
     // swiping from left to right (going left; going back) 
     self.currentIndex--; 
    } else { 
     // swiping from right to left (going right; going forward) 
     self.currentIndex++; 
    } 

    float xPositionToStop = 0; 

    if (self.currentIndex == 0) { 
     // first row 
     xPositionToStop = 0; 
    } else { 
     // one of the next ones 
     xPositionToStop = self.currentIndex * self.cellWidth + (self.currentIndex + 1) * self.minimumLineSpacing - ((scrollView.bounds.size.width - 2*self.minimumLineSpacing - self.cellWidth)/2); 
    } 

    targetContentOffset->x = xPositionToStop; 

    NSLog(@"Point of stopping: %@", NSStringFromCGPoint(*targetContentOffset)); 
} 

당신이 가질 수있는 피드백을 기대한다 더 나은 장소에서 스냅을 만듭니다.나는 또한 제대로 iOS7에의로서 기본이되는 콜렉션 뷰를 선택하고 탭 이벤트 ... 더 나은 솔루션을 찾고에 스위프트의

+0

이것은 작동하는 것처럼 보이지만 "페이징 가능"을 정확히 복제하지 못하고 조금 어색함을 느낍니다. –

2

@Mike M's answer을 ...

class CenteringFlowLayout: UICollectionViewFlowLayout { 

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { 

     guard let collectionView = collectionView, 
      let layoutAttributesArray = layoutAttributesForElementsInRect(collectionView.bounds), 
      var candidate = layoutAttributesArray.first else { return proposedContentOffset } 

     layoutAttributesArray.filter({$0.representedElementCategory == .Cell }).forEach { layoutAttributes in 

      if (velocity.x > 0 && layoutAttributes.center.x > candidate.center.x) || 
       (velocity.x <= 0 && layoutAttributes.center.x < candidate.center.x) { 
       candidate = layoutAttributes 
      } 
     } 

     return CGPoint(x: candidate.center.x - collectionView.bounds.width/2, y: proposedContentOffset.y) 
    } 

}