登录 立即注册
金钱:

Code4App-iOS开发-iOS 开源代码库-iOS代码实例搜索-iOS特效示例-iOS代码例子下载-Code4App.com

可横向排列滑动的collectionview

[复制链接]
来自: shengpeng0225 分类: iOS精品源码 上传时间: 2016-6-20 10:18:55

项目介绍:

UICollectionViewFlowLayout 流式布局我们常用,但他不支持横向排列并横向滑动,我们要求的是这样的效果

要实现这样的效果,我们只有自定义布局,自己设置cell的排列逻辑,笔者试过使用iOS 9的重排API,发现你如果重写layout,底层重排逻辑你没法重写,你也不知道UIKit工程师是怎样写的,所以采用完全自定义Collectionview,这里采用XWDragCellCollectionView,逻辑都是一个思路,大家自己写也可以,稍作修改


1.首先我们需要建立一个layout类继承自UICollectionViewLayout,为什么不继承自UICollectionViewFlowLayout,因为UICollectionViewFlowLayout已经写好了逻辑,我们不清楚他是怎么写的,避免出问题,还是完全自定义

[Objective-C] 查看源文件 复制代码
#import <UIKit/UIKit.h>

@interface PagingCollectionViewLayout : UICollectionViewLayout

@property (nonatomic) CGFloat minimumLineSpacing; //行间距

@property (nonatomic) CGFloat minimumInteritemSpacing; //item间距

@property (nonatomic) CGSize itemSize; //item大小

@property (nonatomic) UIEdgeInsets sectionInset;

- (instancetype)init;

@end



2.在prepareLayout中计算行间距列间距,这个方法是每次要布局时都会调用,你可以在这里面设置默认参数

[Objective-C] 查看源文件 复制代码
- (void)prepareLayout
{
    [super prepareLayout]; //需调用父类方法

    self.itemSize = CGSizeMake(70, 85);
    self.sectionInset = UIEdgeInsetsMake(5, 10, 5, 10);
    self.minimumLineSpacing = 1;
    self.minimumInteritemSpacing = 1;


    CGFloat itemWidth = self.itemSize.width;
    CGFloat itemHeight = self.itemSize.height;

    CGFloat width = self.collectionView.frame.size.width;
    CGFloat height = self.collectionView.frame.size.height;
    //计算真实item间距
    CGFloat contentWidth = (width - self.sectionInset.left - self.sectionInset.right);
    if (contentWidth >= (2*itemWidth+self.minimumInteritemSpacing)) { //如果列数大于2行
        int m = (contentWidth-itemWidth)/(itemWidth+self.minimumInteritemSpacing);
        _line = m+1;
        int n = (int)(contentWidth-itemWidth)%(int)(itemWidth+self.minimumInteritemSpacing);
        if (n > 0) {
            double offset = ((contentWidth-itemWidth) - m*(itemWidth+self.minimumInteritemSpacing))/m;
            itemSpacing = self.minimumInteritemSpacing + offset;
        }else if (n == 0){
            itemSpacing = self.minimumInteritemSpacing;
        }
    }else{ //如果列数为一行
        itemSpacing = 0;
    }
    //计算行间距
    CGFloat contentHeight = (height - self.sectionInset.top - self.sectionInset.bottom);
    if (contentHeight >= (2*itemHeight+self.minimumLineSpacing)) { //如果行数大于2行
        int m = (contentHeight-itemHeight)/(itemHeight+self.minimumLineSpacing);
        _row = m+1;
        int n = (int)(contentHeight-itemHeight)%(int)(itemHeight+self.minimumLineSpacing);
        if (n > 0) {
            double offset = ((contentHeight-itemHeight) - m*(itemHeight+self.minimumLineSpacing))/m;
            lineSpacing = self.minimumLineSpacing + offset;
        }else if (n == 0){
            lineSpacing = self.minimumInteritemSpacing;
        }
    }else{ //如果行数数为一行
        lineSpacing = 0;
    }

    int itemNumber = 0;

    itemNumber = itemNumber + (int)[self.collectionView numberOfItemsInSection:0];

    pageNumber = (itemNumber - 1)/(_row*_line) + 1;

}

- (BOOL)ShouldinvalidateLayoutForBoundsChange:(CGRect)newBounds{
    return YES;
}




3.重写layoutAttributesForItemAtIndexPath:方法,这个方法返回的是cell的attribute,意思是cell的属性信息,包括位置大小形变等等。你可以在这里自定义cell的排序算法,随便怎么排列都行,但要有规律,不然重排会出问题。

[Objective-C] 查看源文件 复制代码
static long  pageNumber = 1;

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];


    CGRect frame;
    frame.size = self.itemSize;
    //下面计算每个cell的frame   可以自己定义
    long number = _row * _line;
//    printf("%ld\n",number);
    long m = 0;  //初始化 m p
    long p = 0;
    if (indexPath.item >= number) {
//        NSLog(@"indexpath.item:%ld",indexPath.item);
        p = indexPath.item/number;  //计算页数不同时的左间距
//        if ((p+1) > pageNumber) { //计算显示的页数
//            pageNumber = p+1;
//            
//        }
//        NSLog(@"%ld",p);
        m = (indexPath.item%number)/_line;
    }else{
        m = indexPath.item/_line;
    }

    long n = indexPath.item%_line;
    frame.origin = CGPointMake(n*self.itemSize.width+(n)*itemSpacing+self.sectionInset.left+(indexPath.section+p)*self.collectionView.frame.size.width,m*self.itemSize.height + (m)*lineSpacing+self.sectionInset.top);

