In touchesBegan method i added stampBrush Image to drawImage where both are UIImageView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
stampBrush = [[UIImageView alloc] initWithImage:[[PaintColor stampImages] objectAtIndex:[stamp_Default integerForKey:STAMP_TYPE]]];
[stampBrush setFrame:CGRectMake(lastPoint.x, lastPoint.y, stampBrush.image.size.width,stampBrush.image.size.height)];
[drawImage addSubview:stampBrush];
}
Now i am trying to remove one by one on removeStampBrush clicked!
which stampBrush need to remove from drawImage!
-(void)removeStampBrush:(UIButton *)sender{
}
Since you want to remove the stamps in reverse order, I would extend UIImageView as follows:
YourImageView.h
#interface YourImageView : UIImageView {
NSMutableArray *stamps;
}
- (void)addStamp:(UIImageView *)stamp;
- (void)removeLastStamp;
#end
YourImageView.m
#import "YourImageView.h"
#implementation YourImageView
-(void)dealloc {
[stamps release];
[super dealloc];
}
- (void)addStamp:(UIImageView *)stamp {
if (stamps == nil) {
stamps = [[NSMutableArray array] retain];
}
[stamps addObject:stamp];
[self addSubview:stamp];
}
- (void)removeLastStamp {
if (stamps.count > 0) {
UIImageView *stamp = [stamps lastObject];
[stamp removeFromSuperview];
[stamps removeLastObject];
}
}
#end
Now from your touch event call [drawImage addStamp:stampBrush] and to remove the last one [drawImage removeLastStamp]
if([stampBrush superView])
{
[stampBrush removeFromSuperView];
}
Related
I have 2 images in a view and I applied a drag touch function to the images, and when the image collides with the image at the top of the view it gives you an alert and changes the image at the top of the view to a different image.
My problem is getting my if else statement to work, If i take out the == image in
([touch view] == image) {
Only one of the images drag, I cannot seem to get both images to drag. My if else statement has no errors, but does not seem to work.
frfViewController.h
#import <UIKit/UIKit.h>
#interface frfViewController : UIViewController {
UIImageView *image;
UIImageView *image2;
UIImageView *images;
UIImageView *collisionImage;
}
#property (nonatomic, retain) IBOutlet UIImageView *image;
#property (nonatomic, retain) IBOutlet UIImageView *image2;
#property (nonatomic, retain) IBOutlet UIImageView *collisionImage;
#property (nonatomic, retain) IBOutlet UIImageView *images;
#end
frfViewController.m
#import "frfViewController.h"
#interface frfViewController ()
#end
#implementation frfViewController
#synthesize image;
#synthesize image2;
#synthesize images;
#synthesize collisionImage;
- (void)viewDidLoad
{
}
- (void)viewWillAppear:(BOOL)animated
{
// [self.navigationController setNavigationBarHidden:YES animated:animated];
// [super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillDisappear:animated];
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if ([touch view] == image) {
image.center = location;
image.userInteractionEnabled = YES;
}
else if ([touch view] == image2) {
image2.center = location;
image2.userInteractionEnabled = YES;
}
[self ifCollided];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesBegan:touches withEvent:event];
}
-(void) ifCollided {
if (CGRectIntersectsRect(image.frame, collisionImage.frame) || CGRectIntersectsRect(image2.frame, collisionImage.frame)) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"image Collided"
message:#"FuckYea"
delegate:nil
cancelButtonTitle:#"Reset!"
otherButtonTitles:nil];
[alert show];
CGRect myImageRect = CGRectMake(0, 0, 320, 100);
images = [[UIImageView alloc] initWithFrame:myImageRect];
[images setImage:[UIImage imageNamed:#"004.jpg"]];
[self.view addSubview:images];
}
}
#end
Thanks any assistance is much appreciated.
From iOS 4 and up you can use UIPanGestureRecognizer to do dragging easily,
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self
action:#selector(labelDragged:)];
[yourview addGestureRecognizer:gesture];
Add recognizer to each UIView and set selector to point, where you set new coordinates = where you can limit it , if you get collision for example...
- (void)labelDragged:(UIPanGestureRecognizer *)gesture
{
UILabel *label = (UILabel *)gesture.view;
CGPoint translation = [gesture translationInView:label];
// move label , limit it to stay inside self.view.frame
float newx = label.center.x + translation.x;
float newy = label.center.y + translation.y;
if (newx<0) { newx = 0; }
if (newy<0) { newy = 0; }
if (newx>self.view.frame.size.width) {
newx = self.view.frame.size.width;
}
if (newy>self.view.frame.size.height) {
newy = self.view.frame.size.height;
}
//possibly compute collision here and limit new coordinates further
label.center = CGPointMake(newx,newy);
// reset translation
[gesture setTranslation:CGPointZero inView:label];
}
Also have a look at draggable&resizable View class at https://github.com/spoletto/SPUserResizableView , that may save you a bit of work also
I'm actually trying to insert touch delegate functions (type touchBegan:withEvent, or touchEnded:withEvent) inside a customScrollView class that implement gestureRecognizers.
When I try to set the delegate of the recognizer object to self, my SDK has a message of warning stating "incompatible type id ".
I understand that the delegate protocol of GestureRecognizer does not include such function, but I don't know which delegate I should trigger in order to use the aforesaid function inside my custom view.
Thank you very much for your responses
Victor-Marie
Here is my code:
#interface TapScrollView : UIScrollView {
// id<TapScrollViewDelegate> delegate;
NSMutableArray *classementBoutons;
int n;
int o;
//UIImageView *bouton;
}
//#property (nonatomic, assign) id<TapScrollViewDelegate> delegate;
//#property (nonatomic, retain) UIImageView *bouton;
//#property (strong, nonatomic) UIPanGestureRecognizer *bouton01pan;
-(id)init;
-(void)initierScrollView;
-(void) createGestureRecognizers;
-(IBAction)handlePanGesture:(UIPanGestureRecognizer*)sender;
#end
#import "TapScrollView.h"
#implementation TapScrollView
//#synthesize bouton;
- (void)setUpBoutonView {
// Create the placard view -- its init method calculates its frame based on its image
//boutonHome *aBoutonMain = [[boutonHome alloc] init];
//self.boutonMain = aBoutonMain;
//[boutonMain setCenter:CGPointMake(200, 200)];
//[self addSubview:boutonMain];
}
- (id) init
{
if (self = [super init])
{
NSLog(#"Classe TapScrollView initiƩe");
}
return self;
}
-(void)initierScrollView
{
int i;
for (i=0; i<6; i++) {
UIImage *image = [UIImage imageNamed:#"back.png"];
UIImageView *bouton = [[UIImageView alloc] initWithImage:image];
[bouton setTag:i];
[bouton setFrame:CGRectMake(72+20*i,10,62,55)];
[classementBoutons insertObject:bouton atIndex:i];
bouton.userInteractionEnabled = YES;
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGesture:)];
recognizer.delegate = self;
[bouton addGestureRecognizer:recognizer];
[self addSubview:bouton];
}
}
//- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//{
// UITouch *touch = [touches anyObject];
//[super touchesBegan:touches withEvent:event];
// for (o=1; o<6; o++) {
// if ([touch view] == [self viewWithTag:o])
// {
// UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:[classementBoutons objectAtIndex:o] action:#selector(handlePanGesture:)];
// [[classementBoutons objectAtIndex:o] addGestureRecognizer:recognizer];
// bouton01 = [self viewWithTag:o];
// }
// }
//CGPoint touchPoint = [touch locationInView:self];
//[self animateFirstTouchAtPoint:touchPoint];
// return;
//}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
for (n=0; n<6; n++) {
NSLog(#"touche cancelled");
[[classementBoutons objectAtIndex:n] setFrame:CGRectMake((72+20)*n,10,62,55)];
}
}
//- (id<TapScrollViewDelegate>) delegate {
// return (id<TapScrollViewDelegate>)super.delegate;
//}
//- (void) setDelegate:(id<TapScrollViewDelegate>) aDelegate
//{
// super.delegate = aDelegate;
//}
#define GROW_ANIMATION_DURATION_SECONDS 0.15
#define SHRINK_ANIMATION_DURATION_SECONDS 0.15
-(IBAction)handlePanGesture:(UIPanGestureRecognizer*)recognizer
{
NSLog(#"Mouvement ok");
CGPoint translation = [recognizer translationInView:self];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self];
}
#end
Try specifying:
#interface TapScrollView : UIScrollView <UIGestureRecognizerDelegate> {
In this way, your warning should disappear, although I have to admit I have not entirely clear what you are trying to accomplish, so there might be other problems.
I have looked at a few guides for CAKeyFrameAnimation and I am failing to see how to trigger them. The only thing I can think of is that I have to use it as a return, but that doesn't make much sense to me.
-H File-
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ImageSequenceViewController : UIViewController
<UIGestureRecognizerDelegate>{
UISwipeGestureRecognizer *swipeLeftRecognizer;
NSMutableArray *myImages;
IBOutlet UIImageView *imageView;
IBOutlet UIImageView *bView;
IBOutlet UISegmentedControl *segmentedControl;
}
#property (nonatomic, retain) UISwipeGestureRecognizer *swipeLeftRecognizer;
#property (nonatomic, retain) UIImageView *imageView;
#property (nonatomic, retain) IBOutlet UISegmentedControl *segmentedControl;
-(IBAction)takeLeftSwipeRecognitionEnabledFrom:(UISegmentedControl *)aSegmentedControl;
-(IBAction)ButtonPressed1: (id)sender;
#end
-M File-
#import "ImageSequenceViewController.h"
#implementation ImageSequenceViewController
#synthesize swipeLeftRecognizer;
#synthesize imageView;
#synthesize segmentedControl;
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
//CUSTOM CODE
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
-(void)loadLeft {
//aView = [[UIImageView alloc] initWithFrame:self.view.frame];
CALayer *layer = [CALayer layer];
[layer setFrame:CGRectMake(0.0,
0.0,
[[self view] frame].size.height,
[[self view] frame].size.width)];
myImages = [[NSMutableArray alloc] init];
for(NSUInteger count=0; count<100; count++){
NSString *fileName;
if (count < 10)
{
fileName = [NSString stringWithFormat:#"trailerRotation_000%d", count];
}
else if (10 <= count < 100)
{
fileName = [NSString stringWithFormat:#"trailerRotation_00%d", count];
}
else
{
fileName = [NSString stringWithFormat:#"trailerRotation_0%d", count];
}
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:#"jpg"];
//UIImage *image = [[UIImage alloc] initWithContentsOfFile:fileName];
//[myImages addObject:image];
[myImages addObject:[UIImage imageWithContentsOfFile:path]];
}
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"Contents"];
[anim setDuration:0.10];
[anim setCalculationMode:kCAAnimationDiscrete];
[anim setRepeatCount:1];
[anim setValues:myImages];
[self.view.layer addSublayer:layer];
[layer addAnimation:anim forKey:#"images"];
//aView.animationImages = myImages;
//aView.animationDuration = 10.00;
//aView.animationRepeatCount = 1;
}
-(void)loadRight {
bView = [[UIImageView alloc] initWithFrame:self.view.frame];
myImages = [[NSMutableArray alloc] init];
for(NSUInteger count=99; count>0; count--){
NSString *countString;
if (count < 10)
{
countString = #"000";
countString = [countString stringByAppendingFormat:#"%d", count];
}
else if (10 <= count < 100)
{
countString = #"00";
countString = [countString stringByAppendingFormat:#"%d", count];
}
else if (100 <= count < 1000)
{
countString = #"00";
countString = [countString stringByAppendingFormat:#"%d", count];
}
NSLog(#"%d", count);
NSString *fileName = #"trailerRotation_";
fileName = [fileName stringByAppendingFormat:countString];
fileName = [fileName stringByAppendingFormat:#".jpg"];
[myImages addObject:[UIImage imageNamed:fileName]];
}
bView.animationImages = myImages;
bView.animationDuration = 10.00;
bView.animationRepeatCount = 1;
}
- (void)viewDidLoad {
[super viewDidLoad];
imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
[imageView setImage:[UIImage imageNamed:#"trailerRotation_0000.jpg"]];
//[self.view addSubview:imageView];
[self loadLeft];
[self loadRight];
UIGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
self.swipeLeftRecognizer = (UISwipeGestureRecognizer *) recognizer;
swipeLeftRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
if ([segmentedControl selectedSegmentIndex] == 0) {
[self.view addGestureRecognizer:swipeLeftRecognizer];
}
self.swipeLeftRecognizer = (UISwipeGestureRecognizer *) recognizer;
[recognizer release];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.segmentedControl = nil;
self.swipeLeftRecognizer = nil;
self.imageView = nil;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)viewDidAppear:(BOOL)animated {
[self becomeFirstResponder];
}
-(void)startItLeft {
NSLog(#"Left");
//[aView startAnimating];
//[self.view addSubview:aView];
//[aView release];
[bView release];
}
-(void)startItRight {
NSLog(#"Right");
[bView startAnimating];
[self.view addSubview:bView];
//[aView release];
[bView release];
}
//- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
//}
//- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
//}
//- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
//}
-(IBAction)ButtonPressed1:(id)sender
{
NSLog(#"Button");
//[aView stopAnimating];
[bView stopAnimating];
//[self loadLeft];
[self loadRight];
}
-(IBAction)takeLeftSwipeRecognitionEnabledFrom:(UISegmentedControl *) aSegmentControl {
if ([aSegmentControl selectedSegmentIndex] == 0) {
[self.view addGestureRecognizer:swipeLeftRecognizer];
}
else {
[self.view removeGestureRecognizer:swipeLeftRecognizer];
}
}
-(void)handleSwipeFrom:(UISwipeGestureRecognizer *) recognizer {
//CGPoint location = [recognizer locationInView:self.view];
//[self showImageWithText:#"swipe" atPoint:location];
if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
//[self startItLeft];
}
else {
[self startItRight];
}
}
//CUSTOM CODE
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)dealloc {
[super dealloc];
}
#end
I'm rather new to iOS development so any advice is helpful.
Thanks.
Try:
[myImages addObject:(id)[UIImage imageWithContentsOfFile:path].CGImage];
Since the CAKeyFrameAnimation expects CGImageRef objects.
It looks like you're trying to load up 100 images and cycle them all within the space of 0.1 second. Not only is that pretty ridiculous (that's 1000fps right there, and CoreAnimation is capped at 60fps), but it's likely to take longer than 0.1 seconds for CoreAnimation to copy all the images before it even starts, which means that it will have finished before it started (and therefore no animation will occur).
I'll admit it was a PEBKAC error.
Thanks all for your help.
I have a problem with touchesBegan event.I displayed an image in an uiimageview.Am trying to detect the touches on that image by displaying small green color points on the image when i clicked on the image..
Am not getting any errors while running but the touches event is not firing.Here is my code:
#import <UIKit/UIKit.h>
#import "Second.h"
#interface pickerExampleViewController : UIViewController <UIImagePickerControllerDelegate>{
IBOutlet UIButton *selectPic;
}
#property (nonatomic,retain) UIButton *selectPic;
-(IBAction)getpic:(id)sender;
#end
#import "pickerExampleViewController.h"
#implementation pickerExampleViewController
#synthesize selectPic;
-(IBAction)getpic:(id)sender
{
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.delegate = self;
picker.editing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
[picker release];
}
#pragma mark imagePickerController delegate methods
-(void)imagePickerController:(UIImagePickerController *) picker
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
[picker dismissModalViewControllerAnimated:YES];
Second *secview = [[Second alloc] initWithNibName:#"Second" bundle:nil];
secview.view.backgroundColor = [UIColor blackColor];
[secview setImage:image];
[self.view addSubview:secview.view];
//[self presentModalViewController:secview animated:YES];
[secview release];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissModalViewControllerAnimated:YES];
}
#interface Second : UIViewController {
IBOutlet UIImageView *imgView;
UIImage *image1;
}
#property(nonatomic,retain) UIImageView *imgView;
-(void)setImage:(UIImage *)img;
-(IBAction)back;
#end
#import "Second.h"
#import <QuartzCore/QuartzCore.h>
#implementation Second
#synthesize imgView;
static int countoftouches,i;
CGPoint points[4];
-(void)setImage:(UIImage *)img
{
[imgView setImage:img];
countoftouches=0;
}
-(IBAction)back
{
[self.view removeFromSuperview];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//NSSet *allTouches = [event allTouches];
if ([touch view] != imgView) {
return;
}
countoftouches++;
CGPoint point = [touch locationInView:imgView];
NSLog(#"x: %f, y: %f", point.x, point.y);
CGRect frame=CGRectMake(point.x, point.y, 5, 5);
if(countoftouches<=4)
{
points[i] = frame.origin;
i++;
UIButton *btn=[[UIButton alloc]initWithFrame:frame];
[btn setBackgroundColor:[UIColor greenColor]];
[imgView addSubview:btn];
[btn release];
}
}
-(void)dealloc
{
[imgView release];
[super dealloc];
}
#end
You need to set userInteractionEnabled to YES.. On youre UIImageView that is.. So:
imgView.userInteractionEnable = YES;
I have successfully integrated the three20 framework in my project,
and I have extended the TTPhotoViewController to add some further
functionality.
Now I need to add some subviews to the TTPhotoView loaded by the
TTPhotoViewController. In particular I would like to add that subviews
after every TTPhotoView as been loaded. These subviews represents
sensible area over the image so they should scale proportionally with
the image.
The user can tap a subview to get extra info about the image.
I don't know how to implement this behavior. Should I extend the
TTPhotoView and make sure that the TTPhotoViewController use this
extended version instead of its TTPhotoView?
Could someone point me to the right direction?
Thank you
Solved subclassing the TTPhotoView (TapDetectingPhotoView) and then adding all my subviews to that subclass.
The main problem was represented by the photo switching, because the TTPhotoViewController (in particular its inner TTScrollView) reuse the TTPhotoView during switching operation.
So for example if you add your subview to your TTPhotoView subclass and try to switch to the next photo, your subview will probably be here, because the TTPhotoView is reused.
To solve this problem I decided to add and remove all my subviews every time a photo switch occur (see TTPhotoViewController::didMoveToPhoto).
In this way I'm sure that every photoview has its subviews.
Here my implementation (only remarkable methods)
Hope these help!
PhotoViewController.h:
#import "TapDetectingPhotoView.h"
#interface PhotoGalleryController : TTPhotoViewController <TTScrollViewDelegate, TapDetectingPhotoViewDelegate> {
NSArray *images;
}
#property (nonatomic, retain) NSArray *images;
#end
PhotoViewController.m:
#import "PhotoGalleryController.h"
#implementation PhotoGalleryController
#synthesize images;
- (void)viewDidLoad { // fill self.images = ... }
- (TTPhotoView*)createPhotoView {
TapDetectingPhotoView *photoView = [[TapDetectingPhotoView alloc] init];
photoView.tappableAreaDelegate = self;
return [photoView autorelease];
}
#pragma mark -
#pragma mark TTPhotoViewController
- (void)didMoveToPhoto:(id<TTPhoto>)photo fromPhoto:(id<TTPhoto>)fromPhoto {
[super didMoveToPhoto:photo fromPhoto:fromPhoto];
TapDetectingPhotoView *previousPhotoView = (TapDetectingPhotoView *)[_scrollView pageAtIndex:fromPhoto.index];
TapDetectingPhotoView *currentPhotoView = (TapDetectingPhotoView *)[_scrollView pageAtIndex:photo.index];
// destroy the sensible areas from the previous photoview, because the photo could be reused by the TTPhotoViewController!
if (previousPhotoView)
previousPhotoView.sensibleAreas = nil;
// if sensible areas has not been already created, create new
if (currentPhotoView && currentPhotoView.sensibleAreas == nil) {
currentPhotoView.sensibleAreas = [[self.images objectAtIndex:photo.index] valueForKey:#"aMap"];
[self showSensibleAreas:YES animated:YES];
}
}
#pragma mark -
#pragma mark TappablePhotoViewDelegate
// show a detail view when a sensible area is tapped
- (void)tapDidOccurOnSensibleAreaWithId:(NSUInteger)ids {
NSLog(#"SENSIBLE AREA TAPPED ids:%d", ids);
// ..push new view controller...
}
TapDetectingPhotoView.h:
#import "SensibleAreaView.h"
#protocol TapDetectingPhotoViewDelegate;
#interface TapDetectingPhotoView : TTPhotoView <SensibleAreaViewDelegate> {
NSArray *sensibleAreas;
id <TapDetectingPhotoViewDelegate> tappableAreaDelegate;
}
#property (nonatomic, retain) NSArray *sensibleAreas;
#property (nonatomic, assign) id <TapDetectingPhotoViewDelegate> tappableAreaDelegate;
#end
#protocol TapDetectingPhotoViewDelegate <NSObject>
#required
- (void)tapDidOccurOnSensibleAreaWithId:(NSUInteger)ids;
#end
TapDetectingPhotoView.m:
#import "TapDetectingPhotoView.h"
#interface TapDetectingPhotoView (Private)
- (void)createSensibleAreas;
#end
#implementation TapDetectingPhotoView
#synthesize sensibleAreas, tappableAreaDelegate;
- (id)init {
return [self initWithSensibleAreas:nil];
}
- (id)initWithFrame:(CGRect)frame {
return [self initWithSensibleAreas:nil];
}
// designated initializer
- (id)initWithSensibleAreas:(NSArray *)areasList {
if (self = [super initWithFrame:CGRectZero]) {
self.sensibleAreas = areasList;
[self createSensibleAreas];
}
return self;
}
- (void)setSensibleAreas:(NSArray *)newSensibleAreas {
if (newSensibleAreas != self.sensibleAreas) {
// destroy previous sensible area and ensure that only sensible area's subviews are removed
for (UIView *subview in self.subviews)
if ([subview isMemberOfClass:[SensibleAreaView class]])
[subview removeFromSuperview];
[newSensibleAreas retain];
[sensibleAreas release];
sensibleAreas = newSensibleAreas;
[self createSensibleAreas];
}
}
- (void)createSensibleAreas {
SensibleAreaView *area;
NSNumber *areaID;
for (NSDictionary *sensibleArea in self.sensibleAreas) {
CGFloat x1 = [[sensibleArea objectForKey:#"nX1"] floatValue];
CGFloat y1 = [[sensibleArea objectForKey:#"nY1"] floatValue];
area = [[SensibleAreaView alloc] initWithFrame:
CGRectMake(
x1, y1,
[[sensibleArea objectForKey:#"nX2"] floatValue]-x1, [[sensibleArea objectForKey:#"nY2"] floatValue]-y1
)
];
areaID = [sensibleArea objectForKey:#"sId"];
area.ids = [areaID unsignedIntegerValue]; // sensible area internal ID
area.tag = [areaID integerValue];
area.delegate = self;
[self addSubview:area];
[area release];
}
}
// to make sure that if the zoom factor of the TTScrollView is > than 1.0 the subviews continue to respond to the tap events
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *result = nil;
for (UIView *child in self.subviews) {
CGPoint convertedPoint = [self convertPoint:point toView:child];
if ([child pointInside:convertedPoint withEvent:event]) {
result = child;
}
}
return result;
}
#pragma mark -
#pragma mark TapDetectingPhotoViewDelegate methods
- (void)tapDidOccur:(SensibleAreaView *)aView {
NSLog(#"tapDidOccur ids:%d tag:%d", aView.ids, aView.tag);
[tappableAreaDelegate tapDidOccurOnSensibleAreaWithId:aView.ids];
}
SensibleAreaView.h:
#protocol SensibleAreaViewDelegate;
#interface SensibleAreaView : UIView {
id <SensibleAreaViewDelegate> delegate;
NSUInteger ids;
UIButton *disclosureButton;
}
#property (nonatomic, assign) id <SensibleAreaViewDelegate> delegate;
#property (nonatomic, assign) NSUInteger ids;
#property (nonatomic, retain) UIButton *disclosureButton;
#end
#protocol SensibleAreaViewDelegate <NSObject>
#required
- (void)tapDidOccur:(SensibleAreaView *)aView;
#end
SensibleAreaView.m:
#import "SensibleAreaView.h"
#implementation SensibleAreaView
#synthesize delegate, ids, disclosureButton;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.userInteractionEnabled = YES;
UIColor *color = [[UIColor alloc] initWithWhite:0.4 alpha:1.0];
self.backgroundColor = color;
[color release];
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self action:#selector(buttonTouched) forControlEvents:UIControlEventTouchUpInside];
CGRect buttonFrame = button.frame;
// set the button position over the right edge of the sensible area
buttonFrame.origin.x = frame.size.width - buttonFrame.size.width + 5.0f;
buttonFrame.origin.y = frame.size.height/2 - 10.0f;
button.frame = buttonFrame;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin |UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
self.disclosureButton = button;
[self addSubview:button];
// notification used to make sure that the button is properly scaled together with the photoview. I do not want the button looks bigger if the photoview is zoomed, I want to preserve its default dimensions
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(zoomFactorChanged:) name:#"zoomFactorChanged" object:nil];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if ([[touches anyObject] tapCount] == 1)
[delegate tapDidOccur:self];
}
- (void)buttonTouched {
[delegate tapDidOccur:self];
}
- (void)zoomFactorChanged:(NSNotification *)message {
NSDictionary *userInfo = [message userInfo];
CGFloat factor = [[userInfo valueForKey:#"zoomFactor"] floatValue];
BOOL withAnimation = [[userInfo valueForKey:#"useAnimation"] boolValue];
if (withAnimation) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.18];
}
disclosureButton.transform = CGAffineTransformMake(1/factor, 0.0, 0.0, 1/factor, 0.0, 0.0);
if (withAnimation)
[UIView commitAnimations];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"zoomFactorChanged" object:nil];
[disclosureButton release];
[super dealloc];
}
Some ideas:
Subclass TTPhotoView, then override createPhotoView in your TTPhotoViewController:
- (TTPhotoView*)createPhotoView {
return [[[MyPhotoView alloc] init] autorelease];
}
Try overriding a private method (yes, bad practice, but hey) setImage: in TTPhotoView subclass:
- (void)setImage:(UIImage*)image {
[super setImage:image]
// Add a subview with the frame of self.view, maybe?..
//
// Check for self.isLoaded (property of TTImageView
// which is subclassed by TTPhotoView) to check if
// the image is loaded
}
In general, look at the headers and implementations (for the private methods) of TTPhotoViewController and TTPhotoView. Set some breakpoints to figure out what does what :)
Interesting question. Facebook has a similar functionality with their tags. Their tags do not scale proportionally with the image. In fact, they do not even show the tags if you have zoomed. I don't know if this will help you, but I would look at how (if) three20 handles tags and then maybe try to extend that.