How would I go about implementing dragging and dropping a UIView from UIPopoverController
into the back UIView
.
This is the functionality that Pages provide in their insert media popover, where you can drag a shape out from the UIPopoverController
and drop it into the main document.
I am actually confused with the pan UIGestureRecognizers
and where they will be implemented.
Thanks,
Umer
According to the documentation on UIPopoverController, when the popover is presented, it is presented on a special "window". Because of this, simply adding a subview to the popover view controller's content view controller is not sufficient to be able to drag a view outside of the popover view controller's view.
The easiest solution here is to create your own window, add your drag-able view to the window when dragging occurs. Make the window visible for the duration of the drag/drop, and then release your window when complete.
As mentioned above, gesture recognizers (GR) are best suited for Drag/Drop functionality. Once the GR's state has changed to "Began" the GR will control all touches until the "Ended" or "Cancelled" state is achieved which makes it ideal for dragging views between view controllers as well as windows :)
Example:
@interface MySplitViewController : UISplitViewController {
UIView *dragView;
UIWindow *dragWindow;
}
Implementation: NOTE we do not need to call "makeKeyAndVisible" on our window. We just need to set its "Hidden" property
From Apple in regards to the makeKeyAndVisible method: // convenience. most apps call this to show the main window and also make it key. otherwise use view hidden property
-(void)dragBegan{
self.dragWindow = [[UIWindow alloc] initWithFrame:self.view.window.frame];
[self.dragWindow addSubview:self.dragView];
[self.dragWindow setHidden:NO];
}
Here we handle the Gesture Recognizer's "Ended" or "Cancelled" state. NOTE: It is important to remove the window when the Drag/Drop is complete or you will lose user interactiveness with the views below.
-(void)dragEnded{
[self.dragView removeFromSuperview];
[self.dragWindow setHidden:YES];
[self.dragWindow release];
[self.view addSubview:self.dragView];
}
You have to deal with two view controllers one that's in the background called mainController one that presented using a UIPopoverViewController
called popoverController. Your popoverController could add a UIPanGestureRecognizer
to the views, that the user can drag. The action target of the gestureRecognizer could be a method on the popoverController.
Once the user starts a dragging operation your action method is called with the gestureRecognizer as an argument, were the state of the gestureRecognizer is UIGestureRecognizerStateBegan
. You could than save the current frame of the view somewere to be able to animate it back, when the dropping fails. It might be necessary to move the view to an other superview (the window for example), because I'm not sure if UIPopoverViewController clipsToBounds its view.
As the user draggs, your action method is called over and over with the gestureRecognizer in the state UIGestureRecognizerStateChanged
. Use the translationInView:
method on UIPanGestureRecognizer
to determine how much the user dragged and update the dragged views center/frame/transform accordingly.
Once the user lifts his finger the action method is called for a last time with the gestureRecoginzers state set to UIGestureRecognizerStateEnded
. Now it's time to find out if the drag was successful. For example the popoverController could ask the mainController via delegation if there's a drop target under the views current position, if so the mainController can take action, else the popoverController would animate the dragged view back to were it came from, and add it back as a subview to it's view.
I hope this is somehow comprehensible and helpful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With