//    printf("%d(%f,%f)\n",indexPath.item,frame.origin.x,frame.origin.y);
    attribute.frame = frame;
    return attribute;
}




4.重写layoutAttributesForElementsInRect: 这个方法返回可见范围内的全部cell的attribute,cell的实时属性是由这个方法给的,意思就是说,例如你想cell移到屏幕中央时变大,就在这里写,然后替换原数组的attribute,返回array就行了。

[Objective-C] 查看源文件 复制代码
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{

    NSMutableArray *tmpAttributes = [NSMutableArray new];
    for (int j = 0; j < self.collectionView.numberOfSections; j ++) {
        NSInteger count = [self.collectionView numberOfItemsInSection:j];
        for (NSInteger i = 0; i < count; i++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:j];
            [tmpAttributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    }
    self.attributes = tmpAttributes;


    return self.attributes;



}



5.此外还有cell的对准方格方法

[Objective-C] 查看源文件 复制代码
- (CGPoint)targetContentOffsetForProposedContentOffset: (CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity //自动对齐到网格
{
    //proposedContentOffset是没有对齐到网格时本来应该停下的位置
    CGFloat offsetY = MAXFLOAT;
    CGFloat offsetX = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + self.itemSize.width/2;
    CGFloat verticalCenter = proposedContentOffset.y + self.itemSize.height/2;
    CGRect targetRect = CGRectMake(0, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
    NSArray* array = [super layoutAttributesForElementsInRect:targetRect];

    //对当前屏幕中的UICollectionViewLayoutAttributes逐个与屏幕中心进行比较,找出最接近中心的一个
    CGPoint offPoint = proposedContentOffset;
    for (UICollectionViewLayoutAttributes* layoutAttributes in array) {
        CGFloat itemHorizontalCenter = layoutAttributes.center.x;
        CGFloat itemVerticalCenter = layoutAttributes.center.y;
        if (ABS(itemHorizontalCenter - horizontalCenter) && (ABS(offsetX)>ABS(itemHorizontalCenter - horizontalCenter))) {
            offsetX = itemHorizontalCenter - horizontalCenter;
            offPoint = CGPointMake(itemHorizontalCenter, itemVerticalCenter);
        }
        if (ABS(itemVerticalCenter - verticalCenter) && (ABS(offsetY)>ABS(itemVerticalCenter - verticalCenter))) {
            offsetY = itemHorizontalCenter - horizontalCenter;
            offPoint = CGPointMake(itemHorizontalCenter, itemVerticalCenter);
        }
    }
    return offPoint;
}



自定义layout后,我们需要建立一个collectionview,并使用这个layout,由于重排要我们自己定义,所以在collectionview中添加长按手势,用于拖动item并重排,重排逻辑在手势响应时间中写。

在自定义collectionview的.m文件中写:

[Objective-C] 查看源文件 复制代码
/**
 *  添加一个自定义的滑动手势
 */
- (void)xwp_addGesture{
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(xwp_longPressed:)];

    longPress.minimumPressDuration = _minimumPressDuration; //最小长按时间
    _longPressGesture = longPress;
    [self addGestureRecognizer:longPress];

}


/**
 *  监听手势的改变
 */
- (void)xwp_longPressed:(UILongPressGestureRecognizer *)longPressGesture{
    if (longPressGesture.state == UIGestureRecognizerStateBegan) {
        [self xwp_gestureBegan:longPressGesture]; //长按开始,隐藏cell并截图,添加截图UIView

    }
    if (longPressGesture.state == UIGestureRecognizerStateChanged) {
        [self xwp_gestureChange:longPressGesture];//处理重排逻辑,数据处理,界面处理
    }
    if (longPressGesture.state == UIGestureRecognizerStateCancelled ||
        longPressGesture.state == UIGestureRecognizerStateEnded){
        [self xwp_gestureEndOrCancle:longPressGesture];//结束处理
    }
}


代码下载: (托管地址


相关源码推荐:

我来说两句
*滑动验证:
所有评论(140)
wang_JJ_lei 2016-6-20 11:46:01
淡定,淡定,淡定……
回复
_memorize 2016-6-20 11:47:26
强烈支持楼主ing……
回复
wang_JJ_lei 2016-6-20 11:50:43
学习学习!
回复
_memorize 2016-6-20 11:57:28
楼主用心了,内容非常精彩。
回复
白色的黑豹 2016-6-20 13:42:18
学习学习!
回复
qw123qw 2016-6-20 15:31:53
楼主威武啊,Code4App有你更给力!
回复
shengpeng0225 2016-6-20 17:55:47
我只是路过打酱油的。
回复
shengpeng0225 2016-6-20 17:56:56
会不断更新完善,互相学习
回复
shengpeng0225 2016-6-20 17:57:18
我只是路过打酱油的。
回复
提取码:  下载次数:178 状态:已购或VIP 售价:0(原价:10)金钱 下载权限:初级码农 
6875 1 178
联系我们
首页/微信公众账号投稿

帖子代码编辑/版权问题

QQ:435399051,742864542

如何获得代码达人称号?

代码贡献英雄榜
用户名 下载数
通过邮件订阅最新 Code4App 信息
上一条 /4 下一条
联系我们
关闭
合作电话:
13802416937
Email:
435399051@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|Github|申请友链|手机版|Code4App ( 粤ICP备15117877号-1 )

快速回复 返回顶部 返回列表
博聚网