2016-09-25 64 views
9

Tüm Hücreler için Özel Boyutlu bir Koleksiyon Görünümünde hücreleri yeniden sıralamak istiyorum.
Koleksiyon Görünümü'nün her hücresinde bir kelime içeren bir etiket var.Özel Boyutlarla Toplama Görünüm Hücresini Yeniden Oluşturma Sorunları

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.installsStandardGestureForInteractiveMovement = false 
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(gesture:))) 
    self.collectionView?.addGestureRecognizer(panGesture) 

} 

func handlePanGesture(gesture: UIPanGestureRecognizer) { 
    switch gesture.state { 
    case UIGestureRecognizerState.began : 
     guard let selectedIndexPath = self.collectionView?.indexPathForItem(at: gesture.location(in: self.collectionView)) else { 
      break 
     } 
     collectionView?.beginInteractiveMovementForItem(at: selectedIndexPath) 
     print("Interactive movement began") 

    case UIGestureRecognizerState.changed : 
     collectionView?.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!)) 
     print("Interactive movement changed") 

    case UIGestureRecognizerState.ended : 
     collectionView?.endInteractiveMovement() 
     print("Interactive movement ended") 

    default: 
     collectionView?.cancelInteractiveMovement() 
     print("Interactive movement canceled") 
    } 
} 

override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { 

    // Swap values if sorce and destination 
    let change = textArray[sourceIndexPath.row] 


    textArray.remove(at: sourceIndexPath.row) 
    textArray.insert(change, at: destinationIndexPath.row) 

    // Reload data to recalculate dimensions for the cells 
    collectionView.reloadData() 
} 

görünümü aşağıdaki gibidir:: collection view

sorunu bu kodla Koleksiyon Görünümü yeniden düzenlemek

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 

    let word = textArray[indexPath.row] 

    let font = UIFont.systemFont(ofSize: 17) 
    let fontAttributes = [NSFontAttributeName: font] 
    var size = (word as NSString).size(attributes: fontAttributes) 
    size.width = size.width + 2 
    return size 
} 

:
Bu kodu bulunan her hücrenin boyutu ayarlamak Yeniden sıralama sırasında, hücreler bir indexPath'ta orijinal hücrenin boyutlarını korur, böylece yeniden düzenleme sırasında görünüm şöyle görünür: reordering Şu anda yeniden boyutlandırmanın sonunda yeniden yükleme yapmak için doğru boyutlarını yeniden hesaplamak için sorunu yeniden yükledim. Ayrıca, etkileşimli hareket sırasında hücreler için doğru boyutları nasıl düzenleyebilir ve özel boyutlu hücreleri yeniden düzenleyebilirim?

+0

Üzgünüm, – ale00

cevap

3

Bu, bütün hafta boyunca beni rahatsız ediyor, bu yüzden bir çözüm bulmaya çalışmak için bu akşam oturdum. İhtiyacınız olan şey, koleksiyon görünümü için, sipariş değiştikçe her hücrenin düzenini dinamik olarak ayarlayabilen özel bir düzen yöneticisi.

Aşağıdaki kod, yukarıdaki düzeninizden çok daha karmaşık bir şey üretir, ancak temel olarak istediğiniz davranışı gerçekleştirir: hücreler yeniden düzenlendiğinde yeni düzende önemli ölçüde hareket etmek, herhangi bir ara ayarlama gerektirmeden "anında" oluşur.

Bunun anahtarı, denetleyicinin sourceData değişkenindeki didSet işlevidir. Bu dizinin değeri değiştiğinde (sıralama düğmesine basmakla - hamilelik yaklaşımınızı jest tanımlayıcınıza), bu, otomatik olarak gerekli hücre boyutlarının yeniden hesaplanmasını tetikler ve bu da düzeni ve yeniden hesaplamayı ve toplama görünümünün yeniden yüklenmesini sağlamak için düzeni tetikler. veri.

Bunlardan herhangi biriyle ilgili sorularınız varsa, bildirin. Umarım yardımcı olur!

