正文  软件开发 > 编程综合 >

自适应高度可移动瀑布流UIColle的封装

导语 我们知道iOS9之后苹果直接封装好了UICollectionView的item移动效果实现。但是这个方法只能移动比较规则的布局,如果做个自适应例子就知道,他会在移动时自动布局...

导语

我们知道iOS9之后苹果直接封装好了UICollectionView的item移动效果实现。但是这个方法只能移动比较规则的布局,如果做个自适应例子就知道,他会在移动时自动布局到系统默认计算的效果去移动(原谅我的表达。。)。 但是实际需要中移动的往往是不一样大小的Item。那么就需要自己去封装一个移动方法。 本例为一个自适应的可移动瀑布流效果。

效果如下

分析

1 首先是自适应,那么我们可以做一个数据model。存储的是image的url,尺寸和比例等。用于布局时的计算。

2 在瀑布流布局中,需要的是计算记录每一列当前最底部的Y值。然后将item插入最小那一列下面,即最短的那一列下面。 由于contSize必须在布局完成后才能获得,所以我们必须在prepareLayout中完成布局计算。然后在获取contentSize。contentSize的height即可由最长的那一列获得。

3 移动的实现其实很没意思必须依赖苹果本身的方法,不然我想要自己实现那样的动画效果会非常麻烦。 那么我们就自己在本身的moveItem方法上进行封装。来实现Item的移动。

使用方式

导入自定义FlowLayout即可,可选择实现其代理方法,有两个FlowLayout,一个是自定义布局的,另一个是做移动操作的。如果想对其他布局进行移动可自行修改布局的FlowLayout:

- (MDMoveAbleWaterFallMoveFlowLayout *)flowLayout{
    if (!_flowLayout) {
        _flowLayout = [[MDMoveAbleWaterFallMoveFlowLayout alloc]init];
        _flowLayout.maxHeight = 200.f;    //item最大高度
        _flowLayout.minHeight = 20.f;       //item最小高度
        _flowLayout.columnNum = 3;        //列数
        _flowLayout.minimumLineSpacing = 10.0f;
        _flowLayout.minimumInteritemSpacing = 10.0f;
        _flowLayout.sectionInset = UIEdgeInsetsMake(5, 0, 5, 0);
    }
    return _flowLayout;
}

主要讲一下移动

为了向iOS9的方法靠拢,我们按照类似的情形封装如下代理方法:

@protocol MDMoveAbleWaterFallMoveFlowLayoutDelegate<NSObject>
@optional
//能否移动,可针对某Item设置
- (BOOL)MDCollectionView:(UICollectionView )collectionView canMoveItemAtIndexPath:( NSIndexPath )indexPath;
//能否移动,可针对要移动的Item和目标Item设置
- (BOOL)MDCollectionView:(UICollectionView )collectionView canMoveItemFromIndexPath:(NSIndexPath )fromIndexPath toDestinationIndexPath:(NSIndexPath )destinationIndexPath; //开始移动时,可自行做一些操作,按实际需要 - (void)MDCollectionView:(UICollectionView )collectionView willBeginMoveItemAtIndexPath:(NSIndexPath )indexPath; //当Item移动完成时,可自行做一些操作,比如数据的调整 - (void)MDCollectionView:(UICollectionView )collectionView didMoveItemFromIndexPath:(NSIndexPath )sourceIndexPath toDestinationItemAtIndexPath:(NSIndexPath )destinationIndexPath;
@end

具体移动操作如下:

  1. 添加长按手势选取要移动的Item。 因为大小不一,那么尽量由选中的Item生成一个小图片来方便移动。

    2 如果允许移动,那么获取当前所在的IndexPath,然后将选中的Item移动到这里。

长按开始选取Item:

