【问题标题】:about UICollectionView Horizontal Paging with pure code关于纯代码的 UICollectionView 水平分页
【发布时间】:2015-03-07 09:34:42
【问题描述】:

为了实现自动水平滚动,我自定义了一个collectionView,有100个section,每个section有5个item。然后添加一个NSTimer,将原来的位置设置在collectionView的中间(第50节),终于可以工作了。 (ps:collectionView是一个tableView的headerView!)

但是,当我自己滚动时,无法正常滚动到下一页。总是出现两个项目(位置不规则),但是我只想要一个。

(最新进展:

设置flowLayout.minimumLineSpacing = 0.0f.后,两个项目的边距变为规则(接近一个未知的固定值)。而且我发现如果我刚刚完成启动应用程序并自己滚动它,它的行为是正常的。但是,如果等待 NSTimer 运行并滚动,它的行为如上所述。总之,如果没有 NSTimer,它的行为是正常的。也许 NSTimer 有问题...)

例外:

原文:

最新的实际

如果我需要覆盖scrollViewDidScroll:,如何?还是注意一些属性? 我的 NSTimer 有问题吗?

一些代码:

**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];

} 

【问题讨论】:

  • 你需要:collectionView.pagingEnabled = YES。并确保 collectionView.frame 在所有方向上都等于 collectionViewCell + inset。
  • @OnikIV : pagingEnabled 已设置。如果我不设置时有默认插入?
  • 您需要在此处添加一些代码,了解如何滚动并在滚动时为每个图像设置边界。
  • @SandeepAggarwal 谢谢你的建议!我已经粘贴了一些相关代码。
  • 如果不自己拖动滚动,单独使用定时器是否可以正常工作?

标签: ios objective-c uiscrollview uicollectionview uicollectionviewcell


【解决方案1】:

您能解释一下为什么要创建 100 个部分而不是一个包含 100 个项目的部分吗?无论如何,我看到 2 个错误: 1)您有全宽图片和“项目间空间”,但您在屏幕上没有该空间的位置(在您的情况下,它不是项目间空间,而是右侧部分插图或其他内容) 2)你有一个右边的部分插图,但你没有左边

因此,如果您将初始位置设置为第一个单元格并滑动,您将在屏幕上看到一个插入部分。在下一次滑动时,您将看到前一个单元格、插图和下一个单元格的一小部分...这样在 50 次滑动后您将看到不可预测的屏幕偏移。

我已经画了一些方法来解决你的问题(对不起我的 fotoshop 技能:D)。在图片中,黑色矩形是屏幕,红色 - 集合视图,绿色 - 单元格。 X 是单元格之间的空间。所以你需要增加collection view的宽度,将其向左放置,将左右部分的insets设置为这个空间的一半。

导致您将获得一个全屏宽度的图片,其中包含项目间的空间,您只能在滑动时看到。

编辑:有示例项目https://github.com/dimasv28/slider

【讨论】:

  • 我有点头晕。能否请您在我的代码中表达或给出一个简单的演示
  • 我不能,因为我不明白你的部分/单元格之间的确切空间是什么。你在故事板中设置它吗?如果您有 100 个部分,其中有 1 个单元格,则需要确保每个部分内没有任何空格,然后您可以设置相等的左右部分插图(我的图片上的 x/2)等。
  • 你看我是用纯代码创建的,没有使用storyboard。你能告诉我如何在代码中设置它吗?
  • 使用- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
  • 我没有在每个section里面设置空格~
【解决方案2】:

为什么不为此使用 UIPageViewController 呢?这似乎更适合您的问题。它旨在完成您想要做的事情。

【讨论】:

  • 我不熟悉 UIPageViewController。在那里,它是 tableView 的 headerView。如果我可以使用它?
  • UIPageViewController 是一个视图控制器,用于管理内容页面,您可以将其从一个滑动到下一个,或使用 iBooks 之类的页面卷曲过渡。 Apple 提供了一个名为 PhotoScroller 的示例程序来演示如何使用它。 (它做了很多其他你不需要的东西。)它曾经是从 UIPageViewController 上的文档链接的,但我再也找不到它了。不过,我确实通过谷歌搜索在 Apple 的网站上找到了它。
  • UIPageViewController 比集合视图更适合您的工作。
  • 如果我可以将它用作tableView的headerView?因为这里的collectionView是tableView的headerView,而不是controller。
  • 您可以将其用作表格视图的标题,但这可能不是最合适的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 2020-11-20
相关资源
最近更新 更多