2016-08-06 13 views
21

Próbuję replikować bezstykowa aby usunąć funkcję jak w tableview mail. Tylko tym razem potrzebuję go zbudować na kolekcji, ale mam trochę problemów. To pozioma lista przewijania z przesunięciem do usunięcia. Już uruchomiłem przesunięcie, ale mam problem z ustaleniem, w jaki sposób ustawić przesunięcie, aby usunąć/dotknąć, aby usunąć lub zignorować funkcję.Swipe usunąć na CollectionView

To wygląda następująco: Delete Image

Więc używam następujący CollectionView:

func buildCollectionView() { 
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() 
    layout.scrollDirection = .horizontal 
    layout.minimumInteritemSpacing = 0; 
    layout.minimumLineSpacing = 4; 

    collectionView = UICollectionView(frame: CGRect(x: 0, y: screenSize.midY - 120, width: screenSize.width, height: 180), collectionViewLayout: layout) 

    collectionView.dataSource = self 
    collectionView.delegate = self 
    collectionView.register(VideoCell.self, forCellWithReuseIdentifier: "videoCell") 
    collectionView.showsHorizontalScrollIndicator = false 
    collectionView.showsVerticalScrollIndicator = false 
    collectionView.contentInset = UIEdgeInsetsMake(0, 20, 0, 30) 
    collectionView.backgroundColor = UIColor.white() 
    collectionView.alpha = 0.0 


    //can swipe cells outside collectionview region 
    collectionView.layer.masksToBounds = false 


    swipeUpRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.deleteCell)) 
    swipeUpRecognizer.delegate = self 

    collectionView.addGestureRecognizer(swipeUpRecognizer) 
    collectionView.isUserInteractionEnabled = true 
} 

Mam zwyczaj videocell zawiera jeden obraz, a poniżej znajduje się przycisk Usuń. Więc jeśli przesuniesz obraz w górę, pojawi się przycisk kasowania. Nie wiem, czy to jest właściwy sposób, w jaki to zrobić:

class VideoCell : UICollectionViewCell { 
var deleteView: UIButton! 
var imageView: UIImageView! 

override init(frame: CGRect) { 
    super.init(frame: frame) 

    deleteView = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)) 
    deleteView.contentMode = UIViewContentMode.scaleAspectFit 
    contentView.addSubview(deleteView) 

    imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)) 
    imageView.contentMode = UIViewContentMode.scaleAspectFit 
    contentView.addSubview(imageView) 


} 

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

i używam następującą logiką:

func deleteCell(sender: UIPanGestureRecognizer) { 
    let tapLocation = sender.location(in: self.collectionView) 
    let indexPath = self.collectionView.indexPathForItem(at: tapLocation) 

    if velocity.y < 0 { 
     //detect if there is a swipe up and detect it's distance. If the distance is far enough we snap the cells Imageview to the top otherwise we drop it back down. This works fine already. 
    } 
} 

Ale problem zaczyna się tam. Gdy moja komórka znajduje się poza granicami zbierania, nie mam już do niej dostępu. Nadal chcę go przesunąć, aby go usunąć. Mogę to zrobić tylko przesuwając przycisk "Usuń", ale chcę, aby widok powyżej niego był przesuwany. Lub jeśli dotknę obrazu poza widokiem kolekcji, powinien on wrócić do linii i nie usuwać jej.

Gdybym zwiększenie granic CollectionView mogę uniknąć tego problemu, ale nie mogę też przesunąć palcem, aby usunąć na zewnątrz komórki widocznego wzrostu. Jest to spowodowane przez tapLocation, która znajduje się wewnątrz widoku kolekcji i wykrywa wskaźnik indexPath. Coś, czego nie chcę. Chcę przesunąć palcem tylko do pracy w komórce kolekcji.

także przycisk, a obraz kolidować ze sobą, bo nie mogę ich rozróżnić. Obaj są w tej samej komórce, dlatego zastanawiam się, czy powinienem mieć przycisk usuwania w komórce. Lub gdzie powinienem umieścić to inaczej? Mogłabym też zrobić dwa przyciski i wyłączyć interakcję użytkownika w zależności od stanu, ale nie jestem pewna, jak to się skończy.

Odpowiedz

3