- (void)handleMove:(UIPanGestureRecognizer  *)sender{
    CGPoint location = [sender locationInView:self.collectionView];
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:{
            if (![self.collectionView indexPathForItemAtPoint:location]) {
                return;
            }
            _selectIndexPath = [self.collectionView indexPathForItemAtPoint:location];
            _selectCell = [self.collectionView cellForItemAtIndexPath:_selectIndexPath];
            if (_selectIndexPath) {
                _fakeImage = [[UIImageView alloc]initWithFrame:_selectCell.frame];
                [_fakeImage getFakeImageFromCell:_selectCell];
                [self.collectionView addSubview:_fakeImage];
                _fakeImage.layer.cornerRadius = 10.f;
                _fakeImage.layer.borderColor = [UIColor redColor].CGColor;
                _fakeImage.layer.borderWidth = 3.f;
                _fakeImage.layer.masksToBounds = YES;
                CGPoint center = _selectCell.center;
                CGSize size = _selectCell.frame.size;
                [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
                    [_fakeImage setFrame:CGRectMake(center.x - size.width/4, center.y - size.height/4, size.width/2, size.height/2)];
                } completion:^(BOOL finished) {
                }];
                _lastCenter = _selectCell.center;
            }
        }
            break;

当手指移动时开始判断是否要移动:

case UIGestureRecognizerStateChanged:{
            [_fakeImage setCenter:location];
            //开始移动
            if ( ![self.collectionView indexPathForItemAtPoint:location]) {
                return;
            }
            _destinationIndexPath = [self.collectionView indexPathForItemAtPoint:location];
            _destinationCell = [self.collectionView cellForItemAtIndexPath:_destinationIndexPath];
            if ([self.delegate respondsToSelector:@selector(MDCollectionView:canMoveItemAtIndexPath:)]) {
                if ([self.delegate respondsToSelector:@selector(MDCollectionView:canMoveItemFromIndexPath:toDestinationIndexPath:)]) {
                    if (![self.delegate MDCollectionView:self.collectionView canMoveItemFromIndexPath:_selectIndexPath toDestinationIndexPath:_destinationIndexPath]) {
                        _destinationIndexPath = _selectIndexPath;
                        _destinationCell = _selectCell;
                        return;
                    }
                }
                if ([self.delegate MDCollectionView:self.collectionView canMoveItemAtIndexPath:_selectIndexPath]) {
                    [self MoveItemFromIndexPath:_selectIndexPath toIndexPath:_destinationIndexPath];
                }
            }
            if((CGRectGetMinY(_fakeImage.frame) - self.collectionView.contentOffset.y) < 0.f ){
                [self ScrollWithDirection:MDScrollDirectionUp];
            }else if((self.collectionView.bounds.size.height + self.collectionView.contentOffset.y - CGRectGetMaxY(_fakeImage.frame)) < 0.f) {
                [self ScrollWithDirection:MDScrollDirectionDown];
            }
            _lastCenter = _fakeImage.center;
        }
            break;

移动操作:

- (void)MoveItemFromIndexPath:(NSIndexPath )fromIndexPath toIndexPath:(NSIndexPath )toIndexpath{
    NSIndexPath *sourceIndexPath = _selectIndexPath;
    if (fromIndexPath && toIndexpath && !([_selectIndexPath isEqual:toIndexpath])) {
        if (!_isBeginMove) {
            if ([self.delegate respondsToSelector:@selector(MDCollectionView:willBeginMoveItemAtIndexPath:)]) {
                [self.delegate MDCollectionView:self.collectionView willBeginMoveItemAtIndexPath:_selectIndexPath];
            }
        }
        [self.collectionView performBatchUpdates:^{
            _selectIndexPath = toIndexpath;
            [self.collectionView moveItemAtIndexPath:sourceIndexPath toIndexPath:toIndexpath];
        } completion:^(BOOL finished) {
            if ([self.delegate respondsToSelector:@selector(MDCollectionView:didMoveItemFromIndexPath:toDestinationItemAtIndexPath:)]) {
                [self.delegate MDCollectionView:self.collectionView didMoveItemFromIndexPath:_selectIndexPath toDestinationItemAtIndexPath:_destinationIndexPath];
            }
        }];
    }
}

手指松开完成移动:

case UIGestureRecognizerStateEnded:{
            [UIView animateWithDuration:.3f delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationCurveEaseInOut animations:^{
            } completion:^(BOOL finished) {
                _selectCell.hidden = NO;
                CGRect destinaFrme;
                if (_destinationCell) {
                    destinaFrme = _destinationCell.frame;
                }else{
                    destinaFrme = _selectCell.frame;
                }
                [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
                    [_fakeImage setFrame:destinaFrme];
                } completion:^(BOOL finished) {
                    [_fakeImage removeFromSuperview];
                }];
            }];
        }
            break;

来自:http://www.jianshu.com/p/8f290972f9f2