Chcę mieć widok, w którym poruszają się pojazdy, który użytkownik może również przeciągać i upuszczać. Jak myślisz, jaka jest najlepsza strategia na dużą skalę, aby to zrobić? Czy najlepiej jest odbierać zdarzenia dotykowe z widoków reprezentujących pojazdy, czy z większego widoku? Czy istnieje prosty paradygmat, którego używałeś do przeciągania i upuszczania, z którego jesteś zadowolony? Jakie są wady różnych strategii?
93
Odpowiedzi:
Załóżmy, że masz
UIView
scenę z obrazem tła i wielevehicles
, możesz zdefiniować każdy nowy pojazd jakoUIButton
(UIImageView prawdopodobnie też zadziała):UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button addTarget:self action:@selector(imageTouch:withEvent:) forControlEvents:UIControlEventTouchDown]; [button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside]; [button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal]; [self.view addSubview:button];
Następnie możesz przemieścić pojazd w dowolne miejsce, odpowiadając na
UIControlEventTouchDragInside
zdarzenie np:- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event { CGPoint point = [[[event allTouches] anyObject] locationInView:self.view]; UIControl *control = sender; control.center = point; }
Pojedynczy pojazd dużo łatwiej poradzi sobie z własnymi przeciągnięciami w porównaniu do zarządzania sceną jako całością.
źródło
Oprócz odpowiedzi Ohho próbowałem podobnej implementacji, ale bez problemu „szybkiego” przeciągania i centrowania do przeciągania.
Inicjalizacja przycisku to ...
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside]; [button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragOutside]; [button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal]; [self.view addSubview:button];
i wdrożenie metody:
- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event { UIControl *control = sender; UITouch *t = [[event allTouches] anyObject]; CGPoint pPrev = [t previousLocationInView:control]; CGPoint p = [t locationInView:control]; CGPoint center = control.center; center.x += p.x - pPrev.x; center.y += p.y - pPrev.y; control.center = center; }
Nie mówię, że to idealne rozwiązanie na odpowiedź. Niemniej jednak uznałem to za najłatwiejsze rozwiązanie do przeciągania.
źródło
Miałem przypadek, w którym chciałbym przeciągać / upuszczać uiviews między wieloma innymi uiviews. W takim przypadku znalazłem najlepsze rozwiązanie do śledzenia zdarzeń panoramy w superwidoku zawierającym wszystkie strefy upuszczania i wszystkie obiekty szczytu przeciągania. Głównym powodem, dla którego NIE dodawałem detektorów zdarzeń do rzeczywistych przeciągniętych widoków, było to, że straciłem trwające zdarzenia panoramowania, gdy tylko zmieniłem nadzór widoku po przeciągnięciu.
Zamiast tego zaimplementowałem raczej ogólne rozwiązanie typu „przeciągnij i upuść”, którego można używać w pojedynczych lub wielu strefach upuszczania.
Stworzyłem prosty przykład, który można zobaczyć tutaj: Przeciągnij upuść uiviews między wieloma innymi uiviews
Jeśli zdecydujesz się pójść w drugą stronę, spróbuj użyć uicontrol zamiast uibutton. Deklarują metody addTarget i są znacznie łatwiejsze do rozszerzenia - stąd dają niestandardowy stan i zachowanie.
źródło
W rzeczywistości śledziłbym przeciąganie samego widoku pojazdu , a nie dużego widoku - chyba że istnieje szczególny powód, aby tego nie robić.
W jednym przypadku, gdy pozwalam użytkownikowi umieszczać elementy, przeciągając je na ekranie. W takim przypadku eksperymentowałem zarówno z widokiem z góry, jak iz widokiem podrzędnym przeciągania . Zauważyłem, że kod jest bardziej przejrzysty, jeśli dodasz kilka widoków „do przeciągania” do UIView i poradzisz sobie, jak można je przeciągać. Użyłem prostego wywołania zwrotnego do nadrzędnego UIView, aby sprawdzić, czy nowa lokalizacja jest odpowiednia, czy nie - więc mogłem wskazać za pomocą animacji.
Wydaje mi się, że przeciąganie ścieżki widoku z góry jest równie dobre, ale to sprawia, że jest nieco bardziej bałagan, jeśli chcesz dodać nieprzeciągalne widoki, które nadal wchodzą w interakcję z użytkownikiem, takie jak przycisk.
źródło
-(void)funcAddGesture { // DRAG BUTTON UIPanGestureRecognizer *panGestureRecognizer; panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragButton:)]; panGestureRecognizer.cancelsTouchesInView = YES; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(50, 100, 60, 60); [button addTarget:self action:@selector(buttontapEvent) forControlEvents:UIControlEventPrimaryActionTriggered]; [button setImage:[UIImage imageNamed:@"button_normal.png"] forState:UIControlStateNormal]; [button addGestureRecognizer:panGestureRecognizer]; [self.view addSubview:button]; } - (void)dragButton:(UIPanGestureRecognizer *)recognizer { UIButton *button = (UIButton *)recognizer.view; CGPoint translation = [recognizer translationInView:button]; float xPosition = button.center.x; float yPosition = button.center.y; float buttonCenter = button.frame.size.height/2; if (xPosition < buttonCenter) xPosition = buttonCenter; else if (xPosition > self.view.frame.size.width - buttonCenter) xPosition = self.view.frame.size.width - buttonCenter; if (yPosition < buttonCenter) yPosition = buttonCenter; else if (yPosition > self.view.frame.size.height - buttonCenter) yPosition = self.view.frame.size.height - buttonCenter; button.center = CGPointMake(xPosition + translation.x, yPosition + translation.y); [recognizer setTranslation:CGPointZero inView:button]; } - (void)buttontapEvent { NSLog(@"buttontapEvent"); }
źródło
odpowiedź Ohho działała dobrze dla mnie. Jeśli potrzebujesz wersji Swift 2.x:
override func viewDidLoad() { let myButton = UIButton(type: .Custom) myButton.setImage(UIImage(named: "vehicle"), forState: .Normal) // drag support myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragInside) myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragOutside) } private func imageMoved(sender: AnyObject, event: UIEvent) { guard let control = sender as? UIControl else { return } guard let touches = event.allTouches() else { return } guard let touch = touches.first else { return } let prev = touch.previousLocationInView(control) let p = touch.locationInView(control) var center = control.center center.x += p.x - prev.x center.y += p.y - prev.y control.center = center }
źródło
Oto najlepszy sposób na przeciąganie i upuszczanie od iOS 11:
https://developer.apple.com/documentation/uikit/drag_and_drop/adopting_drag_and_drop_in_a_custom_view
źródło
Dla Swift 4 Łatwy i najłatwiejszy sposób. 😛
Krok 1: Połącz swój przycisk ze scenorysu, aby wyświetlić kontroler. I ustaw wszystkie podstawowe ograniczenia autoukładu
@IBOutlet weak var cameraButton: UIButton!
Krok 2: Dodaj gest Pan do przycisku W widokuDidLoad ()
self.cameraButton.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(panGesture:))))
Krok 3:
Dodaj panGestureHandler
@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) { let location = recognizer.location(in: view) cameraButton.center = location }
A teraz Twoja akcja przycisku
@IBAction func ButtonAction(_ sender: Any) { print("This is button Action") }
Dodaj Zobacz wynik ☝️
źródło