IOS: drag and drop imageview from a scrollview to a view [duplicate] - ios

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to drag an uiimage from scrollview to another uiimageview in iphone sdk
In my iPad I have a view and inside it, on the left, I have a scrollview with 10 imageViews; so I should drag and drop these images from scrollview to my big subview; how can I do it?

I did something like what you are describing once. I remember to pull it off I created a new UIGestureRecgonizer that I dubbed UIDownwardDragGestureRecognizer. I think I then iterated through the scrollviews gesture recognizers to require them to wait for the UIDownwardGestureRecognizer to fail like:
UIDownwardDragGestureRecognizer *downwardGesture = [UIDownwardGestureRecognizer alloc] initWithTarget:self action:#selector(downwardGestureChanged:)];
[myScrollview addGestureRecognizer:downwardGesture];
for (UIGestureRecognizer *gestureRecognizer in myScrollview.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:myDownwardGesture];
}
Once you have this setup, you should be able to do something like:
- (void) downwardGestureChanged:(UIDownwardDragGestureRecognizer*)gesture
{
CGPoint point = [gesture locationInView:myScrollView];
if (gesture.state == UIGestureRecognizerStateBegan)
{
UIView *draggedView = [myScrollView hitTest:point withEvent:nil];
if ([draggedView isTypeOfClass:[UIImageView class]])
{
self.imageBeingDragged = (UIImageView*)draggedView;
}
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
self.imageBeingDragged.center = point;
}
else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
// Determine if dragged view is in an OK drop zone
// If so, then do the drop action, if not, return it to original location
self.imageBeingDragged = nil;
}
}
In the UIGestureRecognizerStateBegan, once you find a UIImageView you may want to remove it from the superview (scrollview) and add it as a subview to some other container. You will need to translate the point into the new coordinate space if you do this. If you want the original image to stay in the scrollview, then make a copy of it and add that to an outside container.
To try out the above example and see it working, you may need to turn off clipping on the scrollview since the example I gave above is dragging the UIImageView from inside the scrollview (though normally you'd add it to some containing view).

On way I have seen this done is by using an overlay layer to capture the touches and pass them through. This allows you to intercept the clicks before the UIScrollView consumes them.
Here is the demo video that I looked at when trying to construct a UITableView (inside a scroll view) that could have cells dragged and dropped on to it.
Also I am not sure how applicable this is but here is a similar post I made a few days ago.
Having reviewed this issue some more I built something that allows you to drag and drop cells between UITableViews similar to the video I mentioned previously. My tutorial can be found here and the result can be seen in this YouTube video. This method uses the latest gesture features in iOS 5 and pops cells off using a long press.
Hope you can find something in here that helps.

Related

How to dismiss programmatically the clipsToBounds property when a GestureRecognizer begin?

I have a UIScrollView which is able to contains many view. To allow a good scrolling (without the content going outside the view while scrolling), on my Main.sotryboard , I've clicked on my UIScrollView and then in the attribute inspector I have allowed the Clip Subviews property:
My problem: all the views which are in my UIScrollViews are draggable (because they all have a UIPanGestureRecognizer.
So, when I try to drag them OUTSIDE my UIScrollView, they just disappear.
In fact they're just going behind every other view
To give you an exemple, I have others components which allow the drop of a view form the precedent UIScrollView. So when I begin the drag'n'drop from it, it disappear, and then reappear in the second component on which I have dropped the view.
What I have tried: I have a special UIPanGestureRecognizer for te drag'n'drop of a view coming from this UIScrollView. So, I actually have this (which, obviously, doesn't work, otherwise I would not be here):
//Here recognizer is the `UIPanGestureRecognizer`
//selectpostit is the name of the view I want to drag
if(recognizer.state == UIGestureRecognizerStateBegan){
selectpostit.clipsToBounds = NO;
}
Any Ideas on how I can improve that?
Thanks in advance.
You could try to reset scrollView.clipsToBounds to NO every time gesture starts, but that would lead to side effect when other content outside scroll view would become visible when dragging is in the progress.
I would recommend to take snapshot of the the draggable view when panning starts, place it on the scrollview's parent, and move it. Such approach should solve your problem.
Here is the code:
- (void)onPanGesture:(UIPanGestureRecognizer*)panRecognizer
{
if(panRecognizer.state == UIGestureRecognizerStateBegan)
{
//when gesture recognizer starts, making snapshot of the draggableView and hiding it
//will move shapshot that's placed on the parent of the scroll view
//that helps to prevent cutting by the scroll view bounds
self.draggableViewSnapshot = [self.draggableView snapshotViewAfterScreenUpdates: NO];
self.draggableView.hidden = YES;
[self.scrollView.superview addSubview: self.draggableViewSnapshot];
}
//your code that updates position of the draggable view
//updating snapshot center, by converting coordinates from draggable view
CGPoint snapshotCenter = [self.draggableView.superview convertPoint:self.draggableView.center toView: self.scrollView.superview];
self.draggableViewSnapshot.center = snapshotCenter;
if(panRecognizer.state == UIGestureRecognizerStateEnded ||
panRecognizer.state == UIGestureRecognizerStateCancelled ||
panRecognizer.state == UIGestureRecognizerStateFailed)
{
//when gesture is over, cleaning up the snapshot
//and showing draggable view back
[self.draggableViewSnapshot removeFromSuperview];
self.draggableViewSnapshot = nil;
self.draggableView.hidden = NO;
}
}
I recommend you look at this article by ray wenderlich Moving Table View Cells with a Long Press Gesture
It explains how to create snapshots

UISwipeGestureRecognizer interferes with slider

I have a view in an iOS application (Obj-C) which has an image view in the centre, and immediately below that a slider.
The image view shows album artwork, and the slider can be used to adjust the now-playing track position.
There is also a pair of left and right Swipe Gesture Recognizers. These are used to skip to the next or previous tracks.
The problem is that the swipe gesture recognizers seem to over-ride the users moving the slider thumb.
In my gesture recognizer code I check that the point touched was inside the image view, but it still stops the slider from being moved. (The thumb moves, but jumps back to it's original position when you remove your finger).
This is the code I use to reject the gesture if it's not inside the image view.
- (IBAction)swipeLeftGestureAction:(UISwipeGestureRecognizer *)sender {
// Get the location of the gesture.
CGPoint tapPoint = [sender locationInView:_artworkImageView];
// Make sure tap was INSIDE the artwork image frame.
if( (tapPoint.x <0)
|| (tapPoint.y < 0 )
|| (tapPoint.x > _artworkImageView.frame.size.width)
|| (tapPoint.y>_artworkImageView.frame.size.height))
{
NSLog(#"Outside!");
return;
}
NSLog(#"Swipe LEFT");
[_mediaController skipNext];
}
So my question is, how do I limit the gesture to work ONLY when swiped across the image view?
Try to put the code that restricts the gesture's area in gestureRecognizer:shouldReceiveTouch: and return NO in case you don't want the gesture to receive this touch. It should prevent the gesture from over taking the slider interaction.
If you're only interested in swipes that are inside the image view, then you should add the swipe gesture recognizer to the image view instead of adding it to your entire view. Then you won't need any special logic.
There is a dedicated method for checking if a point is inside a view
BOOL isPointInsideView = [_artworkImageViewpointInside:tapPoint withEvent:nil];
But I think what is happening is that if you will look at the tapPoint is that it actually outside of your imageView
And if your slider is really close to the imageView so the slider captures the movement, what you should do is check on the slider if it is intended for the slider and propagate on to the imageView if needed
Or inherit the UISlider and reduce its response rect

How can I set up gesture recognizer to interact any UIView when all the views are being animated?

I found the code listed below from https://github.com/DuncanMC/iOS-CAAnimation-group-demo. This particular method allows the user to stop a UIView while it is "in-flight" in a core animation sequence using a gesture recognizer. When the view is tapped, the animation stops. As shown this code will only work on animated view. I have many animated views and I need interaction with any of the views. I think I must set up an array of views (or layers) and cycle through them. Is this correct? How could I do this? Thanks!
/*
This method gets called from a tap gesture recognizer installed on the view myContainerView.
We get the coordinates of the tap from the gesture recognizer and use it to hit-test
myContainerView.layer.presentationLayer to see if the user tapped on the moving image view's
(presentation) layer. The presentation layer's properties are updated as the animation runs, so hit-testing
the presentation layer lets you do tap and/or collision tests on the "in flight" animation.
*/
- (IBAction)testViewTapped:(id)sender
{
CALayer *tappedLayer;
id layerDelegate;
UITapGestureRecognizer *theTapper = (UITapGestureRecognizer *)sender;
CGPoint touchPoint = [theTapper locationInView: myContainerView];
if (animationInFlight)
{
tappedLayer = [myContainerView.layer.presentationLayer hitTest: touchPoint];
layerDelegate = [tappedLayer delegate];
if (((layerDelegate == imageOne && !doingMaskAnimation)) ||
(layerDelegate == waretoLogoLarge && doingMaskAnimation))
{
if (myContainerView.layer.speed == 0)
[self resumeLayer: myContainerView.layer];
else
{
[self pauseLayer: myContainerView.layer];
//Also kill all the pending label changes that we set up using performSelector:withObject:afterDelay
[NSObject cancelPreviousPerformRequestsWithTarget: animationStepLabel];
}
}
}
}
LOL. That demo project is mine. The code is written to find the layer that was tapped, and then use the fact that for a layer that backs a UIView, the layer's delegate is the view itself.
At the point in the code where it finds the layerDelegate, you should make sure it isKindOfClass UIView, then use whatever method is appropriate to match your view with the views you've animated. You could use an IBOutletCollection to keep track of the views that you are animating, or manually create a mutable array and add view objects to it, use view tags, or whatever makes sense for your application.

iOS: UIPanGesture and frame/bounds issue

I have created a relatively simple app which allows the user to drag an imageview from a 'tray' UIView at the bottom of the screen, and when the view is dropped, it adds itself to a subview of a 'target' UIView.
My problem is, when I drop the imageview into the target view, the frame is totally wrong, and the imageview jumps (seemingly randomly) to another position in the target view.
I've torn my hair out over this, and am having a massive brainfart. Is there a way to just get the coordinates of the dragged view in the superview, and then translate that into coordinates of the target view?
As you can see, i'm taking the icon out of the 'tray' view, and into the main view when the dragging begins. When it ends, I simply add the icon into the target view.
if (gesture.state == UIGestureRecognizerStateBegan){
if (icon.superview == viewTray) {
[self closeTray:nil];
[self.view addSubview:icon];
}
}
if (gesture.state == UIGestureRecognizerStateEnded) {
[viewTarget addSubview:icon];
}
An image of the basics of the xib:
use the gesture recognizer to figure out where the finger touches in the viewTarget's frame by:
CGPoint p = [gesture locationInView:viewTarget];
then set the icon's center to be that point, and you are done:
icon.center = p;
[icon removeFromSuperView];
[viewTarget addSubview:icon];
The problem is that the frame is in the bounds of its superView. So when you drop it into a new superView its not the same. You need to convert it.
This code will convert its from from its superView coordinate system to its targetView coordinate system. You should probably do this right after [viewTarget addSubview:icon];
[viewTarget convertRect:icon.frame fromView:icon.superView];

What steps do you need to take to translate UIPanGestureRecognizer touches to ScrollView zooming?

I am creating a gesture recognizer to handle zooming in a scroll view (scrolls along only one on axis at a time). I have the gesture recognizer working but I'm having trouble using the data from the gesture recognizer to transform my views properly. This is what I do right now:
- (void)handlePinch:(GPinchGestureRecognizer *)pinchRecognizer
{
CGSize contentSize = [[self scrollView] contentSize];
if (pinchRecognizer.pinchType == VerticalPinchZoomIn || pinchRecognizer.pinchType == VerticalPinchZoomOut)
{
[[self scrollView] containerView].transform = CGAffineTransformScale([pinchRecognizer transformBeforeTouches], 1, [pinchRecognizer scale]);
[[self scrollView] setContentSize:CGSizeMake(contentSize.width, [pinchRecognizer initialContentSize].height * [pinchRecognizer scale])];
}
...
...
}
This resizes the view nicely, however, it lets it get to strange positions on the screen, and sometimes the scroll view won't be able to scroll all the way to the edge of it (it thinks its boundary is in the middle of the view somewhere and bounces back).
So basically, my question is, what other properties of what other objects and whatnot do I need to operate on to get this working right? View.transform, ScrollView.contentSize, what else? If only Apple's UIScrollView implementation file was open source xD
U do need to add UIPinchGestureRecognizer or neither maintain it.
Just follow this link to add image in scrollview for zooming

Resources