2010-06-07 17 views
5

Ho integrato con successo il framework three20 nel mio progetto, e ho esteso il TTPhotoViewController per aggiungere ulteriori funzionalità .Estendi TTPhotoViewController con TTPhotoView personalizzato

Ora ho bisogno di aggiungere alcuni sottoview al TTPhotoView caricato dal TTPhotoViewController . In particolare, vorrei aggiungere le sottoview dopo ogni TTPhotoView caricato. Queste sottoview rappresentano l'area sensibile sull'immagine in modo che si ridimensionino proporzionalmente con l'immagine . L'utente può toccare una sottoview per ottenere ulteriori informazioni sull'immagine.

Non so come implementare questo comportamento. Devo estendere il TTPhotoView e assicurarmi che il TTPhotoViewController utilizzi questa versione estesa invece di TTPhotoView?

Qualcuno potrebbe indicarmi la direzione giusta? Grazie

risposta

5

Risolto sottoclasse il TTPhotoView (TapDetectingPhotoView) e quindi aggiungere tutti i miei subviews a tale sottoclasse. Il problema principale era rappresentato dal cambio di foto, poiché TTPhotoViewController (in particolare il suo TTScrollView interno) riutilizzava TTPhotoView durante l'operazione di commutazione. Quindi, ad esempio, se aggiungi la sottoview alla sottoclasse TTPhotoView e provi a passare alla foto successiva, la tua sottoview sarà probabilmente qui, perché TTPhotoView viene riutilizzato. Per risolvere questo problema ho deciso di aggiungere e rimuovere tutte le mie sottoview ogni volta che si verifica un cambio di foto (vedere TTPhotoViewController :: didMoveToPhoto). In questo modo sono sicuro che ogni vista panoramica ha le sue sottoview.

Qui la mia implementazione (solo metodi notevoli) Spero che questo aiuto!

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

Interessante domanda. Facebook ha una funzionalità simile con i loro tag. I tag non vengono ridimensionati proporzionalmente all'immagine. In realtà, non mostrano nemmeno i tag se hai ingrandito. Non so se questo ti sarà d'aiuto, ma guarderei come (se) tre20 maneggia i tag e poi forse cercherò di estenderlo.

1

Alcune idee:

sottoclasse TTPhotoView, poi sovrascrivere createPhotoView nel TTPhotoViewController:

- (TTPhotoView*)createPhotoView { 
    return [[[MyPhotoView alloc] init] autorelease]; 
} 

Prova l'override un metodo privato (sì, cattiva pratica, ma hey) setImage: in TTPhotoView sottoclasse:

- (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 generale, guarda le intestazioni e implementazioni (per i metodi privati) di TTPhotoViewController e TTPhotoView. Impostare alcuni punti di interruzione per capire cosa fa cosa :)