2010-06-07 5 views
5

Ich habe das Framework three20 in meinem Projekt erfolgreich integriert, , und ich habe den TTPhotoViewController erweitert, um weitere Funktionen hinzuzufügen.TTPhotoViewController mit benutzerdefiniertem TTPhotoView erweitern

Nun muss ich einige TTShotView hinzufügen, die von der TTPhotoViewController geladen werden. Insbesondere möchte ich die Subviews nach jedem Laden von TTPhotoView hinzufügen. Diese Subviews repräsentieren sensiblen Bereich über das Bild, so dass sie proportional mit das Bild skalieren sollten. Der Benutzer kann auf eine Unteransicht tippen, um zusätzliche Informationen über das Bild zu erhalten.

Ich weiß nicht, wie dieses Verhalten zu implementieren. Sollte ich die TTPhotoView erweitern und sicherstellen, dass der TTPhotoViewController diese erweiterte Version anstelle seiner TTPhotoView verwendet?

Könnte mir jemand in die richtige Richtung? Danke

Antwort

5

die TTPhotoView Gelöst Subklassen (TapDetectingPhotoView) und dann das Hinzufügen alle meine Subviews zu dieser Unterklasse. Das Hauptproblem wurde durch die Fotoumschaltung dargestellt, weil der TTPhotoViewController (insbesondere seine innere TTScrollView) das TTPhotoView während des Switching-Vorgangs wieder verwendet. Wenn Sie beispielsweise Ihre Unteransicht zu Ihrer TTPhotoView-Unterklasse hinzufügen und versuchen, zum nächsten Foto zu wechseln, wird Ihre Unteransicht wahrscheinlich hier sein, weil TTPhotoView erneut verwendet wird. Um dieses Problem zu lösen, habe ich beschlossen, alle meine Unteransichten jedes Mal hinzuzufügen und zu entfernen, wenn ein Fotowechsel stattfindet (siehe TTPhotoViewController :: didMoveToPhoto). Auf diese Weise bin ich sicher, dass jede Fotoansicht ihre Unteransichten hat.

Hier meine Implementierung (nur bemerkenswerte Methoden) Hoffen, dass diese Hilfe!

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 Frage. Facebook hat eine ähnliche Funktionalität mit ihren Tags. Ihre Tags skalieren nicht proportional zum Bild. Tatsächlich zeigen sie die Tags nicht einmal an, wenn Sie gezoomt haben. Ich weiß nicht, ob dir das weiterhilft, aber ich würde mir ansehen, wie (falls) three20 Tags behandelt und dann vielleicht versucht, das zu erweitern.

1

Einige Ideen:

Subclass TTPhotoView, dann createPhotoView in Ihrem außer Kraft setzen TTPhotoViewController:

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

Versuchen Sie, eine private Methode überschrieben (ja, schlechte Praxis, aber hey) setImage: in TTPhotoView Unterklasse:

- (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 
} 

Im allgemeinen Blick auf die Header und Implementierungen (für die privaten Methoden) von TTPhotoViewController und TTPhotoView. Legen Sie einige Haltepunkte, um herauszufinden, was das tut, was :)