GÜNCELLEME: Tamam, şimdi ne yapmaya çalıştığını anlıyorum ve eklenmiş güncel kodun sizi oraya götürdüğünü düşünüyorum. Yerleşik etkileşim yöntemlerini kullanmak yerine, delegasyonu kullanmak için özel bir düzen yöneticisi uyguladığım şekilde daha kolay olduğunu düşünüyorum: pan jest tanıyıcı bir hücre seçtiğinde, bu sözcük ile hareket eden bir kelimeye dayalı bir alt görünüm oluşturuyoruz jest. Aynı zamanda arka planda, veri kaynağındaki kelimeyi kaldırır ve düzeni yenileriz. Kullanıcı sözcüğü yerleştirmek için bir yer seçtiğinde, bu süreci tersine çeviririz, böylece temsilci veri kaynağına bir sözcük eklemeyi ve düzeni yenilemeyi söyler. Kullanıcı sözcüğü koleksiyon görünümünün dışında veya geçerli olmayan bir konumdan sürüklerse, kelime basitçe başladığı yere geri döner (etiketin etiketi olarak orijinal dizinin saklanması için kurnaz tekniğini kullanın).

Bu size yardımcı olur umarım!

[Wikipedia'nın Metin nezaket] Ben dili ile Sime hatalar yaptıysanız

import UIKit 

class ViewController: UIViewController, bespokeCollectionViewControllerDelegate { 

    let sourceText : String = "So Midas, king of Lydia, swelled at first with pride when he found he could transform everything he touched to gold; but when he beheld his food grow rigid and his drink harden into golden ice then he understood that this gift was a bane and in his loathing for gold, cursed his prayer" 

    var sourceData : [String]! { 
     didSet { 
      refresh() 
     } 
    } 
    var sortedCVController : UICollectionViewController! 
    var sortedLayout : bespokeCollectionViewLayout! 
    var sortButton : UIButton! 
    var sortDirection : Int = 0 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     sortedLayout = bespokeCollectionViewLayout(contentWidth: view.frame.width - 200) 
     sourceData = { 
      let components = sourceText.components(separatedBy: " ") 
      return components 
     }() 

     sortedCVController = bespokeCollectionViewController(sourceData: sourceData, collectionViewLayout: sortedLayout, frame: CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: view.frame.width - 200, height: view.frame.height - 200))) 
     (sortedCVController as! bespokeCollectionViewController).delegate = self 
     sortedCVController.collectionView!.frame = CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: view.frame.width - 200, height: view.frame.height - 200)) 

     sortButton = { 
      let sB : UIButton = UIButton(frame: CGRect(origin: CGPoint(x: 25, y: 100), size: CGSize(width: 50, height: 50))) 
      sB.setTitle("Sort", for: .normal) 
      sB.setTitleColor(UIColor.black, for: .normal) 
      sB.addTarget(self, action: #selector(sort), for: .touchUpInside) 
      sB.layer.borderColor = UIColor.black.cgColor 
      sB.layer.borderWidth = 1.0 
      return sB 
     }() 

     view.addSubview(sortedCVController.collectionView!) 
     view.addSubview(sortButton) 
    } 

    func refresh() -> Void { 
     let dimensions : [CGSize] = { 
      var d : [CGSize] = [CGSize]() 
      let font = UIFont.systemFont(ofSize: 17) 
      let fontAttributes = [NSFontAttributeName : font] 
      for item in sourceData { 
       let stringSize = ((item + " ") as NSString).size(attributes: fontAttributes) 
       d.append(CGSize(width: stringSize.width, height: stringSize.height)) 
      } 
      return d 
     }() 

     if self.sortedLayout != nil { 
      sortedLayout.dimensions = dimensions 
      if let _ = sortedCVController { 
       (sortedCVController as! bespokeCollectionViewController).sourceData = sourceData 
      } 
      self.sortedLayout.cache.removeAll() 
      self.sortedLayout.prepare() 
      if let _ = self.sortedCVController { 

       self.sortedCVController.collectionView?.reloadData() 
      } 
     } 
    } 


    func sort() -> Void { 
     sourceData = sortDirection > 0 ? sourceData.sorted(by: { $0 > $1 }) : sourceData.sorted(by: { $0 < $1 }) 
     sortDirection = sortDirection + 1 > 1 ? 0 : 1 
    } 

    func didMoveWord(atIndex: Int) { 
     sourceData.remove(at: atIndex) 
    } 

    func didPlaceWord(word: String, atIndex: Int) { 
     print(atIndex) 
     if atIndex >= sourceData.count { 
      sourceData.append(word) 
     } 
     else 
     { 
      sourceData.insert(word, at: atIndex) 
     } 

    } 

    func pleaseRefresh() { 
     refresh() 
    } 

} 

protocol bespokeCollectionViewControllerDelegate { 
    func didMoveWord(atIndex: Int) -> Void 
    func didPlaceWord(word: String, atIndex: Int) -> Void 
    func pleaseRefresh() -> Void 
} 

class bespokeCollectionViewController : UICollectionViewController { 

