長按即可移動Cell的CollectionViewFlowLayout

在很多新聞客戶端中都有一個可以排序新聞類別的功能艘包。也用不少通過重寫UIScrollView來實現(xiàn)的统倒。這里主要說下通過UICollectionView怎么實現(xiàn),準確的說是通過CollectionViewFlowLayout來實現(xiàn)氛雪。

  • 什么是UICollectionView

UICollectionView是一種新的數(shù)據(jù)展示方式房匆,簡單來說可以把他理解成多列的UITableView(請一定注意這是UICollectionView的最最簡單的形式)。如果你用過iBooks的話报亩,可能你還對書架布局有一定印象:一個虛擬書架上放著你下載和購買的各類圖書浴鸿,整齊排列

  • UICollectionView結(jié)構(gòu)

    • Cells 用于展示內(nèi)容的主體,對于不同的cell可以指定不同尺寸和不同的內(nèi)容
    • Supplementary Views 追加視圖 如果你對UITableView比較熟悉的話弦追,可以理解為每個Section的Header或者Footer岳链,用來標記每個section的view
    • Decoration Views 裝飾視圖,這是每個section的背景
  • UICollectionViewLayout

UICollectionViewLayout是造就UICollectionView和UITableView最大不同的地方劲件。UICollectionViewLayout可以說是UICollectionView的大腦和中樞掸哑,它負責(zé)了將各個cell、Supplementary View和Decoration Views進行組織零远,為它們設(shè)定各自的屬性苗分,包括但不限于:

  • 位置
  • 尺寸
  • 透明度
  • 層級關(guān)系
  • 形狀
  • 等等等等…
  • Layout決定了UICollectionView是如何顯示在界面上的。在展示之前牵辣,一般需要生成合適的UICollectionViewLayout子類對象摔癣,并將其賦予CollectionView的collectionViewLayout屬性。

長按可移動Cell的UICollectionViewLayout

1、通過UICollectionViewLayout給UICollectionView添加長按事件:主要通過監(jiān)聽layout是否被添加到collectionView中择浊。

-(void)addCollectionCreatedObserver{
  [self addObserver:self forKeyPath:@"collectionView" options:NSKeyValueObservingOptionNew context:nil];
}

2戴卜、添加長按手勢

-(void)setupCollectionView{
  self.longGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlerLongPressGesture:)];
  self.longGestureRecognizer.delegate = self;
  [self.collectionView addGestureRecognizer:self.longGestureRecognizer];
}

3、處理手勢

-(void)handlerLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer{
  switch (gestureRecognizer.state) {
      case UIGestureRecognizerStateBegan:
          [self startLongPressGesture:gestureRecognizer];
          break;
      case UIGestureRecognizerStateChanged:
          [self moveLongPressGesture:gestureRecognizer];
          break;
      case UIGestureRecognizerStateCancelled:
      case UIGestureRecognizerStateEnded:
          [self endLongPressGesture:gestureRecognizer];
          break;
      default:
          break;
  }
}

4琢岩、處理手勢開始移動操作投剥,主要記錄移動的起點,對應(yīng)的Cell粘捎,并對當前Cell做快照薇缅,以便移動

  self.startPoint = [gestureRecognizer locationInView:self.collectionView];
  self.selectedMoveIndexPath = currentIndexPath;
  UICollectionViewCell *collectionViewCell = [self.collectionView cellForItemAtIndexPath:self.selectedMoveIndexPath];
  self.currentMoveView = [[UIView alloc] initWithFrame:collectionViewCell.frame];
  collectionViewCell.highlighted = YES;
  
  UIView *highlightedISnapshotView = [collectionViewCell MT_snapshotView];
  highlightedISnapshotView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  highlightedISnapshotView.alpha = 1.0;
  
  collectionViewCell.highlighted = NO;
  UIView *snapshotView = [collectionViewCell MT_snapshotView];
  snapshotView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  snapshotView.alpha = 0.0;
  
  [self.currentMoveView addSubview:snapshotView];
  [self.currentMoveView addSubview:highlightedISnapshotView];
  [self.collectionView addSubview:self.currentMoveView];
  self.currentViewCenter = self.currentMoveView.center;

5、處理手勢正在移動操作攒磨,主要記錄坐標變動泳桦,并移動快照視圖位置:

  CGPoint currentPoint = [gestureRecognizer locationInView:self.collectionView];
  self.currentPoint = CGPointMake(currentPoint.x - self.startPoint.x, currentPoint.y - self.startPoint.y);
  CGPoint viewCenter = self.currentMoveView.center = MT_CGPointAdd(self.currentViewCenter, self.currentPoint);

