2013-04-21 10 views
11

Mam kilka UIViews, że użytkownik powinien być w stanie przeciągnąć kroplę &. Używam UIPanGestureRecognizer do zarządzania d akcja d & (patrz kod poniżej). Akcja d działa dobrze, ale kiedy zaczynam przeciągać kolejne UIView, ten, który właśnie upuściłem, przeskakuje z powrotem do swojej pierwotnej pozycji.iOS >> Przeciągnięty widok przeskakuje z powrotem do oryginalnej pozycji >> Automatyczny układ w połączeniu z UIPanGestureRecognizer Problem

- (void)handlePan:(UIPanGestureRecognizer *)recognizer { 

    CGPoint translation = [recognizer translationInView:self.view]; 

    switch (recognizer.state) { 
     case UIGestureRecognizerStateBegan: 
      for (UIView* checkView in dragAndDropImageViewsArray) { 
       if (checkView == recognizer.view) { 
        [checkView.superview bringSubviewToFront:checkView]; //this is done to make sure the currently dragged object is the top one 
       } 
      } 
      break; 

     case UIGestureRecognizerStateChanged: 
      recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y); 
      break; 

     case UIGestureRecognizerStateEnded: 
      NSLog(@"UIGestureRecognizerStateEnded"); 
      break; 

     default: 
      break; 
    } 

    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view]; 

} 

Próbowałem kilka rzeczy, które "sloved" problem, ale spowodował inne problemy:

  • Anuluj Auto-Layout: To całkowicie rozwiązuje go, ale teraz muszę zacząć obliczać i zarządzać lokalizacje obiektów i rozmiary dla różnych urządzeń i orientacji.
  • Użyj layer.zPosition zamiast bringSubviewToFront: sprawia to, że obiekty pojawiają się nad innymi obiektami, jednocześnie pozornie unikając "przeskoczenia", ale nie pozwala mi zmienić hierarchii między różnymi przeciągalnymi obiektami.

Zacząłem pogłębiać moją wiedzę na temat automatycznego układu, ale staje się to bardzo skomplikowane, gdy wydaje mi się, że to, czego szukam, powinno być bardzo proste; Widziałem wiele metod, które dotyczą wykonywania "ponownego automatycznego układania", ale nie mam pojęcia, jak z nimi pracować.

Czy istnieje tutaj proste rozwiązanie? jak wywołanie metody, która przesłania ograniczenia Auto-Layout IB i przedefiniowanie ich zgodnie z nową pozycją UIView?

Każda pomoc będzie bardzo ceniona.

Odpowiedz

10

Myślę, że jeśli używasz autolayout i chcesz zmienić pozycję widoku, musisz zaktualizować ograniczenia w widoku zamiast ręcznie ustawić środek widoku. Z opisu brzmi, jakbyś ustawiał centrum, ale kiedy aplikacja następnie rozłoży widoki (np. Przeciągasz kolejne), ustawia ponownie centrum na, czy autolayout mówi, że powinno być.

Nie jestem pewien, jak wygląda reszta aplikacji, ale możesz znaleźć widoki w pobliżu i dodać do niej ograniczenia, lub możesz po prostu zaktualizować ograniczenia widoku przeciągniętego i ustawić wiodące spacja i górna przestrzeń do podglądu ręcznie. Jeśli masz pod ręką zbiór, możesz również usunąć wszystkie ograniczenia, a następnie dodać je ponownie, ponieważ chcesz zachować dopełnienie między widokami.

Aby ustawić wiązania w kodzie, można usunąć ograniczenia dla przeniesionego widoku i ponownie je dodać, lub jeśli masz widok w IB, możesz przeciągnąć wiązania do kodu, aby utworzyć ujście. Spójrz na metody removeConstraints i addConstraints, aby zrobić to w kodzie.

Na koniec, jeśli działa w sposób, w jaki chcesz, bez automatycznego uruchamiania, możesz spróbować ustawić translatesAutoresizingMaskIntoConstraints = YES na przeniesionych widokach, ale pamiętaj, że mogą powodować konflikty w innych miejscach.

+0