    var sourceData : [String] 
    var movingLabel : UILabel! 
    var initialOffset : CGPoint! 
    var delegate : bespokeCollectionViewControllerDelegate! 

    init(sourceData: [String], collectionViewLayout: bespokeCollectionViewLayout, frame: CGRect) { 
     self.sourceData = sourceData 
     super.init(collectionViewLayout: collectionViewLayout) 

     self.collectionView = UICollectionView(frame: frame, collectionViewLayout: collectionViewLayout) 
     self.collectionView?.backgroundColor = UIColor.white 
     self.collectionView?.layer.borderColor = UIColor.black.cgColor 
     self.collectionView?.layer.borderWidth = 1.0 

     self.installsStandardGestureForInteractiveMovement = false 

     let pangesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(gesture:))) 
     self.collectionView?.addGestureRecognizer(pangesture) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    func handlePanGesture(gesture: UIPanGestureRecognizer) { 
     guard let _ = delegate else { return } 

     switch gesture.state { 
     case UIGestureRecognizerState.began: 
      guard let selectedIndexPath = self.collectionView?.indexPathForItem(at: gesture.location(in: self.collectionView)) else { break } 
      guard let selectedCell : UICollectionViewCell = self.collectionView?.cellForItem(at: selectedIndexPath) else { break } 
      initialOffset = gesture.location(in: selectedCell) 

      let index : Int = { 
       var i : Int = 0 
       for sectionCount in 0..<selectedIndexPath.section { 
        i += (self.collectionView?.numberOfItems(inSection: sectionCount))! 
       } 
       i += selectedIndexPath.row 
       return i 
      }() 


      movingLabel = { 
       let mL : UILabel = UILabel() 
       mL.font = UIFont.systemFont(ofSize: 17) 
       mL.frame = selectedCell.frame 
       mL.textColor = UIColor.black 
       mL.text = sourceData[index] 
       mL.layer.borderColor = UIColor.black.cgColor 
       mL.layer.borderWidth = 1.0 
       mL.backgroundColor = UIColor.white 
       mL.tag = index 
       return mL 
      }() 

      self.collectionView?.addSubview(movingLabel) 

      delegate.didMoveWord(atIndex: index) 
     case UIGestureRecognizerState.changed: 
      if let _ = movingLabel { 
       movingLabel.frame.origin = CGPoint(x: gesture.location(in: self.collectionView).x - initialOffset.x, y: gesture.location(in: self.collectionView).y - initialOffset.y) 
      } 

     case UIGestureRecognizerState.ended: 
      print("Interactive movement ended") 
      if let selectedIndexPath = self.collectionView?.indexPathForItem(at: gesture.location(in: self.collectionView)) { 
       guard let _ = movingLabel else { return } 

       let index : Int = { 
        var i : Int = 0 
        for sectionCount in 0..<selectedIndexPath.section { 
         i += (self.collectionView?.numberOfItems(inSection: sectionCount))! 
        } 
        i += selectedIndexPath.row 
        return i 
       }() 

       delegate.didPlaceWord(word: movingLabel.text!, atIndex: index) 
       UIView.animate(withDuration: 0.25, animations: { 
        self.movingLabel.alpha = 0 
        self.movingLabel.removeFromSuperview() 
        }, completion: { _ in 
         self.movingLabel = nil }) 
      } 
      else 
      { 
       if let _ = movingLabel { 
        delegate.didPlaceWord(word: movingLabel.text!, atIndex: movingLabel.tag) 
        UIView.animate(withDuration: 0.25, animations: { 
         self.movingLabel.alpha = 0 
         self.movingLabel.removeFromSuperview() 
        }, completion: { _ in 
         self.movingLabel = nil }) 
       } 
      } 

     default: 
      collectionView?.cancelInteractiveMovement() 
      print("Interactive movement canceled") 
     } 
    } 

    override func numberOfSections(in collectionView: UICollectionView) -> Int { 
     guard !(self.collectionViewLayout as! bespokeCollectionViewLayout).cache.isEmpty else { return 0 } 

     return (self.collectionViewLayout as! bespokeCollectionViewLayout).cache.last!.indexPath.section + 1 
    } 

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     guard !(self.collectionViewLayout as! bespokeCollectionViewLayout).cache.isEmpty else { return 0 } 

     var n : Int = 0 
     for element in (self.collectionViewLayout as! bespokeCollectionViewLayout).cache { 
      if element.indexPath.section == section { 
       if element.indexPath.row > n { 
        n = element.indexPath.row 
       } 
      } 
     } 
     print("Section \(section) has \(n) elements") 
     return n + 1 
    } 

    override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { 
     let change = sourceData[sourceIndexPath.row] 

     sourceData.remove(at: sourceIndexPath.row) 
     sourceData.insert(change, at: destinationIndexPath.row) 
    } 

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell") 

     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) 

     // Clean 
     for subview in cell.subviews { 
      subview.removeFromSuperview() 
     } 

     let label : UILabel = { 
      let l : UILabel = UILabel() 
      l.font = UIFont.systemFont(ofSize: 17) 
      l.frame = CGRect(origin: CGPoint.zero, size: cell.frame.size) 
      l.textColor = UIColor.black 

      let index : Int = { 
       var i : Int = 0 
       for sectionCount in 0..<indexPath.section { 
        i += (self.collectionView?.numberOfItems(inSection: sectionCount))! 
       } 
       i += indexPath.row 
       return i 
      }() 

      l.text = sourceData[index] 
      return l 
     }() 

     cell.addSubview(label) 

     return cell 
    } 

} 


