How to make UIButton Draggeable? - iphone

I need to drag and drop the uibutton in subview only.
Actually i am taking subview in main view. UIbutton is add in subview. When i drag the button it moves on both view but i need to drag button only in subview. Can anyone help me please.
Thanks in advance.
- (void) drag
{
//subview
UIView *viewscramble = [[UIView alloc] initWithFrame:CGRectMake(0, 90, 320, 50)];
[viewscramble setBackgroundColor:[UIColor redColor]];
[self.view addSubview:viewscramble];
//button
UIButton *btnscramble = [[UIButton alloc] initWithFrame:CGRectMake(5, 0, 50, 50)];
btnscramble.titleLabel.text = #"A";
[btnscramble setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btnscramble addTarget:self action:#selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[btnscramble setBackgroundImage:[UIImage imageNamed:#"box.png"] forState:UIControlStateNormal];
//add button`
[viewscramble addSubview:btnscramble];
[btnscramble release];
}
- (IBAction)imageMoved:(id)sender withEvent:(UIEvent *) event
{
CGPoint point = [[[event allTouches]anyObject] locationInView:viewscramble];
UIControl *control = sender;
control.center = point;
}

i just found the solution of your Question from:- http://www.cocoanetics.com/2010/11/draggable-buttons-labels/
- (void)viewDidLoad
{
[super viewDidLoad];
// create a new button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Drag me!" forState:UIControlStateNormal];
// add drag listener
[button addTarget:self action:#selector(wasDragged:withEvent:)
forControlEvents:UIControlEventTouchDragInside];
// center and size
button.frame = CGRectMake((self.view.bounds.size.width - 100)/2.0,
(self.view.bounds.size.height - 50)/2.0,
100, 50);
// add it, centered
[self.view addSubview:button];
}
- (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);
}
Hope its helpful for you :)

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint pointMoved = [touch locationInView:"SUBVIEWNAME.view"];  
    button.frame = CGRectMake(pointMoved.x, pointMoved.y, 64, 64);
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *tap = [touches anyObject];
CGPoint pointToMove = [tap locationInView:yourSubView]; // just assign subview where you want to move the Button
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if([touch view] == YOUR_BUTTON_OBJECT){
CGPoint point = [touch locationInView:YOUR_PARENT_VIEW];
//YOUR_X_LIMIT is your subview end in x direction.
//YOUR_Y_LIMIT is your subview end in y direction.
if(point.x < YOUR_X_LIMIT && point.y < YOUR_Y_LIMIT){
button.center = point;
}else{
// do nothing since touch is outside your limit.
}
}
}

