简体   繁体   中英

about UICollectionView Horizontal Paging with pure code

In order to achieve auto Horizontal scrolling, I custom a collectionView with 100 sections, and there're 5 items in every section. And then add a NSTimer, the original position is set to the middle of collectionView(the 50th sections), it works at last. (ps: the collectionView is the headerView of a tableView!)

However, when I scroll it by myself, it can't be scrolled to the next page properly. It always appears two items(position is irregular), but I only wanna one instead.

( Newest Progress:

After setting flowLayout.minimumLineSpacing = 0.0f. the margin of two items becomes regular(close to a unknown fixed value). And I found if I just finish launching the app and to scroll it by myself, it behaves normal. But if waiting the NSTimer runs and to scroll, it behaves the above what I have said. In a word, if there is no NSTimer, it behaves normal. Maybe there is something wrong with NSTimer...)

Excepted:

在此处输入图片说明

在此处输入图片说明

Original Actually:

在此处输入图片说明

在此处输入图片说明

Newest Actually

在此处输入图片说明

在此处输入图片说明

If I need override scrollViewDidScroll: , and how? Or pay attention to some attributes? Is there something wrong with my NSTimer?

Some codes:

**POChannelPageHeader.h**  (a UICollectionViewCell)

@class POChannelPageItem;

@interface POChannelPageHeader : UICollectionViewCell
@property (nonatomic, strong) POChannelPageItem *channelPageItem;
+ (UICollectionViewCell *)cellWithCollectionView:(UICollectionView *)collectionView;

**POChannelPageHeader.m**
@interface POChannelPageHeader ()
@property (weak, nonatomic)  UILabel *titleLabel;
@property (weak, nonatomic)  UIImageView *picView;
@end


- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {

        [self makeView];
    }

    return self;
}

#pragma mark  custom cell
- (void)makeView
{
    UIImageView * picView = [[UIImageView alloc] init];
    self.picView = picView;
    self.picView.alpha = 0.1f;
    self.picView.contentMode = UIViewContentModeScaleToFill;
    [self.contentView addSubview:self.picView];

    UILabel *titleLabel = [[UILabel alloc] init];
    self.titleLabel = titleLabel;
    self.titleLabel.font = [UIFont systemFontOfSize:15.0f];
    self.titleLabel.textColor = [UIColor whiteColor];
    [self.titleLabel setBackgroundColor:[UIColor colorWithWhite:0.0f alpha:0.6f]];
    self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
    [self.contentView addSubview:self.titleLabel];
}


#pragma mark layoutSubviews
-(void)layoutSubviews
{
    [super layoutSubviews];

    self.picView.x = 0.0f;
    self.picView.y = 0.0f;
    self.picView.width = kScreenWidth ;
    self.picView.height = 0.4 * kScreenHeight;

    self.titleLabel.x = self.picView.x;
    self.titleLabel.width = kScreenWidth;
    CGFloat titleLabelPadding = 12.0f; 
    self.titleLabel.height = [NSString heightForText:self.titleLabel.text boundingRectWithWidth:TitleLabelWidth fontOfSize:15.0f] + titleLabelPadding;
    self.titleLabel.y = self.picView.height - self.titleLabel.height;

}

#pragma mark - setter
- (void)setChannelPageItem:(POChannelPageItem *)channelPageItem
{
    _channelPageItem = channelPageItem;
    self.picView.alpha = 0.1f;
    UIImage *placeholderImage = [UIImage imageWithColor:[UIColor colorWithWhite:0.0 alpha:0.2f]];
    [self.picView sd_setImageWithURL:[NSURL URLWithString:_channelPageItem.imgsrc] placeholderImage:placeholderImage options:SDWebImageRetryFailed completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        [UIView animateWithDuration:0.5f animations:^{
            self.picView.alpha = 1.0f;
        }];
    }];

    self.titleLabel.text = [@"  "  stringByAppendingString:_channelPageItem.title];

}




#import "POChannelPageViewController.h" ( a UITableViewController)

#define POChannelHeaderID     @"POChannelPageHeader"
#define POMaxSections         100
#define POChannelHeaderPages  5

@interface POChannelPageViewController () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>

@property (weak, nonatomic)  UICollectionView *headerView;
@property (nonatomic, strong) NSMutableArray *headerNews;
@property (nonatomic, strong) NSTimer *timer;
@property (weak, nonatomic) UIPageControl *headerPage;


@end



- (void)viewDidLoad {

    [super viewDidLoad];
    [self makeHeaderView]
}