class bespokeCollectionViewLayout : UICollectionViewLayout { 

    var cache : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]() 
    let contentWidth: CGFloat 
    var dimensions : [CGSize]! 

    init(contentWidth: CGFloat) { 
     self.contentWidth = contentWidth 

     super.init() 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func prepare() -> Void { 
     guard self.dimensions != nil else { return } 
     if cache.isEmpty { 
      var xOffset : CGFloat = 0 
      var yOffset : CGFloat = 0 

      var rowCount = 0 
      var wordCount : Int = 0 

      while wordCount < dimensions.count { 
       let nextRowCount : Int = { 
        var totalWidth : CGFloat = 0 
        var numberOfWordsInRow : Int = 0 

        while totalWidth < contentWidth && wordCount < dimensions.count { 
         if totalWidth + dimensions[wordCount].width >= contentWidth { 
          break 
         } 
         else 
         { 
          totalWidth += dimensions[wordCount].width 
          wordCount += 1 
          numberOfWordsInRow += 1 
         } 

        } 
        return numberOfWordsInRow 
       }() 

       var columnCount : Int = 0 
       for count in (wordCount - nextRowCount)..<wordCount { 
        let index : IndexPath = IndexPath(row: columnCount, section: rowCount) 
        let newAttribute : UICollectionViewLayoutAttributes = UICollectionViewLayoutAttributes(forCellWith: index) 
        let cellFrame : CGRect = CGRect(origin: CGPoint(x: xOffset, y: yOffset), size: dimensions[count]) 
        newAttribute.frame = cellFrame 
        cache.append(newAttribute) 

        xOffset += dimensions[count].width 
        columnCount += 1 
       } 

       xOffset = 0 
       yOffset += dimensions[0].height 

       rowCount += 1 

      } 
     } 
    } 

    override var collectionViewContentSize: CGSize { 
     guard !cache.isEmpty else { return CGSize(width: 100, height: 100) } 
     return CGSize(width: self.contentWidth, height: cache.last!.frame.maxY) 
    } 

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
     var layoutAttributes = [UICollectionViewLayoutAttributes]() 
     if cache.isEmpty { 
      self.prepare() 
     } 
     for attributes in cache { 
      if attributes.frame.intersects(rect) { 
       layoutAttributes.append(attributes) 
      } 
     } 
     return layoutAttributes 
    } 
} 
+0

çalışmanız için teşekkür ederiz italyanım, anlıyorum ve bu uygulamaya çalışacağız. – ale00

+0

@ ale00 sorununu güncellemeye devam edeceğim, bunun üzerinde çalışmaktan keyif aldım. Bunun nispeten karmaşık olduğunu takdir ediyorum, ancak bunu çalıştırırsanız ve kodla çalışırsanız mantıklı olmalıdır.Özel bir koleksiyon görünümü mizanpajı bu gibi durumlarda çok daha fazla kontrol olanağı buluyorum. – Sparky

+0

Kodu çalıştırdım ve iyi çalışıyor, ardından yeniden tanımlamayı jest tanıyıcı ile uygulamaya çalıştım, ancak hücreyi asıl satıra taşıyorsam, bir hücre kayboluyor ve onu uygulamanın çökmesi dışında taşıyorsam. İşte benim kodum şu: https://gist.github.com/ale00/a34c575e1d4f6f16774c68a921759d3b, değişiklikler hat 88'den başlıyor. Belki de yanlış şekilde yapıyorum. (İngilizce dil hataları için özür dilerim) – ale00