Dzięki James - Czy możesz bardziej szczegółowo opisać, jak używać metod removeConstraints i addConstraints? Jak przechwycić tablicę "nowych ograniczeń", gdy widok został upuszczony na nową pozycję? Jeśli jest dobry tutorial na ten temat, do którego możesz mnie skierować - naprawdę bym to docenił. –

+1

Wypróbuj sekcję Zarządzanie ograniczeniami w dokumentacji UIView, aby dodać/usunąć. Jeśli chcesz, aby pozostało tam, gdzie wylądował, możesz spróbować ustawić górne dopełnienie i dopełnienie widoku. W przypadku ograniczeń wizualnych ustawienie widoku na 400 z góry i 200 z krawędzi wiodącej mogłoby wyglądać następująco: [Ograniczenia NSLayoutConstraintWithVisualFormat: @ "| - (= 200) - [movedViewView]": dane zerowe: widoki zerowe: @ {@ "movedView": rozpoznawanie.view}] [Ograniczenia NSLayoutConstraintWithVisualFormat: @ "V: | - (= 400) - [movedView]" opcje: zero dane: zero widoki: @ {@ "movedView": rozpoznawanie.view}] – James

6

To wszystko jest możliwe przy użyciu Kreatora interfejsu. Oto kod Kiedyś to zrobić:

@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonXConstraint; 
@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonYConstraint; 

Następnie podłączyć te IBOutlets do poziomego położenia Ograniczenie (X) i (Y pionowe Wiązanie pozycja) w konstruktorze Interface.Upewnij się, że więzy są podłączone do widoku podstawowego, a nie najbliższego widoku.

spięcie pan gest, a następnie użyć tego poniższy kod, aby przeciągnąć obiekt wokół:

- (IBAction)panPlayButton:(UIPanGestureRecognizer *)sender 
{ 
    if(sender.state == UIGestureRecognizerStateBegan){ 

    } else if(sender.state == UIGestureRecognizerStateChanged){ 
     CGPoint translation = [sender translationInView:self.view]; 

     //Update the constraint's constant 
     self.buttonXConstraint.constant += translation.x; 
     self.buttonYConstraint.constant += translation.y; 

     // Assign the frame's position only for checking it's fully on the screen 
     CGRect recognizerFrame = sender.view.frame; 
     recognizerFrame.origin.x = self.buttonXConstraint.constant; 
     recognizerFrame.origin.y = self.buttonYConstraint.constant; 

     // Check if UIImageView is completely inside its superView 
     if(!CGRectContainsRect(self.view.bounds, recognizerFrame)) { 
      if (self.buttonYConstraint.constant < CGRectGetMinY(self.view.bounds)) { 
       self.buttonYConstraint.constant = 0; 
      } else if (self.buttonYConstraint.constant + CGRectGetHeight(recognizerFrame) > CGRectGetHeight(self.view.bounds)) { 
       self.buttonYConstraint.constant = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(recognizerFrame); 
      } 

      if (self.buttonXConstraint.constant < CGRectGetMinX(self.view.bounds)) { 
       self.buttonXConstraint.constant = 0; 
      } else if (self.buttonXConstraint.constant + CGRectGetWidth(recognizerFrame) > CGRectGetWidth(self.view.bounds)) { 
       self.buttonXConstraint.constant = CGRectGetWidth(self.view.bounds) - CGRectGetWidth(recognizerFrame); 
      } 
     } 

     //Layout the View 
     [self.view layoutIfNeeded]; 
    } else if(sender.state == UIGestureRecognizerStateEnded){ 

    } 

    [sender setTranslation:CGPointMake(0, 0) inView:self.view]; 
} 

Dodałem kod w tam, aby sprawdzić ramkę i upewnij się, że nie dzieje się poza widokiem. Jeśli chcesz, aby obiekt był częściowo poza ekranem, możesz go wyjąć.

Zajęło mi to trochę czasu, aby zdać sobie sprawę, że to było użycie AutoLayout, który resetował widok, ale ograniczenia zrobią to, czego potrzebujesz tutaj!

+0

To działało dla mnie. Jednak sprawdzenie, czy pozycja ramki jest w pełni widoczna na ekranie, ogranicza ruch znacznie mniejszy niż granice super widoku. – Ali

Powiązane problemy