In my iPhone App I want to implemented functionality as shown below
user can pick a shape(an image) from one view and put in other view
How can I achieve this?
Easiest way is to use a UIPanGestureRecognizer. That will give you messages when the view is moved and when it is dropped. When it is moved, update its center. When it is dropped, check if its position is within the bounds of the view you want to drop in. (You might need to convert coordinates to the target view's coordinate system.) If it is, do the appropriate action.
Try below link drag and drop image around the screen
also try this
You can refer to the previous post which will definitely help you to achieve this functionality...
Basic Drag and Drop in iOS
Building drag and drop interface on iphone
iPhone drag/drop
For all of above link, You have to keep in mind that You need to first get TouchesBegin event for any Control and then you have to get the TouchesMoved event for same control.
In TouchesMoved event, you just have to get the center point (CGPoint) of the Control. And when you release the control will be set at that CGPoint. If this creates problem then you can take that CGPoint in variable and set that Point in TouchesEnded event.
For your case, i think you must have to maintain the Hierarchy of the Views...Else while dragging you view may not be visible...
FOR MORE CODING PART :
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"%f,%f", self.center.x, self.center.y);
CGPoint newLoc = CGPointZero;
newLoc = [self.mainView convertPoint:[[touches anyObject] locationInView:self.superview] toView:self.superview];
float newX = newLoc.x + self.superview.frame.origin.x + (self.frame.size.width /2) + [[touches anyObject] locationInView:self].x ;
float newY = newLoc.y - (((UIScrollView *)self.superview).contentOffset.y *2) ;
NSLog(#"content offset %f", ((UIScrollView *)self.superview).contentOffset.y);
self.scrollParent.scrollEnabled = NO;
NSLog(#"%f,%f", self.center.x, self.center.y);
newLoc = CGPointMake(newX, newY);
[self.superview touchesCancelled:touches withEvent:event];
[self removeFromSuperview];
NSLog(#"%f,%f", self.center.x, self.center.y);
self.center = CGPointMake(newLoc.x, newLoc.y);
[self.mainView addSubview:self];
NSLog(#"%f,%f", self.center.x, self.center.y);
[self.mainView bringSubviewToFront:self];
isInScrollview = NO;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[UIView beginAnimations:#"stalk" context:nil];
[UIView setAnimationDuration:.001];
[UIView setAnimationBeginsFromCurrentState:YES];
UITouch *touch = [touches anyObject];
self.center = [touch locationInView: self.superview];
[UIView commitAnimations];
if ((self.center.x + (self.frame.size.width / 2)) > 150 && hasExitedDrawer && !self.scrollParent.dragging ) {
self.scrollParent.scrollEnabled = NO;
[self.delegate moveItemsDownFromIndex: ((self.center.y + (self.scrollParent.contentOffset.y)) / 44) + 1 ];
//NSLog(#"%i", ((self.center.y + (self.scrollParent.contentOffset.y *2)) / 44) + 1);
}
if (self.center.x + (self.frame.size.width / 2) < 150) {
hasExitedDrawer = YES;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if ((self.center.x + (self.frame.size.width / 2)) > 150 && hasExitedDrawer && !self.scrollParent.dragging ) {
CGPoint newLoc = CGPointZero;
newLoc = [self.scrollParent convertPoint:[[touches anyObject] locationInView:self.superview] toView:self.superview];
float newY = newLoc.y + (self.scrollParent.contentOffset.y *2);
[self.scrollParent insertSubview:self atIndex:((self.center.y + (self.scrollParent.contentOffset.y)) / 44) ];
self.frame = CGRectMake(0, newY, self.frame.size.width, self.frame.size.height);
isInScrollview = YES;
hasExitedDrawer = NO;
}
}
This code may cantains some irrelevant but gives you more idea...
You can use below open source libraries:
Library 1 OBDragDrop
Library 2 AJWDraggableDroppable
Library 3 iOS-DragAndDrop
Library 4 ios-drag-and-drop
Adding drag and drop component to iOS app the Question
i thing you are going to Build a feature like Add to cart in Most of the Shopping Apps like Amazon, Flip kart and etc..
Three step solution
1) u'll have to implement/listen for touch events
2) implement dragging and touch events
3) and then manage movetosuperview method.
Related
I have a scroll view with a fixed number of thumbnail images added as subview. I want to move these images along touch to the rectangle in another view. I am able to move the image along scrollview (ie, along the same view) but not able to move across another view.
Now am changing the center of image depending on touch position. When touch point increases beyond the frame of scrollview the image disappears. This is my problem
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self];
NSLog(#"%f,%f",location.x,location.y);
touch.view.center = location;
}
Any solution to this problem will be a great help for me !!!
Please refer image for further details
Here is what I'd do :
Add a panGestureRecognizer to each image, with the following handlePan: method as its action. You still have to figure out how to get the correct imageView (myImageView), but this will make your image follow your finger.
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
// Find the correct image you're dragging
// UIImageView *myImageview = ...
CGPoint translation = [recognizer translationInView:self.view];
if (recognizer.state == UIGestureRecognizerStateEnded) {
// What to do when you start the gesture
// You may also define myImageView here
// (if so, make sure you put it in #interface,
// because this method will be called multiple times,
// but you will enter this "if" only when you start the touch)
}
// Keep your image in the screen
if (myImageView.frame.origin.x + translation.x >= 0.0f &&
myImageView.frame.origin.x + myImageView.frame.size.width + translation.x <= 320.0f &&
myImageView.frame.origin.y + translation.y >= 0.0f &&
myImageView.frame.origin.y + myImageView.frame.size.height + translation.y <= 480.0f) {
myImageView.center = CGPointMake(myImageView.center.x + translation.x,
myImageView.center.y + translation.y);
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
// What to do when you remove your finger from the screen
}
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
Okay, I have been all over the internet trying to find the answer to this, I am trying to create a custom UIScrollView scroller.
Here is a link to a picture of the scroller
http://postimage.org/image/cg2jvde9z/
http://postimage.org/image/ko0mp3kdj/
(that white box is just for me to test the scrollview)
I have gotten the scroller to work, although I need help figuring out how many pixels the scrollview should move every time the scroller is pushed
here is some code
-(IBAction)scroller_bar:(id)sender withEvent:(UIEvent *)event{
UIButton *button_sent = (UIButton *)sender;
UITouch *touch = [[event touchesForView:button_sent] anyObject];
CGPoint previousLocation = [touch previousLocationInView:button_sent];
CGPoint location = [touch locationInView:button_sent];
CGFloat delta_x = location.x - previousLocation.x;
float left_side = button_sent.center.x + delta_x;
float right_side = button_sent.center.x + delta_x;
if (right_side > button_sent.center.x) {
scroll_right = YES;
}
else{
scroll_right = NO;
}
if (left_side <= 13 + 50.5 || right_side >= 307 - 50.5) {
}
else{
button_sent.center = CGPointMake(button_sent.center.x + delta_x,
button_sent.center.y);
if (scroll_right) {
[selection_scroll setContentOffset:CGPointMake(selection_scroll.contentOffset.x - (Help HERE!), selection_scroll.contentOffset.y) animated:YES];
}
else{
[selection_scroll setContentOffset:CGPointMake(selection_scroll.contentOffset.x + (Help HERE!), selection_scroll.contentOffset.y) animated:YES];
}
}
}
In the above code you should see a '(Help HERE!)',
that is where i am trying to figure out how many pixels i should move the scroll view. This is a bit of a confusing question, hope you understand.
Thanks :)
I don't know whether APPLE will approve this or not but the code written below can change the scollView 's scroller images
for (UIImageView *img in yourscrollView.subviews) {
[img setImage:[UIImage imageNamed:#"your custom scroller image"]];
}
I'm trying to implement a drag & drop feature on a UIButton, and it works fine, but I can't figure out a way to determine when the user has let go of the button and finished dragging. The below code works fine for dragging, but I need to be notified when the user has finished dragging and let go of the button.
- (void)viewDidLoad
{
[gesturesBrowserButton addTarget:self action:#selector(wasDragged:withEvent:)
forControlEvents:UIControlEventTouchDragInside];
[gesturesBrowserButton addTarget:self action:#selector(finishedDragging:withEvent:)
forControlEvents:UIControlEventTouchDragExit];
}
- (void)wasDragged:(UIButton *)button withEvent:(UIEvent *)event
{
// get the touch
UITouch *touch = [[event touchesForView:button] anyObject];
// get delta
CGPoint previousLocation = [touch previousLocationInView:button];
CGPoint location = [touch locationInView:button];
CGFloat delta_x = location.x - previousLocation.x;
CGFloat delta_y = location.y - previousLocation.y;
// move button
button.center = CGPointMake(button.center.x + delta_x,
button.center.y + delta_y);
NSLog(#"was dragged");
}
- (void)finishedDragging:(UIButton *)button withEvent:(UIEvent *)event
{
//doesn't get called
NSLog(#"finished dragging");
}
I think that replacing
UIControlEventTouchDragExit
with
UIControlEventTouchDragExit|UIControlEventTouchUpInside
would be a good start to solve your problem.
The event I believe you want here is UIControlEventTouchUpInside. That's the "touch has gone away while inside this control." It's possible you won't get that one at this point, though. You certainly won't get UIControlEventTouchDragExit, since that means the drag has left the control.
If UIControlEventTouchUpInside doesn't work for you, I like to capture UIControlEventAllEvents and just log them as they come in. Then you can see exactly what is fired when.
This isn't another one of "those" questions, don't worry.
Basically I want to test for a pinch and then run an animation. Here is the code I currently have:
// test for a pinch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
if([allTouches count] == 2){
//there are two touches...
UITouch *firstTouch = [[allTouches allObjects] objectAtIndex:0];
UITouch *secondTouch = [[allTouches allObjects] objectAtIndex:1];
CGPoint firstPoint = [firstTouch locationInView:self.superview];
CGPoint secondPoint = [secondTouch locationInView:self.superview];
int X1 = firstPoint.x;
int Y1 = firstPoint.y;
int X2 = secondPoint.x;
int Y2 = secondPoint.y;
// lets work out the distance:
// sqrt( (x2-x1)^2 + (y2-y1)^2 );
preDistance = sqrtf( (float)pow((X2-X1),2) + (float)pow((Y2-Y1),2) );
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
if([allTouches count] == 2){
//there are two touches...
UITouch *firstTouch = [[allTouches allObjects] objectAtIndex:0];
UITouch *secondTouch = [[allTouches allObjects] objectAtIndex:1];
CGPoint firstPoint = [firstTouch locationInView:self.superview];
CGPoint secondPoint = [secondTouch locationInView:self.superview];
int X1 = firstPoint.x;
int Y1 = firstPoint.y;
int X2 = secondPoint.x;
int Y2 = secondPoint.y;
// lets work out the distance:
// sqrt( (x2-x1)^2 + (y2-y1)^2 );
postDistance = sqrtf( (float)pow((X2-X1),2) + (float)pow((Y2-Y1),2) );
// lets test now
// if the post distance is LESS than the pre distance then
// there has been a pinch INWARDS
if(preDistance > postDistance){
NSLog(#"Pinch INWARDS");
// so we need to move it back to its small frame
if(CGRectEqualToRect(self.frame, largeFrame) && !CGRectIsEmpty(self.smallFrame)){
// we can go inwards
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
self.frame = smallFrame;
[UIView commitAnimations];
}
}
else {
NSLog(#"Pinch OUTWARDS");
// so we need to move it back to its small frame
if(!CGRectEqualToRect(self.frame, largeFrame)){
// we can go outwards
// set org frame
smallFrame = self.frame; // so we can go back later
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
self.frame = largeFrame;
[UIView commitAnimations];
}
}
}
}
All it does is measure the distance between the two touches if there is a multi touch, then it measures the distance again when the touches end. If the difference between the two is positive then it was an outwards pinch, and if it was negative it was an inwards pinch.
Depending on the direction of the pinch the image view will scale bigger or smaller to and from set CGRects (this is why I don't want the "normal" pinch and zoom functionality). I just want it to be a gesture to scale an image up and down again.
However, this isn't working very well... it doesn't always pick up pinches. I don't know if this is because the view its in is also detecting touches (only single pinches), but still...
Anyway, I was wondering if anyone has a better way of detecting pinches? I've currently subclassed the UIImageView to create my ImageController class which has these touch methods in them. All I need to know is a) they are touching this image and b) which direction they've pinched in.
Thanks
Check out UIPinchGestureRecognizer in the documentation. I haven't used it, but seems like it's just what you need.
Anyway, I was wondering if anyone has a better way of detecting pinches?
If you're targeting iOS 3.2 and upwards you can use gesture recognizers - there's no good reason not to. If you need to target pre 3.2, then your above approach (or varients therein, using touchesBegin, etc) is the only way, so it's just tweaking the algorithm.
If you can, I'd strongly recommend using UIPinchGestureRecognizer. It will make your life considerably easier, as it handles all the details. If you want to detect both the scale and direction of the pinch you can combine UIPinchGestureRecognizer with a UIRotationGestureRecognizer - the former will just give you the scale of a pinch, not the relative angle.
If you can live without 3.1.x devices I would recommend that you use the UIPinchGestureRecognizer. It's very simple to use, but the problem is that you're only going to be able to run it on iOS devices running 3.2 and upwards.
For some reason you are using locationInView to identify the position of the touches. Have you tried identifying the touches location in the current view (the actual image view)? Calling superview means that you will get the position of the touches in the view that contains your image view.
I am attempting to make a UIView/UIControl that people can drag up and reveal a text box, and then drag down to hide it. However, I have yet to find a method to make this "fluid" - it always seems to stop at random places and doesn't allow any more movement. At the moment I am using a UIView for the top part of the view and here is the current code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == topMenuView) {
CGPoint location = [touch locationInView:self.superview];
CGPoint locationInsideBox = [touch locationInView:self];
CGPoint newLocation = location;
newLocation.x = self.center.x;
newLocation.y = newLocation.y + (self.frame.size.height - locationInsideBox.y) / 2;
if ((self.superview.frame.size.height - newLocation.y) < (self.frame.size.height / 2) && (self.superview.frame.size.height - newLocation.y) > -32)
{
self.center = newLocation;
}
return;
}
}
Any help would be much appreciated!
I would use a pan gesture recognizer. The following code will simply move the view up and down along with the user's finger. If you want to limit how far up it moves, have it snap to place or have momentum you'll need to add to it.
UIView * view; // The view you're moving
CGRect originalFrame; // The frame of the view when the touch began
- (void) pan:(UIPanGestureRecognizer *)pan {
switch (pan.state) {
case UIGestureRecognizerStateBegan: {
originalFrame = view.frame;
} break;
case UIGestureRecognizerStateChanged:
case UIGestureRecognizerStateEnded: {
CGPoint translation = [pan translationInView:view];
CGRect frame = originalFrame;
frame.origin.y += translation.y;
view.frame = frame;
} break;
}
}
Removing this line may well help you:
newLocation.y = newLocation.y + (self.frame.size.height - locationInsideBox.y) / 2;
What you're trying to accomplish is really nothing more than a scrollable view, so I would recommend using a UIScrollView.
Put your UIView in a UIScrollView with transparent background, and place the UIScrollView on top of your textbox. Set the correct contentSize and you're good to go.
use a uiview animation block to update the frame of the sliding view corresponding with the touch point recieved. set the animation blocks duration to something really short like .01 or lower.
I'd recommend splitting the issue in two:
Implement the view which has the text box at the bottom - You will just have to implement your own custom view/view controller.
Add your view as a subview of a UIScrollView.
This is a good tutorial which demonstrates proper initialization of UIScrollView and embedding content in it.
Custom views/controllers are a bit of a broader subject :)