Changing an Image on TouchesBegan - iphone

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

Related

How to make UIButton Draggeable?

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..

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"

Instantiate object on position in Xcode

What is the code when you want to instantiate an object (for example a bullet) on a certian position on screen? I've tried it myself and searched on the internet but there are no good examples or basic Xcode tutorials that explain this. I don't use Cocos2d. Help is much appreciated :) Thanks in advance!
//
// CoreViewController.m
// Core
//
// Created by user on 29-04-11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "CoreViewController.h"
#implementation CoreViewController
#synthesize ship;
#synthesize bullet;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == ship){
//ship
CGPoint location = [touch locationInView:self.view];
ship.center = location;
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == ship){
//bullet
// CGPoint blltPos = bullet.center;
CGPoint shpPos = ship.center;
// blltPos.x = blltPos.x += 3;
// bullet.center = blltPos;
UIImage *bulletImage = [UIImage imageNamed:#"bullet.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:bulletImage];
imageView.frame = CGRectMake(shpPos.x, shpPos.y, 60, 60);
}
}
#end
If you are using UIKit:
Create a UIImageView that contains a UIImage of the bullet.
Set the frame of the UIImageView to be the location you want (offset to the center) and the size of the image.
Quick example:
UIImage *bulletImage = [UIImage imageNamed:#"bullet.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:bulletImage];
imageView.frame = CGRectMake(xLoc, yLoc, bulletImage.size.width, bulletImage.size.height);
Maybe you've already figured it out, but to add the new UIImageView to a parent view, probably(?) the CoreViewController, you'll have to do something like this after you've done what Mark wrote:
[self.view addSubview:imageView];
or
[self.view insertSubview:imageView atIndex:0];
In the latter example you decides its z-position (atIndex) of the subviews, i.e if you want it to be in front or behind other subviews.

UIImage detecting touch and dragging

Fairly common question this, to which I have a few answers and I'm nearly there. I have a button which when pressed, will create an image (code as follows)
(numImages is set on load to ZERO and is used as a count up for the tag numbers of all images created)
UIImage *tmpImage = [[UIImage imageNamed:[NSString stringWithFormat:#"%i.png", sender.tag]] retain];
UIImageView *myImage = [[UIImageView alloc] initWithImage:tmpImage];
numImages += 1;
myImage.userInteractionEnabled = YES;
myImage.tag = numImages;
myImage.opaque = YES;
[self.view addSubview:myImage];
[myImage release];
I then have a touchesBegan method which will detect what's touched. What I need it to do is to allow the user to drag the newly created image. It's nearly working, but the image flickers all over the place when you drag it. I can access the image which you click on as I can get it's TAG, but I just cannot drag it nicely.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if (touch.view.tag > 0) {
touch.view.center = location;
}
NSLog(#"tag=%#", [NSString stringWithFormat:#"%i", touch.view.tag]);
}
- (void) touchesMoved:(NSSet *)touches withEvent: (UIEvent *)event {
[self touchesBegan:touches withEvent:event];
}
It works, in that I get an output of the tag for each image as I click on them. But when I drag, it flashes... any ideas?
In answer to my own question - I decided to create a class for handling the images I place on the view.
Code if anyone's interested....
Draggable.h
#import <Foundation/Foundation.h>
#interface Draggable : UIImageView {
CGPoint startLocation;
}
#end
Draggable.m
#import "Draggable.h"
#implementation Draggable
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point
CGPoint pt = [[touches anyObject] locationInView:self];
startLocation = pt;
[[self superview] bringSubviewToFront:self];
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
// Move relative to the original touch point
CGPoint pt = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];
frame.origin.x += pt.x - startLocation.x;
frame.origin.y += pt.y - startLocation.y;
[self setFrame:frame];
}
#end
and to call it
UIImage *tmpImage = [[UIImage imageNamed:"test.png"] retain];
UIImageView *imageView = [[UIImageView alloc] initWithImage:tmpImage];
CGRect cellRectangle;
cellRectangle = CGRectMake(0,0,tmpImage.size.width ,tmpImage.size.height );
UIImageView *dragger = [[Draggable alloc] initWithFrame:cellRectangle];
[dragger setImage:tmpImage];
[dragger setUserInteractionEnabled:YES];
[self.view addSubview:dragger];
[imageView release];
[tmpImage release];
Usually you get an implicit animation when you change center. Are you messing with -contentMode or calling -setNeedsDisplay by any chance?
You can explicitly request animation to avoid the delete and re-draw this way:
if (touch.view.tag > 0) {
[UIView beginAnimations:#"viewMove" context:touch.view];
touch.view.center = location;
[UIView commitAnimations];
}
Do note that NSLog() can be very slow (much slower than you'd expect; it's much more complicated than a simple printf), and that can cause trouble in something called as often as touchesMoved:withEvent:.
BTW, you're leaking tmpImage.

Which object, or view, did I touch?

Working in a ViewController that has a few views which were added to it as subviews and I have a touchesBegan method:
UIImageView *testImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.png"]];
testImage.frame = CGRectMake(0, 0, 480, 280);
[self.view addSubview:testImage];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point;
UITouch *touch = [touches anyObject];
point.x = [touch locationInView:self.view].x;
point.y = [touch locationInView:self.view].y;
if ( point.y >= 280 && point.y <= 320 )
{
if ( point.x >= 0 && point.x <= 160 )
{
[self menu1];
}
if ( point.x >= 161 && point.x <= 320 )
{
[self menu2];
}
if ( point.x >= 321 && point.x <= 480 )
{
[self menu3];
}
}
}
My question is how in that method can I discern which view was clicked? I've been doing it with those screen coordinates, but that won't work if I also move those views at runtime.
Is there a way to see which view was clicked in the touches or event or in this code from above:
UITouch *touch = [touches anyObject];
Any help appreciated // :)
Say you have a view controller with these ivars (connect to controls in Interface Builder)
IBOutlet UILabel *label;
IBOutlet UIImageView *image;
To tell if a touch hit these items or the background, view add this method to your view controller.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
{
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == label) {
NSLog(#"touched the label");
}
if ([touch view] == image) {
NSLog(#"touched the image");
}
if ([touch view] == self.view) {
NSLog(#"touched the background");
}
}
Any UIView subclass like a UIView, UILabel or UIImageView that you want to respond to touches must have the .userInteractionEnabled property set to YES.
[touch view] will give you the view in which the touch initially occured (i.e., this view will remain the same even if the user moves the finger away from the view during the touch).
If that is not the behavior you require, use:
[self.view hitTest:[touch locationInView:self.view] withEvent:event];
I might be missing something, but wouldn't your "menuX" elements have their own rects describing their sizes and locations? Then all you do is ask if the point is within those rectangles.
Why are you implementing your own hit-testing? It's trivial just to place transparent buttons wherever you want them.