Возможно, что то, что устанавливает эти числа там, не очень впечатляет, когда вы устанавливаете contentOffset в его руки. Таким образом, он просто устанавливает то, что, по его мнению, должно быть contentOffset в следующий момент, не проверяя, изменилось ли за это время contentOffset.
Я бы создал подкласс UIScrollView и вложил волшебство в метод setContentOffset
. По моему опыту, все изменение смещения содержимого проходит через этот метод, даже изменение смещения содержимого, вызванное внутренней прокруткой. Просто выполните [super setContentOffset: ..]
в какой-то момент, чтобы передать сообщение реальному UIScrollView.
Может быть, если вы поместите туда свое переключение, это сработает лучше. Вы могли бы по крайней мере обнаружить 3000-off настройку contentOffset и исправить ее перед передачей сообщения. Если вы также переопределите метод contentOffset
, вы можете попробовать и посмотреть, сможете ли вы создать виртуальный бесконечный размер контента и уменьшить его до реальных пропорций «под капотом».
Когда я столкнулся с этой проблемой, у меня было 3 изображения, которые нужно было прокручивать бесконечно в любом направлении. Оптимальным решением, вероятно, было бы загрузить 3 изображения и изменить панель содержимого, когда пользователь перемещается к крайнему правому / левому изображению, но я нашел более простое решение. (Внесены некоторые изменения в код, могут содержать опечатки)
Вместо 3 изображений я настроил представление прокрутки с 5 изображениями, например:
3 | 1 | 2 | 3 | 1
и рассчитал представление содержимого соответствующим образом тогда как размер контента фиксирован. Вот код:
for ( NSUInteger i = 1; i <= NO_OF_IMAGES_IN_SCROLLVIEW + 2 ; i ++) {
UIImage *image;
if ( i % 3 == 1){
image = [UIImage imageNamed:[NSString stringWithFormat:@"img1.png"]];
}
else if (i % 3 == 2 ) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"img2.png"]];
}
else {
image = [UIImage imageNamed:[NSString stringWithFormat:@"img3.png"]];
}
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((i-1)*_scrollView.frame.size.width, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
imageView.contentMode=UIViewContentModeScaleToFill;
[imageView setImage:image];
imageView.tag=i+1;
[self.scrollView addSubview:imageView];
}
[self.scrollView setContentOffset:CGPointMake(self.scrollView.frame.size.width, 0)];
[scrMain setContentSize:CGSizeMake(self.scrollView.frame.size.width * ( NO_OF_IMAGES_IN_SCROLLVIEW + 2 ), self.scrollView.frame.size.height)];
Теперь, когда изображения добавлены, остается только создать иллюзию бесконечной прокрутки. Для этого я «телепортировал» пользователя в три основных изображения, когда бы он ни пытался прокрутить одно из двух внешних изображений. Важно сделать это без анимации, чтобы пользователь не смог это почувствовать:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.x < scrollView.frame.size.width ){
[scrollView scrollRectToVisible:CGRectMake(scrollView.contentOffset.x + 3 * scrollView.frame.size.width, 0, scrollView.frame.size.width, scrollView.frame.size.height) animated:NO];
}
}
else if ( scrollView.contentOffset.x > 4 * scrollView.frame.size.width ){
[scrollView scrollRectToVisible:CGRectMake(scrollView.contentOffset.x - 3 * scrollView.frame.size.width, 0, scrollView.frame.size.width, scrollView.frame.size.height) animated:NO];
}
}
Я сделал пример проекта, чтобы решить вашу проблему.
Вы можете скачать код с
https://code.google.com/p/iphone-infinite-horizont-scroller/
, который прокручивается в в обоих направлениях бесконечно и загружает изображения на ходу.
Я разработал этот вид uiscrollview, так что вы можете проверить мой проект в Infinite UIScrollView в обоих направлениях
Я сделал подкласс UIScrollView, который просто делает то, что вы хотите. Он просто прокручивается навсегда в любых направлениях, даже в обоих направлениях одновременно. Он поддерживает плавную прокрутку и прокрутку подкачки
Таким образом, одна проблема заключается в том, что установка contentOffset в методе scrollViewDidScroll: Delegate приведет к повторному запуску метода делегата, пока вы находитесь внутри него. Так что я делаю, это удаляю делегата> setContentOffset> снова устанавливаем делегата.
Вот мой код:
#import "ViewController.h"
@interface ViewController () <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) NSMutableArray *labels;
@property (weak, nonatomic) UILabel *originLabel;
- (void)addScrollViewLabels;
- (void)adjustOrigins:(float)deltaX;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// just some starting size
CGSize size = self.scrollView.frame.size;
CGSize contentSize = CGSizeMake(size.width * 4, size.height);
[self.scrollView setContentSize:contentSize];
// just some starting offset
CGPoint contentOffset = CGPointMake((contentSize.width / 2), 0);
[self.scrollView setContentOffset:contentOffset];
[self addScrollViewLabels];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGSize contentSize = scrollView.contentSize;
CGSize size = scrollView.frame.size;
CGPoint contentOffset = scrollView.contentOffset;
const float kContentOffsetBuffer = 100;
const float kContentSizeGrowth = (4 * size.width);
BOOL shouldGrowContentSize = (contentOffset.x > (contentSize.width - size.width - kContentOffsetBuffer))
|| (contentOffset.x < (kContentOffsetBuffer));
if (shouldGrowContentSize) {
// the contentOffset has reached a point where we need to grow the contentSize
CGSize adjustedContentSize = CGSizeMake(contentSize.width + kContentSizeGrowth, contentSize.height);
[self.scrollView setContentSize:adjustedContentSize];
if(contentOffset.x < (kContentOffsetBuffer)) {
// the growth needs to happen on the left side which means that we need to adjust the contentOffset to compensate for the growth.
// this is not necessary when growth happens to the right since the contentOffset is the same.
CGPoint adjustedContentOffset = CGPointMake(contentOffset.x + kContentSizeGrowth, contentOffset.y);
[self.scrollView setDelegate:nil];
[self.scrollView setContentOffset:adjustedContentOffset];
[self.scrollView setDelegate:self];
[self adjustOrigins:kContentSizeGrowth];
}
[self addScrollViewLabels];
}
}
- (void)addScrollViewLabels {
const float kOriginY = 100;
if (!self.labels) {
self.labels = [NSMutableArray array];
float originX = [self.scrollView contentOffset].x;
UILabel *label0 = [[UILabel alloc] initWithFrame:CGRectMake(originX, kOriginY, 100, 30)];
label0.text = @"0";
[self.scrollView addSubview:label0];
[self.labels addObject:label0];
self.originLabel = label0;
}
CGSize contentSize = [self.scrollView contentSize];
const float kIncrementAmount = 75;
NSInteger indexOfOriginLabel = [self.labels indexOfObject:self.originLabel];
// add labels to the right
UILabel *lastLabel = [self.labels lastObject];
float lastOriginX = lastLabel.frame.origin.x;
for (float x = (lastOriginX + kIncrementAmount); (x < (contentSize.width)) ; x += kIncrementAmount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x, kOriginY, 100, 30)];
NSInteger indexFromOrigin = ([self.labels count] - indexOfOriginLabel);
label.text = [@(indexFromOrigin) description];
[self.scrollView addSubview:label];
[self.labels addObject:label];
[label setNeedsDisplay];
}
// add labels to the left
UILabel *firstLabel = [self.labels firstObject];
float firstOriginX = firstLabel.frame.origin.x;
for (float x = (firstOriginX - kIncrementAmount); (x >= 0) ; x -= kIncrementAmount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x, kOriginY, 100, 30)];
NSInteger indexFromOrigin = -(indexOfOriginLabel + 1);
label.text = [@(indexFromOrigin) description];
[self.scrollView addSubview:label];
[self.labels insertObject:label atIndex:0];
indexOfOriginLabel++;
[label setNeedsDisplay];
}
}
- (void)adjustOrigins:(float)deltaX {
for (UILabel *label in self.labels) {
CGRect frame = label.frame;
frame.origin.x += deltaX;
[label setFrame:frame];
[label setNeedsDisplay];
}
}
@end
(надеюсь, я публикую это правильно - я здесь новенький!?)
mvds был на высоте - спасибо - подкласс UIScrollView работает отлично - мне еще предстоит реализовать смещение и загрузка новых данных, но у меня есть UIScrollView, который прокручивается в бесконечном цикле!
Вот код:
#import "BRScrollView.h"
@implementation BRScrollView
- (id)awakeFromNib:(NSCoder *)decoder {
offsetAdjustment = 0;
[super initWithCoder:decoder];
return self;
}
- (void)setContentOffset:(CGPoint)contentOffset {
float realOffset = contentOffset.x + offsetAdjustment;
//This happens when contentOffset has updated correctly - there is no need for the adjustment any more
if (realOffset < expectedContentOffset-2000 || realOffset > expectedContentOffset+2000) {
offsetAdjustment = 0;
realOffset = contentOffset.x;
}
float pageNumber = realOffset / 320;
float pageCount = self.contentSize.width / 320;
if (pageNumber > pageCount-4) {
offsetAdjustment -= 3200;
realOffset -= 3200;
}
if (pageNumber < 4) {
offsetAdjustment += 3200;
realOffset += 3200;
}
//Save expected offset for next call, and pass the real offset on
expectedContentOffset = realOffset;
[super setContentOffset:CGPointMake(realOffset, 0)];
}
- (void)dealloc {
[super dealloc];
}
@end
Примечания:
Если вам действительно нужен бесконечный цикл, вам нужно отрегулировать числа - этот код замечает, когда вы приближаетесь к краю, и перемещает вас сразу за середину
My contentSize - 6720 (21 страница)
Меня интересует только горизонтальная прокрутка, поэтому сохраняйте только значения x и жестко закодируйте y на 0!
Бен