Przez cały tydzień dręczyło mnie to, więc usiadłem dziś wieczorem i spróbowałem znaleźć rozwiązanie. Myślę, że potrzebujesz niestandardowego menedżera układu dla widoku kolekcji, który dynamicznie dostosowuje układ każdej komórki w miarę zmiany kolejności.
Poniższy kod w oczywisty sposób daje coś znacznie większego niż powyższy układ, ale zasadniczo osiąga pożądane zachowanie: w przypadku zmiany kolejności zachodzi natychmiastowe przejście do nowego układu, "natychmiast" bez żadnych wymaganych korekt tymczasowych.
Kluczem do wszystkiego jest funkcja didSet w zmiennej sourceData kontrolera widoku. Gdy wartość tej tablicy zostanie zmieniona (poprzez naciśnięcie przycisku sortowania - moje przybliżone przybliżenie do rozpoznawanego gestu), to automatycznie powoduje ponowne obliczenie wymaganych wymiarów komórki, co powoduje również wygaszenie układu i ponowne obliczenie oraz widok kolekcji w celu ponownego załadowania dane.
Jeśli masz jakiekolwiek pytania na ten temat, daj mi znać. Mam nadzieję, że to pomoże!
AKTUALIZACJA: OK, rozumiem, co próbujesz teraz zrobić, i myślę, że załączony zaktualizowany kod cię tam zawiedzie. Zamiast korzystać z wbudowanych metod interakcji, myślę, że jest to łatwiejsze, biorąc pod uwagę sposób, w jaki zaimplementowałem niestandardowy menedżer układu do korzystania z delegacji: gdy wybierak gestów panoramy wybierze komórkę, tworzymy widok podzapytania oparty na tym słowie, który porusza się wraz z gest. W tym samym czasie usuwamy słowo ze źródła danych i odświeżamy układ. Gdy użytkownik wybierze lokalizację, w której umieszcza słowo, odwracamy ten proces, nakazując delegatowi wstawienie słowa do źródła danych i odświeżenie układu. Jeśli użytkownik przeciągnie słowo poza widok kolekcji lub do niewłaściwej lokalizacji, słowo zostanie po prostu cofnięte tam, gdzie ono się zaczęło (użyj sprytnej techniki przechowywania oryginalnego indeksu jako znacznika etykiety).
Mam nadzieję, że ci pomogę!
[uprzejmości Tekst Wikipedia]
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
}
}
Niestety jeśli zrobiłem Sime błędów z językiem, jestem włoski – ale00