自適應高度可移動瀑布流UIColle的封裝

nzhf8334 8年前發布 | 7K 次閱讀 iOS開發 移動開發

導語

我們知道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</code></pre>

    具體移動操作如下:

    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

     

 本文由用戶 nzhf8334 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!