刷新CollectionView

  NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentMoveView.center];
  NSIndexPath *preIndexPath = self.selectedMoveIndexPath;
  if(newIndexPath == nil || [newIndexPath isEqual:preIndexPath]){
      return;
  }
  self.selectedMoveIndexPath = newIndexPath;
  
  if ([self.collectionView.dataSource respondsToSelector:@selector(collectionView:moveItemAtIndexPath:toIndexPath:)]) {
      [self.collectionView.dataSource collectionView:self.collectionView moveItemAtIndexPath:preIndexPath toIndexPath:newIndexPath];
  }
  __weak typeof(self) weakSelf = self;
  [self.collectionView performBatchUpdates:^{
      [weakSelf.collectionView deleteItemsAtIndexPaths:@[preIndexPath]];
      [weakSelf.collectionView insertItemsAtIndexPaths:@[newIndexPath]];
  } completion:^(BOOL finished) {
      
  }];

6、處理手勢結(jié)束移動娩缰。重置記錄:

NSIndexPath *currentIndexPath = self.selectedMoveIndexPath;
self.selectedMoveIndexPath = nil;
self.currentViewCenter = CGPointZero;
[self.currentMoveView removeFromSuperview];
self.currentMoveView = nil;
[self invalidateLayout];
      

7灸撰、重載layoutAttributesForElementsInRect:

  -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    NSArray *layoutAttributesForElementsInRect = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes *layoutAttributes in layoutAttributesForElementsInRect) {
        if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell){
            [self applyLayoutAttributes:layoutAttributes];
        }
    }
    return layoutAttributesForElementsInRect;
}

8、重載layoutAttributesForItemAtIndexPath:

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
    if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell){
        [self applyLayoutAttributes:layoutAttributes];
    }
    return layoutAttributes;
}

9拼坎、隱藏當前選擇的Cell

-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
  if([layoutAttributes.indexPath isEqual:self.selectedMoveIndexPath]){
      layoutAttributes.hidden = YES;
  }
}

移動Cell時可通知滾動UICollectionView

添加CADisplayLink浮毯,來主動觸發(fā)UICollectionView滾動。

1泰鸡、創(chuàng)建CADisplayLink

    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleScroll:)];
    
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

2债蓝、處理屏幕刷新事件:

    CGSize frameSize = self.collectionView.bounds.size;
    CGSize contentSize = self.collectionView.contentSize;
    CGPoint contentOffset = self.collectionView.contentOffset;
    UIEdgeInsets contentInset = self.collectionView.contentInset;
    // Important to have an integer `distance` as the `contentOffset` property automatically gets rounded
    // and it would diverge from the view's center resulting in a "cell is slipping away under finger"-bug.
    CGFloat distance = rint(self.scrollingSpeed * displayLink.duration);
    CGPoint translation = CGPointZero;
    ...
    self.collectionView.contentOffset = MT_CGPointAdd(contentOffset, translation);

效果圖:

Untitled.gif

完整源碼--》Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市盛龄,隨后出現(xiàn)的幾起案子饰迹,更是在濱河造成了極大的恐慌,老刑警劉巖余舶,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啊鸭,死亡現(xiàn)場離奇詭異,居然都是意外死亡匿值,警方通過查閱死者的電腦和手機赠制,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挟憔,“玉大人钟些,你說我怎么就攤上這事“硖罚” “怎么了厘唾?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長龙誊。 經(jīng)常有香客問我抚垃,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任鹤树,我火速辦了婚禮铣焊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罕伯。我一直安慰自己曲伊,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布追他。 她就那樣靜靜地躺著坟募,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邑狸。 梳的紋絲不亂的頭發(fā)上懈糯,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音单雾,去河邊找鬼赚哗。 笑死,一個胖子當著我的面吹牛硅堆,可吹牛的內(nèi)容都是我干的屿储。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼渐逃,長吁一口氣:“原來是場噩夢啊……” “哼够掠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起茄菊,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤疯潭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后买羞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袁勺,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡雹食,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年畜普,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片群叶。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡吃挑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出街立,到底是詐尸還是另有隱情舶衬,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布赎离,位于F島的核電站逛犹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虽画,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一舞蔽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧码撰,春花似錦渗柿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柴梆,卻和暖如春陨溅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轩性。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工声登, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揣苏。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓悯嗓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卸察。 傳聞我的和親對象是個殘疾皇子脯厨,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件坑质、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,024評論 4 62
  • 什么是UICollectionView合武? UICollectionView是一種新的數(shù)據(jù)展示方式,簡單來說可以把他...
    凌峰Mical閱讀 43,196評論 11 201
  • 最近將 UICollectionView 進行了一個全面的學(xué)習(xí)及總結(jié)涡扼,參考了網(wǎng)上大量的文章稼跳,把官方文檔進行了大概翻...
    varlarzh閱讀 21,346評論 3 94
  • 地上的劍還在錚鳴, 殘陽如血吃沪,紅了雙眼汤善, 聽山風(fēng)四蕩,散了這一世英明票彪。 從來無休離愁恨愛红淡, 焚心流淚,終究無奈降铸, ...
    小王爺小王爺閱讀 240評論 0 1
  • 1.過濾器創(chuàng)建 了解過濾器常見配置含義 filter-mapping標簽里面還有許多參數(shù)在旱,可以參考學(xué)習(xí)博客特別注意...
    丁白一閱讀 233評論 0 0