2010-06-07 109 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实现(用于私有方法)。设置一些断点找出什么是:)