- (void)makeHeaderView
{

    UICollectionViewFlowLayout *flowLayout= [[UICollectionViewFlowLayout alloc]init];
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    flowLayout.itemSize = CGSizeMake(kScreenWidth, 0.4 * kScreenHeight);
    UICollectionView *headerView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth , 0.4 *kScreenHeight) collectionViewLayout:flowLayout];
    headerView.pagingEnabled = YES;

    self.headerView = headerView;
    self.headerView.delegate = self;
    self.headerView.dataSource = self;
    self.headerView.showsHorizontalScrollIndicator = NO;

    [self.headerView registerClass:[POChannelPageHeader class] forCellWithReuseIdentifier:POChannelHeaderID];
    self.tableView.tableHeaderView =self.headerView;

    // add PageControl
    UIPageControl *headerPage = [[UIPageControl alloc] init];
    headerPage.x = kScreenWidth - 100.0f  + 2.0f; // little adjustment 
    headerPage.height = 37;
    headerPage.y =  self.headerView.height - headerPage.height +  5.0f;// little adjustment 
    headerPage.width = 100.0f;
    self.headerPage = headerPage;
    self.headerPage.numberOfPages = POChannelHeaderPages;
    self.headerPage.currentPage = 0;
    self.headerPage.pageIndicatorTintColor = [UIColor lightGrayColor];
    self.headerPage.currentPageIndicatorTintColor = [UIColor colorWithRed:0.735 green:1.000 blue:0.300 alpha:1.000];
    [self.tableView addSubview:self.hederPage];

    [self.headerView  scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:POMaxSections / 2] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

    [self addTimer];

}

#pragma mark - add Timer
- (void)addTimer
{
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    self.timer = timer;

}

#pragma mark - remove Timer
- (void)removeTimer
{
    [self.timer invalidate];
    self.timer = nil;
}

#pragma mark - resetIndexPath
- (NSIndexPath *)resetIndexPath
{
    NSIndexPath *currentIndexPath = [[self.headerView indexPathsForVisibleItems] lastObject];

    NSIndexPath *currentIndexPathReset = [NSIndexPath indexPathForItem:currentIndexPath.item inSection:POMaxSections / 2];

    [self.headerView scrollToItemAtIndexPath:currentIndexPathReset atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
    return currentIndexPathReset;
}

- (void)nextPage
{
    NSIndexPath *currentIndexPathReset = [self resetIndexPath];

    NSInteger nextItem = currentIndexPathReset.item + 1;
    NSInteger nextSection = currentIndexPathReset.section;
    if (nextItem == self.headerNews.count) {
        nextItem = 0;
        nextSection++;
    }
    NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:nextItem inSection:nextSection];

    [self.headerView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}

#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.headerNews.count;
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return POMaxSections;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    POChannelPageHeader *cell = [collectionView dequeueReusableCellWithReuseIdentifier:POChannelHeaderID forIndexPath:indexPath];

    cell.channelPageItem = self.headerNews[indexPath.item];

    return cell;
}

#pragma mark  - UICollectionViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
        [self removeTimer];

}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{

    if (scrollView == self.headerView) {
         [self addTimer];
    }


}



**// I'm not sure this method, because I study from a demo**
- (void)scrollViewDidScroll:(UIScrollView *)scrollView  
{
    if(scrollView == self.tableView ){
        **// especially here!!!** 
     NSInteger page = (NSInteger)(scrollView.contentOffset.x / scrollView.bounds.size.width + 0.5) % self.headerNews.count;
     self.headerPage.currentPage = page;

  } else if (scrollView ==self.tableView && scrollView.contentOffset.y ==0){

      [self addTimer];

} 

Can you explain why did you create 100 section instead of one section with 100 items? Anyway I see 2 mistakes: 1) You have a full width picture and "inter item space", but you don't have a place on the screen for this space (in your case it is not inter item space, but right section inset or something else) 2) You have a right section inset, but you don't have a left

So if you will set initial position to first cell and swipes, you'll see a section inset on the screen. At the next swipe you will see small part of the previous cell, inset and next cell... In this way after 50 swipes you will see unpredictable screen offset.

I had paint a some way to solve your problem (sorry for my fotoshop's skill :D). In the picture black rect is screen, red - collection view, and green - cell. X is your space between cells. So you need to increase collection view width, depose it left, set left and right section insets with half value of this space.

在此处输入图片说明

Resulting in you will have a full screen width picture with inter item space, that you will see only while swiping.

EDIT: there is example project https://github.com/dimasv28/slider

Why not use a UIPageViewController for this? It seems like a much better fit for your problem. It's designed to do exactly what you're trying to do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM