UIScroll모바일 사파리 탭과 같은 수평 페이징 보기
모바일 사파리에서는 페이지 컨트롤을 하단에 두고 일종의 UISScrollView 수평 페이징 뷰를 입력하여 페이지를 전환할 수 있습니다.
수평으로 스크롤 가능한 UIScrollView가 다음 보기의 일부 내용을 표시하는 이 특정 동작을 복제하려고 합니다.
Apple이 제공한 예: 페이지 컨트롤은 수평 페이징에 UIScrol View를 사용하는 방법을 보여주지만 모든 뷰가 전체 화면 너비를 차지합니다.
모바일 Safari처럼 다음 보기의 일부 콘텐츠를 표시하려면 UIScrollView를 어떻게 해야 합니까?
A UIScrollView
페이징을 활성화하면 프레임 너비(또는 높이)의 배수에서 중지됩니다.첫 번째 단계는 페이지의 너비를 파악하는 것입니다.다 .UIScrollView
그런 크기를 하고 . UIScrollView
.
그런 세트를 clipsToBounds
.NO
mhjoy 의 말대로 트릭 가 트릭 부분은 이제 사용자가 범위 밖에서 드래그를 시작할 때 스크롤하도록 하는 것입니다의 밖에서 를 시작할 때 입니다.UIScrollView
의 체구. (최근에 이 일을 해야 때) 제 (최근에 이 작업을 수행해야 했을 때) 제 해결책은 다음과 같습니다.
만들기UIView
아류(즉, 서브클래스)ClipView
) 할 것입니다.UIScrollView
그리고 그것은 서브뷰 입니다.,다.UIScrollView
정상적인 상황에서는 그럴 겁니다배치.UIScrollView
ClipView
합니다를 합니다.ClipView
의clipsToBounds
로 설정됩니다.YES
그 폭이 부모 뷰의 폭보다 작을 경우.또도.ClipView
합니다에 합니다.UIScrollView
.
는 입니다를(를) 재정의하는 입니다.- (UIView *)hitTest:withEvent:
안에ClipView
.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? scrollView : nil;
}
으로 합니다.UIScrollView
부모님의 관점에서 당신이 필요로 하는 것을 말입니다.
은 서브클래스 입니다입니다.UIScrollView
그리고 그것을 무시합니다.- (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) event
method이며,다를(를) 를 결정하기 어려울 수 .YES
UIScrollView
의 체구.
참고: 서브뷰 사용자 상호 작용에 문제가 있는 경우 Juri Pakaste의 히트 Test:withEvent:modification도 살펴봐야 합니다.
ClipView
에게 효과가 는 다른만,다를 했습니다.-[UIView hitTest:withEvent:]
실행. Marty 은 가로 뷰와 상호 하지 .Ed Marty 버전은 가로 스크롤 안에 있는 세로 스크롤 뷰와 사용자 상호 작용을 하지 않았습니다.
다음 버전이 제게 효과가 있었습니다.
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* child = nil;
if ((child = [super hitTest:point withEvent:event]) == self)
return self.scrollView;
return child;
}
scrollView의 프레임 크기를 페이지 크기로 설정합니다.
[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];
이제 당신은 팬온을 할 수 있습니다.self.view
.
사용.scrollView.clipsToBounds = NO;
내용을 잘라내는 것을 방지합니다.
사용자 지정 UIScrollView가 제가 보기에는 가장 빠르고 간단한 방법이었기 때문에 결국 사용자 지정 UIScrollView를 사용하게 되었습니다.하지만 정확한 코드가 없어서 공유하려고 했습니다.저는 내용이 작은 UIScrollView가 필요했습니다. 따라서 UIScrollView 자체가 페이징 효과를 얻기에는 작았습니다.게시글에 쓰여 있듯이 가로챌 수 없습니다.하지만 이제는 할 수 있습니다.
클래스 CustomScrollView 및 하위 클래스 UISscrollView를 만듭니다.그러면 이 파일을 .m 파일에 추가하기만 하면 됩니다.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return (point.y >= 0 && point.y <= self.frame.size.height);
}
이렇게 하면 좌우(수평)로 스크롤할 수 있습니다.그에 따라 경계를 조정하여 스와이프/스크롤 터치 면적을 설정합니다.맛있게 드세요.
스크롤 뷰를 자동으로 반환할 수 있는 다른 구현을 했습니다.따라서 프로젝트에서 재사용을 제한하는 IBOutlet을 가질 필요가 없습니다.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if ([self pointInside:point withEvent:event]) {
for (id view in [self subviews]) {
if ([view isKindOfClass:[UIScrollView class]]) {
return view;
}
}
}
return nil;
}
ClipView hitTest 구현에 유용한 다른 수정 사항이 있습니다.UIScrollView 참조를 ClipView에 제공해야 하는 것이 싫었습니다.아래의 제 구현을 통해 ClipView 클래스를 다시 사용하여 모든 것의 히트 테스트 영역을 확장할 수 있으며 참조와 함께 제공할 필요가 없습니다.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (([self pointInside:point withEvent:event]) && (self.subviews.count >= 1))
{
// An extended-hit view should only have one sub-view, or make sure the
// first subview is the one you want to expand the hit test for.
return [self.subviews objectAtIndex:0];
}
return nil;
}
했지만,UICollectionView
저는 틀에서 벗어난 것은 무엇이든 화면에서 꺼지도록 사용하고 있었습니다.이로 인해 사용자가 자신을 향해 스크롤할 때만 주변 셀이 경계 밖으로 렌더링되는 현상이 발생했는데, 이는 이상적이지 않았습니다.
된 (또는 하는 것이었습니다.UICollectionViewLayout
).
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
if (velocity.x > 0) {
proposedContentOffset.x = ceilf(self.collectionView.contentOffset.x / pageSize) * pageSize;
}
else {
proposedContentOffset.x = floorf(self.collectionView.contentOffset.x / pageSize) * pageSize;
}
return proposedContentOffset;
}
이렇게 하면 스와이프 동작을 전적으로 위임할 수 없게 되고, 이는 보너스이기도 합니다.UIScrollViewDelegate
다라는 을 가지고 .scrollViewWillEndDragging:withVelocity:targetContentOffset:
UITableViews 및 UISscrollViews 를 페이지화하는 데 사용할 수 있습니다.
이 SO 질문의 기법을 지원하면서 스크롤 뷰의 자식 뷰에서 실행 탭 이벤트를 활성화합니다.가독성을 위해 스크롤 뷰(self.scrollView)에 대한 참조를 사용합니다.
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = nil;
NSArray *childViews = [self.scrollView subviews];
for (NSUInteger i = 0; i < childViews.count; i++) {
CGRect childFrame = [[childViews objectAtIndex:i] frame];
CGRect scrollFrame = self.scrollView.frame;
CGPoint contentOffset = self.scrollView.contentOffset;
if (childFrame.origin.x + scrollFrame.origin.x < point.x + contentOffset.x &&
point.x + contentOffset.x < childFrame.origin.x + scrollFrame.origin.x + childFrame.size.width &&
childFrame.origin.y + scrollFrame.origin.y < point.y + contentOffset.y &&
point.y + contentOffset.y < childFrame.origin.y + scrollFrame.origin.y + childFrame.size.height
){
hitView = [childViews objectAtIndex:i];
return hitView;
}
}
hitView = [super hitTest:point withEvent:event];
if (hitView == self)
return self.scrollView;
return hitView;
}
터치 이벤트를 캡처하려면 하위 보기에 추가합니다.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
(이는 user1856273의 솔루션을 변형한 것입니다.가독성을 위해 청소하고 바트서크의 버그 수정을 포함시켰습니다.user1856273의 답변을 수정하려고 생각했는데 너무 큰 변경이었습니다.)
my version 스크롤에 누워있는 버튼 누르기 - work = )
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView* child = nil;
for (int i=0; i<[[[[self subviews] objectAtIndex:0] subviews] count];i++) {
CGRect myframe =[[[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i] frame];
CGRect myframeS =[[[self subviews] objectAtIndex:0] frame];
CGPoint myscroll =[[[self subviews] objectAtIndex:0] contentOffset];
if (myframe.origin.x < point.x && point.x < myframe.origin.x+myframe.size.width &&
myframe.origin.y+myframeS.origin.y < point.y+myscroll.y && point.y+myscroll.y < myframe.origin.y+myframeS.origin.y +myframe.size.height){
child = [[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i];
return child;
}
}
child = [super hitTest:point withEvent:event];
if (child == self)
return [[self subviews] objectAtIndex:0];
return child;
}
objectAt만 [self subviews]인덱스: 0]은(는) 스크롤이어야 합니다.
여기 Ed Marty의 답변을 바탕으로 한 스위프트 답변이 있으며 스크롤 뷰 내부에서 버튼 탭 등이 가능하도록 Juri Pakaste가 수정한 내용도 포함되어 있습니다.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
return view == self ? scrollView : view
}
스위프트 5 / iOS 15
- 내 의 TLDR - 합니다를 합니다.hitTest(...)
저는 사용자가 왼쪽이나 오른쪽의 페이지를 탭하여 가운데로 스크롤할 수 있기를 원했지만 기존 솔루션은 작동하지 않았습니다(이를 위해 각 페이지에 제스처 인식기를 추가했으며 제스처가 외부 페이지에 대해 트리거되지 않았습니다).scrollView
틀을 짜다).
hitTest
오버라이드는 좋지 않았습니다. 각 페이지의 요소가 터치에 반응하지 않았습니다(탭에 반응하지 않는 UIS 스위치가 있었습니다).hitTest(...)
다 각 왜냐하면 탭은 외부 페이지에 있기 때문입니다.scrollView
합니다).scrollView
, ).
대신 다음 코드를 사용했는데, 완벽하게 작동합니다.저는 인터넷에 접속하는 것을 좋아하지 않습니다.scrollView
의 컨텐츠는 이와 같이 표시되지만 코드가 충돌하지 않고 원래 제안된 코드로 안전하게 돌아갑니다.면에 하는 더 을 아는 ,scrollView
의 컨텐츠 뷰를 봐주시면 감사하겠습니다.
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let scrollViewContentView = scrollView.subviews.first else {
// fallback behavior - user can scroll carousel if touch starts outside the scrollView frame, but taps on elements outside the scrollView frame will be ignored
let view = super.hitTest(point, with: event)
return view == self ? scrollView : view
}
let convertedPoint = scrollViewContentView.convert(point, from: self)
return self.point(inside: point, with: event) ? scrollViewContentView.hitTest(convertedPoint, with: event) : nil
}
UIScrollView의 경계를 벗어나 컨테이너 뷰 내부에 있는 뷰를 UIScrollView에서 터치할 수 있는 경우.
- 컨테이너 뷰에 터치 가능한 뷰 할당
- 를 무시하다
hitTest
보기 계층 구조는
- ContainerView
-- UIScrollView
--- ContentViews
컨테이너 뷰에 대한 예로 아래 클래스를 예로 들어 보겠습니다.
class PassthroughView: UIView {
var touchableSubviews: [UIView] = []
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
for view in touchableSubviews {
if let v = view.hitTest(view.convert(point, from: self), with: event) {
return v
}
}
return super.hitTest(point, with: event)
}
}
컨테이너의 서브뷰 계층 구조를 반복할 수 있지만, 저는 좀 더 명확한 것이 좋습니다.
이제 내용 보기가 전체 화면 너비보다 작을 수 있는 페이징이 활성화된 UIScrollView가 있습니다.콘텐츠를 일반 UISCrollView인 것처럼 터치하고 스크롤할 수 있습니다.
UIScrollView에서 속성을 설정하는 것도 잊지 마십시오.
scrollView.isPagingEnabled = true
scrollView.clipsToBounds = false
언급URL : https://stackoverflow.com/questions/1220354/uiscrollview-horizontal-paging-like-mobile-safari-tabs
'programing' 카테고리의 다른 글
다중 인수를 tong-click 메서드에 전달 (0) | 2023.10.07 |
---|---|
C: 2차원 배열 크기 (0) | 2023.10.07 |
w3wp clr.dll 오류 디버그 방법 (0) | 2023.10.07 |
Android에서 활동에서 단편으로 데이터 전송 (0) | 2023.10.07 |
git reset --hard HEAD~1'과 'git reset --soft HEAD~1'의 차이점은 무엇입니까? (0) | 2023.10.07 |