Use UIControlEventTouchDragInside and UIControlEventTouchUpInside events of UIButton like
// add drag listener
[button addTarget:self action:#selector(wasDragged:withEvent:) forControlEvents:UIControlEventTouchDragInside];
// add tap listener
[button addTarget:self action:#selector(wasTapped:) forControlEvents:UIControlEventTouchUpInside];
You can use hbdraggablebutton control..

Related

How to change the positions of UIButton on iOS/iPhone

In my application, I am creating three UIButton inside, and I want these button should be swapped among it. (i.e) If I drag and drop the (button 1) and place it on (button 2), then
(button 2) should get replaced in the position of (button 1) and also the same for (button 3). I found, for how to drag and drop the UIButton, but I can't able to swap it.
Here is my code for button creation and drag and drop:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Drag One!" forState:UIControlStateNormal];
// add drag listener
[button addTarget:self action:#selector(wasDragged:withEvent:)
forControlEvents:UIControlEventTouchDragInside];
// center and size
button.frame = CGRectMake((self.view.bounds.size.width - 10)/2.0,
(self.view.bounds.size.height - 50)/2.0,
100, 50);
button.tag=0;
[self.view addSubview:button];
.........
-(void)wasDragged:(UIButton *)button withEvent:(UIEvent *)event
{
if(button.tag==0){
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);
}
...........
}
Use code like this:
[UIView animateWithDuration:0.5
delay:0.1
options: UIViewAnimationCurveEaseOut
animations:^
{
CGSize s = [[CCDirector sharedDirector] winSize];
CGRect frame = mButton.frame;
frame.origin.y = location.y ;
frame.origin.x = location.x ;
mButton.frame = frame;
}
completion:^(BOOL finished)
{
}];

touchesEnded not called

I have one custom table name tbltask in my view and on touch begin and on touch moved method i am creating a lable dynamically.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
self.scrollEnabled=NO;
CGPoint point = [[touches anyObject] locationInView:[self superview]];
CGPoint pointtask=[[touches anyObject] locationInView:self];
NSIndexPath *indexPath = [self indexPathForRowAtPoint:pointtask];
rowid=indexPath.row;
app.sublable=[[UILabel alloc] initWithFrame:CGRectMake((point.x)-145, (point.y)-50, 300, 40)];
app.sublable.textAlignment=UITextAlignmentRight;
messagedrag=[app.arraddtask objectAtIndex:rowid];
app.sublable.text=[NSString stringWithFormat:#" %#",messagedrag.msgsubject];
app.sublable.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"black.png"]];
app.sublable.layer.cornerRadius=8.0;
app.sublable.layer.borderWidth=4;
app.sublable.layer.borderColor=[[UIColor lightGrayColor] CGColor];
app.sublable.textColor=[UIColor whiteColor];
UIFont *f = [UIFont fontWithName:#"Verdana-Bold" size:16];
app.sublable.font = f;
[app.sublable setTextAlignment:UITextAlignmentLeft];
[self.superview addSubview:app.sublable];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if(app.sublable!=nil)
{
[app.sublable removeFromSuperview];
}
CGPoint point = [[touches anyObject] locationInView:[self superview]];
NSIndexPath *indexPath = [self indexPathForRowAtPoint:point];
NSLog(#"............super %f",[self superview].frame.origin.y);
app.sublable=[[UILabel alloc] initWithFrame:CGRectMake((point.x)-145, (point.y)-50, 300, 40)];
app.sublable.textAlignment=UITextAlignmentRight;
messagedrag=[app.arraddtask objectAtIndex:rowid];
app.sublable.text=[NSString stringWithFormat:#" %#",messagedrag.msgsubject];
app.sublable.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"black.png"]];
app.sublable.layer.borderWidth=4;
app.sublable.layer.borderColor=[[UIColor lightGrayColor] CGColor];
app.sublable.layer.cornerRadius=8.0;
app.sublable.textColor=[UIColor whiteColor];
UIFont *f = [UIFont fontWithName:#"Verdana-Bold" size:16];
app.sublable.font = f;
[app.sublable setTextAlignment:UITextAlignmentLeft];
[self.superview addSubview:app.sublable];
}
it result in that.
so when i touch on tbltask touchBegan method start working and create one lable with subject is written on that in superview which is main view here on where the tbltask is there as you can see.(the bottom one is table task)
Now when i call touchesEnded method ::
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
//<my stuff>
[super touchesEnded:touches withEvent:event];
NSString *taskname=[[NSString alloc] init];
self.scrollEnabled=YES;
if(app.sublable!=nil)
{
taskname=app.sublable.text;
[app.sublable removeFromSuperview];
}
[taskdelegate droptask:self strtask:taskname];
}
this subject is dropped on above table.
It works fine.but when i touch the tbltask left to right or right to left something is happened and touch end method is not called so sublable is not removed from the view like this.like this...
so what am i doing wrong in this...
and yes i m calling the touch events on table touch as you will notice.
please help me in this problem...
Thanks in Advance.

How to achieve continuous drag drop menu effect?

