Extend TTPhotoViewController with custom TTPhotoView - iphone

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.

Related

Getting 2 Images to Drag in View Xcode

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

Activating UIImageView with GestureRecognizer in a ScrollView

I,
I'm currently trying to implement a Gesture recognizer into a ScrollView.
I first created a custom ScrollView in which I integrated ImageView object.
When the user clicks on a ImageView, normally the PanGestureRecognizer activates and the ImageView object follow the move on the screen.
I have read and followed the instructions on Gesture Recognizer and the Raywenderlich blog (which is very well done).
If someone has a clue of what is missing in my code, I would be happy to read it
Thank in advance. Here is my code
#import <Foundation/Foundation.h>
#import "mainInterface03.h"
#import <QuartzCore/QuartzCore.h>
#import "boutonHome.h"
#import "DragGestureRecognizer.h"
#class boutonHome;
#class DragGestureRecognizer;
#interface TapScrollView : UIScrollView {
// id<TapScrollViewDelegate> delegate;
NSMutableArray *classementBoutons;
int n;
int o;
UIView *bouton01;
}
#property (nonatomic, retain) UIView *bouton01;
#property (retain, nonatomic) IBOutletCollection(UIButton) NSMutableSet* buttons;
-(id)init;
-(void)initierScrollView;
-(void) createGestureRecognizers;
-(IBAction)handlePanGesture:(UIPanGestureRecognizer*)sender;
#end
m.file
#import "TapScrollView.h"
#implementation TapScrollView
#synthesize bouton01;
- (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*i+20,10,62,55)];
[classementBoutons insertObject:bouton atIndex:i];
[self addSubview:bouton];
}
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:bouton01 action:#selector(handlePanGesture:)];
[bouton01 addGestureRecognizer:recognizer];
}
- (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])
{
bouton01 = [self viewWithTag:o];
}
}
return;
}
-(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
I am not sure if this setup can work. Essentially, you are assigning whatever view has been touched to bouton01, which carries the gesture recognizer. Seems a bit convoluted to me, and also your code is not so efficient.
It seems that when you call [super touchesBegan:touches withEvent:event]; it will pass the touch up the view hierarchy. Only after that do make the assignment to bouton01. So it would seem logical that bouton01 never receives a touch event.
Indeed, it is because of this strange approach of iterating through the views and assigning it the one that has the recognizer that this error arose. I would suggest to assign the same recognizer to all concerned views during setup.

Drag and drop images from toolbar to view canvas

I want to make a app where I need to have a toolbar. The toolbar will have various number of objects (images). These objects should be draggable and placed on view right above it.
This is a kind of drawing app where user can pick any shape and place on canvas. Can anyone tell me the best to achieve this ?
Thanks in advance.
Tough one.
What I would do is make each item on the toolbar a UIView and override touchesBegan, touchesEnded, and touchesMoved. Make your canvas another UIView. When a user clicks an item to drag, register that item somewhere, say a square. then when they drop on the canvas, draw that square at that location. To make it look pretty, would probably make a UIImageView with an alpha of like .4 to move with the user's touch, so they know what they are dragging, and where it will land.
Here is the code.
UIViewController.h
#class ToolBox;
#interface ViewController : UIViewController {
IBOutlet UIView *canvas;
IBOutlet ToolBox *toolBox;
}
#property (nonatomic, retain) UIView *canvas;
#property (nonatomic, retain) ToolBox *toolBox;
#end
UIViewController.m
#import "ViewController.h"
#import "ToolBox.h"
#import "Tool.h"
#implementation ViewController
#synthesize canvas, toolBox;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[self toolBox] setCanvas:[self canvas]];
Tool *tool = [[[Tool alloc] initWithFrame:CGRectMake(0,0,64,64)] autorelease];
[tool setImageView:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"1.png"]] autorelease]];
[tool setImage:[UIImage imageNamed:#"1.png"]];
[tool addSubview:[tool imageView]];
[tool setToolBox:[self toolBox]];
[[self toolBox] addObject:tool];
}
#end
ToolBox.h
#class Tool;
#interface ToolBox : UIView {
NSMutableArray *tools;
UIView *canvas;
UIImage *currentTool;
}
#property (nonatomic, retain) UIImage *currentTool;
#property (nonatomic, retain) NSMutableArray *tools;
#property (nonatomic, retain) UIView *canvas;
-(void)addObject:(Tool *)newTool;
-(void)updatePositions;
#end
ToolBox.m
#implementation ToolBox
#synthesize tools, canvas, currentTool;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
-(NSMutableArray *)tools {
if(tools == nil) {
[self setTools:[NSMutableArray array]];
}
return tools;
}
-(void)addObject:(Tool *)newTool {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(draggingTool:) name:#"Dragging New Tool" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(draggedTool:) name:#"Dragged Tool To" object:nil];
[[self tools] addObject:newTool];
[self updatePositions];
}
-(void)updatePositions {
int x = 0;
int y = 0;
int width = 64;
int height = 64;
for(Tool *button in [self tools]) {
[button setFrame:CGRectMake(x, y, width, height)];
x += width;
[self addSubview:button];
}
}
-(void)draggingTool:(NSNotification *)notif {
NSDictionary *dict = [notif userInfo];
UIImage *image = [dict valueForKey:#"Image"];
[self setCurrentTool:image];
}
-(void)draggedTool:(NSNotification *)notif {
UITouch *touch = [[notif userInfo] valueForKey:#"Touch"];
CGPoint point = [touch locationInView:canvas];
UIImageView *imageView = [[[UIImageView alloc] initWithImage:currentTool] autorelease];
[imageView setCenter:point];
[canvas addSubview:imageView];
}
#end
Tool.h
#class ToolBox;
#interface Tool : UIView {
UIImageView *imageView;
UIImage *image;
UIImageView *ghostImageView;
ToolBox *toolBox;
}
#property (nonatomic, retain) UIImageView *imageView;
#property (nonatomic, retain) UIImage *image;
#property (nonatomic, retain) UIImageView *ghostImageView;
#property (nonatomic, retain) ToolBox *toolBox;
#end
Tool.m
#import "Tool.h"
#import "ToolBox.h"
#implementation Tool
#synthesize imageView, image, ghostImageView, toolBox;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"tool touches began");
NSDictionary *dict = [NSDictionary dictionaryWithObject:[self image] forKey:#"Image"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"Dragging New Tool" object:nil userInfo:dict];
UITouch *touch = [touches anyObject];
CGPoint center = [touch locationInView:[[self toolBox] canvas]];
[self setGhostImageView:[[[UIImageView alloc] initWithImage:[self image]] autorelease]];
[[self ghostImageView] setCenter:center];
[[[self toolBox] canvas] addSubview:[self ghostImageView]];
[[self ghostImageView] setAlpha:.4];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"tool touches ended");
NSDictionary *dict = [NSDictionary dictionaryWithObject:[touches anyObject] forKey:#"Touch"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"Dragged Tool To" object:nil userInfo:dict];
[self setGhostImageView:nil];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"tool touch moved");
if([self ghostImageView] != nil) {
UITouch *touch = [touches anyObject];
CGPoint center = [touch locationInView:[[self toolBox] canvas]];
NSLog(#"Ghost : %2f, %2f", center.x, center.y);
[[self ghostImageView] setCenter:center];
}
}
#end
My Program came out like this -
Initial screen: The tool is ready to be dragged and dropped onto the canvas
Dropped the tool on the canvas
And here is the ghost for the transition
I'm not exactly sure how this would be implemented in objective c, but I have done almost exactly what you are describing in java. Basically, when you begin to drag the object in the toolbar, it will recognize the action and store a new instance of the item in what I call a transfer container, which is basically a global static variable. That way when the drag action competes (I.e. drops) you can just grab that object from the container and add it to wherever it was dropped.

CALayer delegate callbacks in a UITableViewCell - Workflow

I'm using several CALayers to draw my content in a UITableViewCell subclass. The actual drawing is supposed to happen by calling the CALayer delegate method drawLayer:inContext:. However the delegate methods never gets called.
Here is my structure:
CustomCell: UITalbeViewCell
creates CustomCellContentView: UIView
creates CABackgroundLayer: CALayer
creates CATextLayer: CALayer
creates CALayerDelegate: NSObject
Each customCell has a customContentView, which holds all the CALayers for drawing.
Each customCell creates a caLayerDelegate for the CALayers to call. The caLayerDelegate reports back to the customCell.
CustomCell:
#define CALAYER_TEXTLAYER_NAME #"CATextLayer"
#define CALAYER_BGLAYER_NAME #"CABackgroundLayer"
...
- (id) customContentViewForCurrentCell
{
CGRect contentViewFrame = CGRectMake(-CC_LEFTRIGHT_PADDING, 0., self.contentView.bounds.size.width, self.contentView.bounds.size.height);
CustomCellContentView *cellContentView = [[[CustomCellContentView alloc] initWithFrame: contentViewFrame] autorelease];
CALayerDelegate *layerDelegate = [[CALayerDelegate alloc] initWithView: self];
cellContentView.layerDelegate = layerDelegate;
[cellContentView setupSubLayers];
[layerDelegate release];
return cellContentView;
}
#pragma mark - Initialisation
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (!self)
return nil;
self.customContentView = (CustomCellContentView *)[self customContentViewForCurrentCell];
self.customContentView.opaque = TRUE;
self.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self.contentView addSubview: self.customContentView];
return self;
}
#pragma mark - Cell Update
- (void) refreshLayout
{
[self setNeedsDisplay];
[self.customContentView setNeedsDisplay];
}
...
#pragma mark - CALayer Delegate Methods
-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context
{
}
-(void) drawCABackgroundLayer: (CALayer*) layer inContext: (CGContextRef) context
{
UIGraphicsPushContext(context);
CGRect contentRect = [layer bounds];
UIImage *bgImage = [[ImageCacheController sharedImageCache] imageFromCache: GENERIC_BGIMAGE_FILENAME];
[bgImage drawInRect: CGRectMake(contentRect.origin.x, contentRect.origin.y, contentRect.size.width, contentRect.size.height)];
UIGraphicsPopContext();
}
-(void) drawCATextLayer: (CALayer*) layer inContext: (CGContextRef) context
{
UIGraphicsPushContext(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.f, 2.0f), 0.0f, [UIColor mainLabelShadowColor].CGColor);
[[UIColor mainLabelColor] set];
UIFont *mainFont = [UIFont fontWithName: FONT_INFOS size: CC_MAINLABEL_FONTSIZE_MAX];
[#"ArthurDent" drawAtPoint: [self mainViewPosition]
forWidth: CC_MAINLABEL_WIDTH
withFont: mainFont
minFontSize: CC_MAINLABEL_FONTSIZE_MAX
actualFontSize: NULL
lineBreakMode: UILineBreakModeTailTruncation
baselineAdjustment: UIBaselineAdjustmentAlignBaselines];
UIGraphicsPopContext();
}
CustomCellContentView:
#interface CustomCellContentView : UIView
{
CALayerDelegate *layerDelegate;
CALayer *backgroundLayer;
CALayer *textLayer;
}
#property (nonatomic, retain) CALayerDelegate *layerDelegate;
#property (nonatomic, retain) CALayer *backgroundLayer;
#property (nonatomic, retain) CALayer *textLayer;
- (void) setupSubLayers;
#end
#implementation CustomCellContentView
#synthesize textLayer, backgroundLayer, layerDelegate;
#pragma mark - Initialisation
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame: frame];
if(!self)
return nil;
return self;
}
- (void) setupSubLayers
{
self.textLayer = [CALayer layer];
self.textLayer.name = CALAYER_TEXTLAYER_NAME;
self.textLayer.shadowColor = [UIColor mainLabelShadowColor].CGColor;
self.textLayer.shadowOffset = CGSizeMake(0.0f, 2.0f);
self.textLayer.shadowOpacity = 1.f;
self.textLayer.shadowRadius = 0.f;
self.textLayer.needsDisplayOnBoundsChange = TRUE;
self.textLayer.delegate = self.layerDelegate;
self.backgroundLayer = [CALayer layer];
self.backgroundLayer.name = CALAYER_BGLAYER_NAME;
self.backgroundLayer.needsDisplayOnBoundsChange = TRUE;
self.backgroundLayer.delegate = self.layerDelegate;
[self.layer addSublayer: self.textLayer];
[self.layer addSublayer: self.backgroundLayer];
[self.textLayer setNeedsDisplay];
[self.backgroundLayer setNeedsDisplay];
}
#pragma mark - SetNeedsDisplay Overwritten
- (void) setNeedsDisplay
{
[super setNeedsDisplay];
[self.layer setNeedsDisplay];
[self.textLayer setNeedsDisplay];
[self.backgroundLayer setNeedsDisplay];
}
...
CALayerDelegate:
#implementation CALayerDelegate
#pragma mark - Initialisation
-(id) initWithView: (UIView *) view
{
self = [super init];
if (!self)
return nil;
_view = view;
return self;
}
#pragma mark - CALayer Delegate Methods
-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context
{
NSString* methodName = [NSString stringWithFormat: #"draw%#:inContext:", [layer name]];
SEL selector = NSSelectorFromString(methodName);
if (![_view respondsToSelector: selector])
selector = #selector(drawLayer:inContext:);
[_view performSelector: selector
withObject: layer
withObject: (id)context];
}
#end
I've read for UIViewController it is better to create sub-CALayers in awakeFromNib: and not in initWithFrame:, because there is some form of layer - backing happening after the initWithFrame:, which will discard the creation of the sublayers. So, you should only add sublayers after the view is loaded?
I use seperate CALayerDelegate - objects, so the CustomCell and its view are only responsible for the customContentView.layer.
Anyone knows, what I'm doing wrong?
Thanks in advance!!
From the documentation for CALayer describing the 'delegate' property: 'In iOS, if the layer is associated with a UIView object, this property must be set to the view that owns the layer'.
If I read that correctly then you need to set CustomCellContentView as the layer delegate. Move the functionality from CALayerDelegate directly into your custom view class and see if that works. That would be the standard way to do it anyway, rather than creating a separate class just to act as a delegate.
Check that your frame is not CGRectZero.
I had a similar issue to what you describe. If the frame is CGRectZero this will prevent the drawLayer:inContext from being called.

photo gallery uiscrollView scrolling and zooming

HI i'm tring to create photogallery with two scrollviews
one for horizontal scrolling between images and second for zooming images.
scrolling between images works fine but i'm not able to zoom image into second scrollView.
mainScrollView named VcLicences
VcLicences.h
#import <UIKit/UIKit.h>
#interface VcLicences : UIViewController <UIScrollViewDelegate>{
IBOutlet UIScrollView* scrollView;
IBOutlet UIPageControl* pageControl;
BOOL pageControlIsChangingPage;
}
#property (nonatomic, retain) UIView *scrollView;
#property (nonatomic, retain) UIPageControl* pageControl;
/* for pageControl */
- (IBAction)changePage:(id)sender;
/* internal */
- (void)setupPage;
#end
VcLicences.m
#import "VcLicences.h"
#import "VcImageZoomView.h"
#implementation VcLicences
#synthesize scrollView;
#synthesize pageControl;
- (void)setupPage
{
scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor whiteColor]];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleBlack;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.multipleTouchEnabled = NO;
NSUInteger nim = 0;
CGFloat cx = 0;
NSArray *licence = [NSArray arrayWithObjects:#"zl1.jpg", #"zl2.jpg", #"zl3.jpg", #"dph.jpg", #"or.jpg", nil];
for (nim=0; nim < [licence count]; nim++)
{
VcImageZoomView *imageZoom = [[VcImageZoomView alloc] initWithNibName:#"VcImageZoomView" bundle:nil];
[imageZoom.view setFrame:CGRectMake(cx, 0, 320, 332)];
[imageZoom setMyImage:[licence objectAtIndex:nim]];
[scrollView addSubview:imageZoom.view];
[imageZoom release];
cx += scrollView.frame.size.width;
}
self.pageControl.numberOfPages = nim;
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
#pragma mark UIScrollViewDelegate stuff
- (void)scrollViewDidScroll:(UIScrollView *)_scrollView
{
if (pageControlIsChangingPage)
{
return;
}
CGFloat pageWidth = _scrollView.frame.size.width;
int page = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView
{
pageControlIsChangingPage = NO;
}
- (IBAction)changePage:(id)sender
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlIsChangingPage = YES;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
self.navigationItem.title = #"CZECHMAT's licenses";
[self setupPage];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
//[scrollView release];
//[pageControl release];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (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.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
//return (interfaceOrientation == UIInterfaceOrientationPortrait);
return YES;
}
#end
second ScrollView for zooming images named VcImageZoomView
VcImageZoomView.h
#import <UIKit/UIKit.h>
#interface VcImageZoomView : UIViewController <UIScrollViewDelegate>{
IBOutlet UIScrollView *scroll;
UIImageView *image;
}
#property (nonatomic, retain) UIScrollView *scroll;
-(void)setMyImage:(NSString *) imageName;
#end
VcImageZoomView.m
#import "VcImageZoomView.h"
#implementation VcImageZoomView
#synthesize scroll;
-(void)setMyImage:(NSString *) imageName;
{
NSLog(#"%#", imageName);
image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
float scaleWidth = scroll.frame.size.width / image.frame.size.width;
float scaleHeight = scroll.frame.size.height / image.frame.size.height;
float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
NSLog(#"%f", scale);
[scroll addSubview:image];
scroll.minimumZoomScale = scale;
scroll.maximumZoomScale = 1.0;
scroll.delegate = self;
[scroll setZoomScale:scroll.minimumZoomScale];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[super dealloc];
}
- (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.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return image;
}
#end
thx for way
You really need to look at Apple's PhotoViewer sample and the WWDC'10 and '11 videos about ScrollViews: they are explaining in details (with this very example of a photoviewer scrolling and zooming) how to implement it:
How to recycle memory so that your memory footprint is drastically reduced (very important for fluidity)
How to handle both scrolling in one view and zooming in the other
If needed, how to do image tiling to optimize memory when zooming (only useful if you tiling is precomputed, so if you have images in your bundle anyway)
This is very interesting tutorials and videos and really worth reading/viewing.
https://github.com/doubleencore/KTPhotoBrowser
find above attached link get source code for photo gallery .....