iOS의 기본 드래그 앤 드롭


93

사용자가 드래그 앤 드롭 할 수있는 차량이 주변을 돌아 다니는 뷰를 갖고 싶습니다. 이를위한 최고의 대규모 전략은 무엇이라고 생각하십니까? 차량을 나타내는보기 또는 더 큰보기에서 터치 이벤트를 얻는 것이 가장 좋습니까? 드래그 앤 드롭에 사용한 간단한 패러다임이 만족 스럽습니까? 다른 전략의 단점은 무엇입니까?


답변:


126

UIView배경 이미지와 많은 씬 이 있다고 가정하면 vehicles각각의 새 차량을 다음과 같이 정의 할 수 있습니다 UIButton(UIImageView도 작동 할 것임).

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];

그런 다음 UIControlEventTouchDragInside이벤트 에 응답하여 원하는 곳으로 차량을 이동할 수 있습니다 . 예 :

- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
    CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
    UIControl *control = sender;
    control.center = point;
}

전체 장면을 관리하는 것과 비교하여 개별 차량이 자체 드래그를 처리하는 것이 훨씬 쉽습니다.


위대하고 매우 간단 해 보입니다! 나는 이것을 시도 할 것이다.
Luke

10
이 전략으로 인해 사용자가 업데이트 된 애니메이션보다 빠르게 버튼을 드래그하면 드래그가 중단됩니까? 손가락이 상자 밖으로 나오면 imageMoved : withEvent : 호출 수신이 중지됩니다. 맞나요?
Tim

이미지 드래그가 중지되는지 어떻게 알 수 있습니까? 손가락이 튀어 나온 것을 어떻게 알 수 있습니까?
ymutlu

오호-이미지 또는 버튼의 드래그 "핸들"을 오프셋하여 오른쪽 상단 또는 왼쪽 상단 모서리로 드래그 할 수 있습니까?
LJ Wilson

나는 점점 예외를하려 할 때 - [drag_move_textViewController imageTouch : withEvent :] : 예를 0x4b4b1c0로 전송 인식 할 수없는 선택
iosDev

34

ohho의 답변 외에도 유사한 구현을 시도했지만 "빠른"드래그 및 드래그 센터링 문제가 없습니다.

버튼 초기화는 ...

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];

및 방법 구현 :

- (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;
}

나는 이것이 답을위한 완벽한 해결책이라고 말하지 않습니다. 그럼에도 불구하고 나는 이것이 드래그를위한 가장 쉬운 해결 책임을 발견했습니다.


2
예제 코드에서 UIControl * control = sender를 사용한 후에 정의합니다. 이전에 정의하지 않아야합니까?
Peter Johnson

@PeterJohnson : 사실이 경우에는 중요하지 않습니다. 당신은 :) 언급 한 라인 때문에이 변수에는 이전 사용은 없습니다
JakubKnejzlik

1
CGPoint pPrev = [t previousLocationInView : control]; CGPoint p = [t locationInView : control]; 앞의 두 줄은 모두 "control"을 가리키는 것처럼 보입니다.
Peter Johnson

오 이런! 어떻게 놓칠 수 있습니까? : -O ... 대답을 편집했습니다.
JakubKnejzlik 2012 년

나는 버튼 폼 인터페이스 빌더를 추가하고 일부 로그인을 위해 자동 레이아웃을 사용합니다. 버튼을 숨기고 다시 표시합니다.이 기능을 방지하는 방법은 원래 위치로 돌아갑니다.
Amr Angry

2

여러 다른 uiview간에 uiview를 드래그 / 드롭하려는 경우가있었습니다. 이 경우 모든 드롭 존과 모든 드래그 게이블 오브젝트가 포함 된 수퍼 뷰에서 팬 이벤트를 추적하는 최상의 솔루션을 찾았습니다. 실제 드래그 된 뷰에 이벤트 리스너를 추가하지 않은 주된 이유는 드래그 된 뷰에 대한 수퍼 뷰를 변경하자마자 진행중인 팬 이벤트를 잃었 기 때문입니다.

대신 단일 또는 다중 드롭 영역에서 사용할 수있는 다소 일반적인 드래그 드롭 솔루션을 구현했습니다.

여기에서 볼 수있는 간단한 예제를 만들었습니다. 다른 여러 uiview간에 드롭 uiviews를 드래그합니다.

다른 방향으로 가기로 결정했다면 uibutton 대신 uicontrol을 사용해보십시오. addTarget 메서드를 선언하고 확장하기가 훨씬 더 쉽습니다. 따라서 사용자 지정 상태와 동작을 제공합니다.


1

저는 실제로 차량 뷰 에서 드래그를 추적 합니다. 특별한 이유가없는 한 큰보기보다는 자체에서 입니다.

사용자가 항목을 화면에 끌어 놓아 놓을 수있는 경우가 있습니다. 이 경우에는 상위 뷰하위 뷰 를 모두 실험했습니다. 드래그 할 있는 . UIView에 몇 개의 "드래그 가능한"뷰를 추가하고 드래그 할 수있는 방법을 처리하면 코드가 더 깔끔하다는 것을 알았습니다. 부모 UIView에 대한 간단한 콜백을 사용하여 새 위치가 적합한 지 확인했습니다. 그래서 애니메이션으로 나타낼 수 있습니다.

갖는 상위 뷰 같아요 드래그 트랙 것은 좋은대로,하지만이 아닌 드래그 뷰를 추가 할 경우 그게 약간 더 혼란을 만드는 여전히 상호 작용 버튼 등 사용자와.


1
-(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");
}

1

오호의 답변이 잘 맞았습니다. 신속한 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
}


0

Swift 4의 경우 쉽고 쉬운 방법입니다. 😛

1 단계 : 스토리 보드에서 View Controller로 버튼을 연결합니다. 그리고 모든 기본 AutoLayout 제약 조건 설정

 @IBOutlet weak var cameraButton: UIButton!

2 단계 : viewDidLoad ()에서 버튼에 팬 제스처 추가

self.cameraButton.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(panGesture:))))

3 단계 :

panGestureHandler 추가

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

         let location = recognizer.location(in: view)
        cameraButton.center = location

    }

이제 버튼 동작

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

여기에 이미지 설명 입력

추가 결과보기 ☝️

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.