paging в UIScrollView - отличная возможность, мне нужно здесь, чтобы установить пейджинг на меньшее расстояние, например, я хочу, чтобы мой UIScrollView отображал меньше размера, чем ширина кадра UIScrollView. Благодаря
Размер пользовательского подкачки UIScrollView
Ответ 1
Существует метод делегата UIScrollView
который вы можете использовать. Установите свой класс в качестве делегата представления прокрутки, а затем реализуйте следующее:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
CGFloat kMaxIndex = 23;
CGFloat targetX = scrollView.contentOffset.x + velocity.x * 60.0;
CGFloat targetIndex = 0.0;
if (velocity.x > 0) {
targetIndex = ceil(targetX / (kCellWidth + kCellSpacing));
} else if (velocity.x == 0) {
targetIndex = round(targetX / (kCellWidth + kCellSpacing));
} else if (velocity.x < 0) {
targetIndex = floor(targetX / (kCellWidth + kCellSpacing));
}
if (targetIndex < 0)
targetIndex = 0;
if (targetIndex > kMaxIndex)
targetIndex = kMaxIndex;
targetContentOffset->x = targetIndex * (kCellWidth + kCellSpacing);
//scrollView.decelerationRate = UIScrollViewDecelerationRateFast;//uncomment this for faster paging
}
Параметр скорости необходим для того, чтобы прокрутка была естественной и не заканчивалась внезапно, когда касание заканчивается, когда ваш палец все еще движется. Ширина ячейки и расстояние между ячейками - это ширина страницы и расстояние между страницами в вашем представлении. В этом случае я использую UICollectionView
.
Ответ 2
- Измените размер scrollView на желаемый размер страницы.
- Установите
scroll.clipsToBounds = NO
-
Создайте подкласс UIView (например, HackClipView) и переопределите метод hitTest: withEvent: method
-(UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event { UIView* child = [super hitTest:point withEvent:event]; if (child == self && self.subviews.count > 0) { return self.subviews[0]; } return child; }
-
Установите
HackClipView.clipsToBounds = YES
- Поместите свой scrollView в этот HackClipView (с полным размером прокрутки).
Подробнее см. этот ответ
Обновление:
Как указано в ответе lucius, теперь вы можете реализовать протокол UIScollViewDelegate
и использовать метод - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
. Поскольку targetContentOffset
является указателем. Использование этого метода не гарантирует вам тот же результат со страницами просмотра прокрутки, так как пользователь может прокручивать сразу несколько страниц. Но установка descelerationRate
в fast
почти даст вам тот же результат
Ответ 3
Вы должны отключить пейджинг и добавить UIPanGestureRecognizer в свое представление прокрутки и самостоятельно обрабатывать пейджинг.
- (void)viewDidLoad {
[super viewDidLoad];
CGRect viewRect = self.view.bounds; // View controller view bounds
theScrollView = [[UIScrollView alloc] initWithFrame:viewRect];
theScrollView.scrollsToTop = NO;
theScrollView.pagingEnabled = NO;
theScrollView.delaysContentTouches = NO;
theScrollView.delegate = self;
[self.view addSubview:theScrollView];
UIPanGestureRecognizer * peter = [[[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)]
autorelease];
[theScrollView addGestureRecognizer:peter];
}
-(void)handlePan:(UIPanGestureRecognizer*)recognizer{
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:{
// panStart and startPoint are instance vars for the viewContainer
panStart = theScrollView.contentOffset;
startPoint = [recognizer locationInView:theScrollView];
break;
}
case UIGestureRecognizerStateChanged:{
CGPoint newPoint = [recognizer locationInView:theScrollView];
CGFloat delta = startPoint.x - newPoint.x;
if ( abs(delta) > 2)
theScrollView.contentOffset = CGPointMake( theScrollView.contentOffset.x + delta, 0);
CGFloat moveDelta = panStart.x - theScrollView.contentOffset.x;
// current witdh should hold the currently displayed page/view in theScrollView
if ( abs(moveDelta) > (currentWidth * 0.40)){
panStart = theScrollView.contentOffset;
startPoint = newPoint;
//NSLog(@"delta is bigger");
if ( moveDelta < 0 )
[self incrementPageNumber]; // you should implement this method and present the next view
else
[self decrementPageNumber]; // you should implement this method and present the previous view
recognizer.enabled = NO; // disable further event until view change finish
}
break;
}
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
recognizer.enabled = YES;
[self showDocumentPage:currentPage];
break;
default:
break;
}
}
Ответ 4
Решение Swift 4.1, которое упрощает повторное использование:
/// Protocol that simplifies custom page size configuration for UIScrollView.
/// Sadly, can not be done better due to protocol extensions limitations - https://stackoverflow.com/questions/39487168/non-objc-method-does-not-satisfy-optional-requirement-of-objc-protocol
/// - note: Set '.decelerationRate' to 'UIScrollViewDecelerationRateFast' for a fancy scrolling animation.
protocol ScrollViewCustomHorizontalPageSize: UIScrollViewDelegate {
/// Custom page size
var pageSize: CGFloat { get }
/// Helper method to get current page fraction
func getCurrentPage(scrollView: UIScrollView) -> CGFloat
/// Helper method to get targetContentOffset. Usage:
///
/// func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
/// targetContentOffset.pointee.x = getTargetContentOffset(scrollView: scrollView, velocity: velocity)
/// }
func getTargetContentOffset(scrollView: UIScrollView, velocity: CGPoint) -> CGFloat
/// Must be implemented. See 'getTargetContentOffset' for more info.
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
}
extension ScrollViewCustomHorizontalPageSize {
func getCurrentPage(scrollView: UIScrollView) -> CGFloat {
return (scrollView.contentOffset.x + scrollView.contentInset.left) / pageSize
}
func getTargetContentOffset(scrollView: UIScrollView, velocity: CGPoint) -> CGFloat {
let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
var targetIndex = (targetX + scrollView.contentInset.left) / pageSize
let maxOffsetX = scrollView.contentSize.width - scrollView.bounds.width + scrollView.contentInset.right
let maxIndex = (maxOffsetX + scrollView.contentInset.left) / pageSize
if velocity.x > 0 {
targetIndex = ceil(targetIndex)
} else if velocity.x < 0 {
targetIndex = floor(targetIndex)
} else {
let (maxFloorIndex, lastInterval) = modf(maxIndex)
if targetIndex > maxFloorIndex {
if targetIndex >= lastInterval / 2 + maxFloorIndex {
targetIndex = maxIndex
} else {
targetIndex = maxFloorIndex
}
} else {
targetIndex = round(targetIndex)
}
}
if targetIndex < 0 {
targetIndex = 0
}
var offsetX = targetIndex * pageSize - scrollView.contentInset.left
offsetX = min(offsetX, maxOffsetX)
return offsetX
}
}
Просто ScrollViewCustomPageSize
протоколу ScrollViewCustomPageSize
в вашем ScrollViewCustomPageSize
UIScrollView/UITableView/UICollectionView, и все готово, например:
extension MyCollectionViewController: ScrollViewCustomPageSize {
var pageSize: CGFloat {
return 200
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
targetContentOffset.pointee.x = getTargetContentOffset(scrollView: scrollView, velocity: velocity)
}
}
Для необычной прокрутки я также рекомендую установить collectionView.decelerationRate = UIScrollViewDecelerationRateFast
Ответ 5
Установите contentOffset
в
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
.
Также см. UIScrollViewDelegate ссылается
Ответ 6
У меня была такая же проблема, поэтому я создал пользовательский UIScrollView. Теперь он доступен в Github, потому что, когда я искал, я не нашел таких решений. Наслаждайтесь! https://github.com/MartinMetselaar/MMCPSScrollView
MMCPSScrollView* scrollView = [[MMCPSScrollView alloc] initWithFrame:self.view.bounds];
[scrollView setType:MMCPSScrollVertical];
[scrollView setPageHeight:250];
[scrollView setPageSize:2];
[self.view addSubview:scrollView];
Если у вас есть дополнительные вопросы об этом компоненте, просто спросите.
Ответ 7
У меня была одна и та же проблема. Мой aproach должен был добавить второй UIScrollView
в scrollview. Таким образом, вы можете перейти на страницу. На этой странице кажется, что если страница больше экрана. Надеюсь, это сработает и в вашей ситуации.; -)
Сандро Мейер
Ответ 8
Мне это показалось намного лучше:
Пользовательский пейджинг UIScrollView
Здесь они добавляют scrollview (сохраняя его пейджинговую привлекательность) в качестве подзаголовка в ExtendedTouchView или подкласс UIVIew и перезаписывая метод тестового теста
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
if ([[self subviews] count] > 0) {
//force return of first child, if exists
return [[self subviews] objectAtIndex:0];
} else {
return self;
}
}
return nil;
}
Это сделало именно то, что я хотел с минимальным кодом и головной болью.
Ответ 9
Добавление распознавателей жестов или других подзаголовков и т.д. глупо. Просто установите делегат для просмотра прокрутки, как показано ниже:
// This is for a vertical scrolling scroll view.
// Let say you want it to snap to every 160 pixels :
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
int y = scrollView.contentOffset.y;
int yOff = y % 160;
if(yOff < 80)
y -= yOff;
else
y += 160 - yOff;
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, y) animated:YES];
}
// This is for a horizontal scrolling scroll view.
// Let say you want the same, to snap to every 160 pixels :
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
int x = scrollView.contentOffset.x;
int xOff = x % 160;
if(xOff < 80)
x -= xOff;
else
x += 160 - xOff;
[scrollView setContentOffset:CGPointMake(x, scrollView.contentOffset.y) animated:YES];
}
Ответ 10
Swift 4.1, iOS11+:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
targetContentOffset.pointee = CGPoint(
x: round(targetContentOffset.pointee.x / pageWidth) * pageWidth,
y: targetContentOffset.pointee.y
)
}
Ответ 11
Самый простой способ - добавить этот код
scrollView.clipsToBounds = false
scrollView.removeGestureRecognizer(scrollView.panGestureRecognizer)
view.addGestureRecognizer(scrollView.panGestureRecognizer)