I'm trying to achieve a Drag and Drop menu affect. I'm not sure how to go about this, perhaps someone has experience with this exact effect.
Quite simply, when a user touches down on a menu item, I want a graphic to appear at their touch location. Their touch will now control the panning of the graphic. Upon releasing the touch, the graphic will sit in its place and assume full alpha.
I'm already familiar with creating pan gestures and instantiating a graphic. So far, I can create the graphic where the menu item is touched. The biggest issue is how I "pass over" the touch gesture so it is a single and continuous motion.
Also, should the menu item be UIButton or UIImageView?
Any help appreciated. Thanks
I had some fun with this one. The following code will grab the image from the button when touched, drag that image at alpha=0.5, and drop it wherever your touches end at alpha=1.0. It will continue to be draggable thereafter.
After importing QuartzCore, create a new file. The .h should read:
#import <Foundation/Foundation.h>
#import <QuartzCore/CAGradientLayer.h>
#import <QuartzCore/CALayer.h>
#interface DraggableImage : CAGradientLayer
- (void)draw:(UIImage *)image;
- (void)moveToFront;
- (void)appearDraggable;
- (void)appearNormal;
#end
and the .m should read:
#import "DraggableImage.h"
#implementation DraggableImage
- (void)draw:(UIImage *)image{
CGRect buttonFrame = self.bounds;
int buttonWidth = buttonFrame.size.width;
int buttonHeight = buttonFrame.size.height;
UIGraphicsBeginImageContext( CGSizeMake(buttonWidth, buttonHeight) );
[image drawInRect:self.bounds];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[newImage drawInRect:self.bounds];
}
- (void)moveToFront {
CALayer *superlayer = self.superlayer;
[self removeFromSuperlayer];
[superlayer addSublayer:self];
}
- (void)appearDraggable {
self.opacity = 0.5;
}
- (void)appearNormal {
self.opacity = 1.0;
}
#end
Now in your main view controller, add:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "DraggableImage.h"
#interface YourViewController : UIViewController{
DraggableImage *heldImage;
DraggableImage *imageForFrame[5]; // or however many
UIButton *buttonPressed;
int imageCount;
}
#property (weak, nonatomic) IBOutlet UIButton *imageButton;
-(IBAction)buildImageLayerForButton:(UIButton *)sender;
- (void)moveHeldImageToPoint:(CGPoint)location;
- (CALayer *)layerForTouch:(UITouch *)touch;
The imageButton in this case would be your apple Button. Now in your .m file, add this:
#synthesize imageButton;
#pragma - mark Touches
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CALayer *hitLayer = [self layerForTouch:[touches anyObject]];
if ([hitLayer isKindOfClass:[DraggableImage class]]) {
DraggableImage *image = (DraggableImage *)hitLayer;
heldImage = image;
[heldImage moveToFront];
}
hitLayer = nil;
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if (heldImage)
{
UITouch *touch = [touches anyObject];
UIView *view = self.view;
CGPoint location = [touch locationInView:view];
[self moveHeldImageToPoint:location];
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (heldImage) {
[heldImage appearNormal];
heldImage = nil;
}
}
- (void)dragBegan:(UIControl *)c withEvent:ev {
}
- (void)dragMoving:(UIControl *)c withEvent:ev {
UITouch *touch = [[ev allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
[self moveHeldImageToPoint:touchPoint];
}
- (void)dragEnded:(UIControl *)c withEvent:ev {
UITouch *touch = [[ev allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
[self moveHeldImageToPoint:touchPoint];
[heldImage appearNormal];
heldImage = nil;
}
-(IBAction)buildImageLayerForButton:(UIButton *)sender{
DraggableImage *image = [[DraggableImage alloc] init];
buttonPressed = sender;
CGRect buttonFrame = sender.bounds;
int buttonWidth = buttonFrame.size.width;
int buttonHeight = buttonFrame.size.height;
image.frame = CGRectMake(120, 24, buttonWidth*3, buttonHeight*3);
image.backgroundColor = [UIColor lightGrayColor].CGColor;
image.delegate = self;
imageForFrame[imageCount] = image;
[self.view.layer addSublayer:image];
[image setNeedsDisplay];
[image moveToFront];
[image appearDraggable];
heldImage = image;
[self moveHeldImageToPoint:sender.center];
imageCount++;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
UIGraphicsPushContext(ctx);
DraggableImage *image = (DraggableImage *)layer;
[image draw:[buttonPressed imageForState:UIControlStateNormal]];
UIGraphicsPopContext();
}
- (void)moveHeldImageToPoint:(CGPoint)location
{
float dx = location.x;
float dy = location.y;
CGPoint newPosition = CGPointMake(dx, dy);
[CATransaction begin];
[CATransaction setDisableActions:TRUE];
heldImage.position = newPosition;
[CATransaction commit];
}
- (CALayer *)layerForTouch:(UITouch *)touch
{
UIView *view = self.view;
CGPoint location = [touch locationInView:view];
location = [view convertPoint:location toView:nil];
CALayer *hitPresentationLayer = [view.layer.presentationLayer hitTest:location];
if (hitPresentationLayer)
{
return hitPresentationLayer.modelLayer;
}
return nil;
}
-(void)viewDidLoad{
[imageButton addTarget:self action:#selector(dragBegan:withEvent:) forControlEvents: UIControlEventTouchDown];
[imageButton addTarget:self action:#selector(dragMoving:withEvent:) forControlEvents: UIControlEventTouchDragInside | UIControlEventTouchDragOutside];
[imageButton addTarget:self action:#selector(dragEnded:withEvent:) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
[super viewDidLoad];
}
- (void)viewDidUnload {
[self setImageButton:nil];
[super viewDidUnload];
}
Et voila! Connect your button, set its image, and throw copies all over the screen. :)
Note: I didn't comment much, but would be happy to answer any questions.
Cheers!
EDIT: fixed the -(void)draw:(UIImage *)image{} so that it would resize the image properly.
if what you want is to pass the touch function to the second graphic (the big one) i think you can do something like this
on .h you have to declare the images that you're going to drag and float variable to remember previous point of the dragable button (i'm assuming you use IOS 5 SDK)
#property(nonatomic, strong) UIImageView* myImage;
#property float pointX;
#property float pointY;
then, at .m you can do this
myImage = [[UIImageView alloc]initWithImage:#"appleImage.jpg"];
myImage.alpha = 0;
//default UIImageView interaction is disabled, so lets enabled it first
myImage.userInteractionEnabled = YES;
[button addTarget:self action:#selector(wasDragged:withEvent:) forControlEvents:UIControlEventTouchDragInside];
and then make the drag function
- (void)wasDragged:(UIButton *)button withEvent:(UIEvent *)event
{
self.myImage.alpha = 0.5;
UITouch *touch = [[event touchesForView:button] anyObject];
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, to keep the dragging effect
button.center = CGPointMake(button.center.x + delta_x,
button.center.y + delta_y);
// moving the image
button.center = CGPointMake(button.center.x + delta_x,
button.center.y + delta_y);
self.pointX = previousLocation.x;
self.pointY = previousLocation.y;
[button addTarget:self action:#selector(dragRelease:withEvent:) forControlEvents:UIControlEventTouchUpInside];
}
finally, make the dragRelease function where you return the button to its original place and set the alpha of the images to 1
-(void)dragRelease:(UIButton *)button withEvent:(UIEvent *)event
{
self.myImage.alpha = 1;
button.center = CGPointMake(pointX, pointY);
}
and you're done :3
this is just the basic idea though, maybe this isn't what you want, but i hope this helps
edit* : oh and don't forget to synthesize all the properties, also if you're using SDK below 5.0, you can change the "strong" property to "retain"

Changing an Image on TouchesBegan

Hey, I am trying to change the image when the user touches the ImageView. At the moment the ImageView has the image "heart1.png" so when i touch the ImageViewer on screen it will change to "heart2.png" this is my code, help is much appreciated:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if (location.x >= imageView.frame.origin.x && location.x <= imageView.frame.origin.x + imageView.frame.size.height && location.y >= imageView.frame.origin.y && location.y <= imageView.frame.origin.y + imageView.frame.size.height) {
imageView.image = [UIImage imageNamed:#"heart2.png"];
}
}
That looks like a problem to me:
if (location.x >= imageView.frame.origin.x && location.x <= imageView.frame.origin.x + imageView.frame.size.--> height <--
should be width there probably :)
Rather than fool around with checking coordinates against a bounding rect, why don't you simplify things by using interface building to place a custom (i.e. invisible) UIButton right over the image? Then you can hook up touchesUpInside to an IBAction method. Then there's no awkward if statements in your code and less chance of making mistakes like this.
Consider using an UIButton instead.
[button setImage:[UIImage imageNamed:#"heart1.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"heart2.png"] forState:UIControlStateHighlighted];
There is no need to find location of view, You don't have to do move UIImageView. Simply do this:
-(void)viewDidLoad
{
// imageView is your UIImageView
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
[imageView setImage:[UIImage imageNamed:#"heart1.png"]];
[imageView setUserInteractionEnabled:YES];
// Make sure userInteractionEnable is set to be YES; otherwise the touch event will be happen on UIView not on ImageView;
[self.view addSubview:imageView];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view]==imageView)
[imageView setImage:[UIImage imageNamed:#"heart2.png"]];
}

UIButton grid activate same time dragging

I have a grid of various UIButtons (5 x 5)... Now I have a UIControlEventTouchUpInside.. this means that when the user wants to choose various buttons need to press each, one by one...
How can I do to activate the buttons when the user is dragging his finger over various buttons.
Here is the code I use:
for (i = 0; i < num_caselles; i++)
{
lletra = [[UIButton alloc] initWithFrame:CGRectMake(POS_H, POS_V, mida_boto, mida_boto)];
[botones addObject: lletra];
[lletra setTitle: [caselles objectAtIndex: i] forState: UIControlStateNormal];
lletra.tag = i;
[lletra addTarget:self action:#selector(lletraPitjada:) forControlEvents: UIControlEventTouchUpInside];
}
You can also react to:
UIControlEventTouchDragEnter or
UIControlEventTouchDragExit
to handle these cases.
Ok finally I resolved this way :
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint location = [touch locationInView:touch.view];
for(UIButton*boton in botones)
{
if(CGRectContainsPoint([boton frame], location) && boton.tag != boton_anterior)
{
boton_anterior = boton.tag;
[self lletraPitjada:boton];
}
}
}
I override/commented the button set action, because is not working for me :
//[lletra addTarget:self action:#selector(lletraPitjada:) forControlEvents: UIControlEventTouchDragEnter];
and deactive user interaction, because UITouch dont like buttons :
lletra.userInteractionEnabled = NO;
And voilà... all is working perfect...