2010-06-07 106 views
5

我已經成功地將three20框架集成到了我的項目中,並且我已經擴展了TTPhotoViewController以添加一些其他 功能。使用自定義TTPhotoView擴展TTPhotoViewController

現在我需要添加一些子視圖到TTPhotoView由 加載TTPhotoViewController。特別是我想在加載每個TTPhotoView之後添加子視圖 。這些子視圖代表圖像上的合理區域 ,因此它們應該按比例與 圖像成比例。 用戶可以點擊子視圖以獲取有關圖像的額外信息。

我不知道如何實現這種行爲。我應該擴展 TTPhotoView並確保TTPhotoViewController使用此 擴展版本而不是其TTPhotoView?

難道有人指着我正確的方向嗎? 謝謝

回答

5

解決子類化TTPhotoView(TapDetectingPhotoView),然後將所有我的子視圖添加到該子類。 主要問題是由照片切換代表的,因爲TTPhotoViewController(特別是其內部的TTScrollView)在切換操作期間重用了TTPhotoView。 因此,例如,如果您將子視圖添加到TTPhotoView子類並嘗試切換到下一張照片,則您的子視圖可能會在此處,因爲TTPhotoView會被重用。 爲了解決這個問題,我決定添加和刪除所有我的子視圖每次發生照片切換(請參閱TTPhotoViewController :: didMoveToPhoto)。 通過這種方式,我確信每個圖片瀏覽都有其子視圖。

在這裏我的實現(只有非凡的方法) 希望這些幫助!

PhotoViewController.h:

#import "TapDetectingPhotoView.h" 


@interface PhotoGalleryController : TTPhotoViewController <TTScrollViewDelegate, TapDetectingPhotoViewDelegate> { 

    NSArray *images; 
} 
@property (nonatomic, retain) NSArray *images; 
@end 

PhotoViewController。米:

#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

有趣的問題。 Facebook與他們的標籤具有類似的功能。他們的標籤不能與圖像成比例地縮放。事實上,他們甚至沒有顯示標籤,如果你已經放大。我不知道這是否會對您有所幫助,但我會考慮如何(如果)three20處理標籤,然後嘗試擴展標籤。

1

一些想法:

子類TTPhotoView,然後覆蓋createPhotoViewTTPhotoViewController

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

嘗試重寫一個私有方法(是的,不好的做法,但嘿)在TTPhotoViewsetImage:

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

一般來說,看標題以及TTPhotoViewControllerTTPhotoView實現(用於私有方法)。設置一些斷點找出什麼是:)