Dla własnej ciekawości próbowałem stworzyć kopię tego, co próbujesz zrobić, i sprawiło, że działa jakoś dobrze. Różni się on od twojego w sposobie, w jaki ustawiam gesty machnięcia, ponieważ nie używałem patelni, ale powiedziałeś, że masz już tę część i nie poświęcałeś jej zbyt wiele czasu.Pan jest oczywiście bardziej solidnym rozwiązaniem, aby uczynić go interaktywnym, ale wymaga nieco więcej czasu, aby go obliczyć, ale jego efekt i obsługa nie powinny różnić się od mojego przykładu.

Aby rozwiązać ten problem nie jest w stanie przesunąć na zewnątrz komórki postanowiłem sprawdzić, czy punkt był w przeciągnął rect, która jest dwukrotnie wysokość nie przeciągnął rect tak:

  let cellFrame = activeCell.frame 
      let rect = CGRectMake(cellFrame.origin.x, cellFrame.origin.y - cellFrame.height, cellFrame.width, cellFrame.height*2) 
      if CGRectContainsPoint(rect, point) { 
       // If swipe point is in the cell delete it 

       let indexPath = myView.indexPathForCell(activeCell) 
       cats.removeAtIndex(indexPath!.row) 
       myView.deleteItemsAtIndexPaths([indexPath!]) 

      } 

Stworzyłem demonstrację z komentarzami: https://github.com/imbue11235/swipeToDeleteCell

Mam nadzieję, że pomoże ci to w każdym razie!

+0

Jestem z pewnością zainteresowany twoim rozwiązaniem. Czy mógłbyś przekazać zaktualizowaną wersję githubowi, ponieważ obecnie otrzymuję pusty projekt! – Wouter125

+0

O tak, jasne, to błąd, zawstydzający. Jest teraz aktualizowany! – Imbue

+0

Działa jak urok. Było dokładnie to, czego szukałem. Już przepisałem to dla mojego pangesture, ale faktycznie szukałem jak powiększyć obszar komórki :) – Wouter125

8

Jeśli chcesz, aby wykrywacz gestów kontynuował nagrywanie, gdy znajdują się poza ich widokiem kolekcji, musisz dołączyć go do nadrzędnego widoku kolekcji, więc jest on ograniczony do pełnego obszaru, w którym użytkownik może trzepnąć.

To oznacza, że ​​otrzymasz swipes dla rzeczy spoza widoku kolekcji, ale możesz z łatwością zignorować te, używając dowolnej liczby technik.

Aby zarejestrować usuwać krany przycisk, musisz zadzwonić addTarget: Działanie: forControlEvents: przycisk

chciałbym zachować komórkę, jak masz go z obrazem i przycisku razem. O wiele łatwiej będzie nim zarządzać i należą do siebie.

Aby zarządzać przenoszeniem obrazu w górę iw dół, chciałbym sprawdzić użycie transformacji lub NSLayoutConstraint. Następnie wystarczy ustawić jedną wartość, aby przesunąć ją w górę i w dół zsynchronizowaną z przesunięciem użytkownika. Bez problemów z ramkami.

+0

Pozwól mi spłynąć każdego alinea. Jeśli dołączę go do widoku rodzica, tak jak powiedziałeś, dostanę wszędzie. Problem polega na tym, że gdy moja komórka znajdzie się poza moim zbiorem, moja ścieżka indeksu w funkcji deletecell stanie się zerowa i nie będę już mógł przeciągać komórki. Zwiększenie rozmiaru kolekcji będzie możliwe, ale pozwoli także użytkownikom przeciągać komórki, nawet jeśli nie dotykają one samego obrazu. Usuń akcję można łatwo naprawić. Jedynym problemem jest to, że widok obrazu ma inną akcję niż przycisk usuwania. Jak połączyć te dwie akcje, gdy obie są widoczne? – Wouter125

+0

Nie jestem pewien, wyobrażałbym sobie, że wyłączenie klipów z kolekcji klipów na granicach pozwoliłoby na przekształcenie widoku obrazu poza nim. 'myCollectionView.clipsToBounds = false' – Michael

+0

Nie, to nie wystarczy, ponieważ widok przesunie tylko zdarzenia" dotyku "do subskrybentów (komórek wewnątrz widoku kolekcji), jeśli znajdują się one w jego granicach. Zwiększenie granic zadziała, ale nie tego chcę. Jakieś inne sugestie? Mogłem zastąpić metodę pointInsuide, ale to jest coś, czego nie chcę, ponieważ myślę, że nie zwróci mojej ścieżki indeksowej. – Wouter125

Powiązane problemy