使用自定义TTPhotoView扩展TTPhotoViewController

ggo*_*d75 5 iphone three20 ttphotoviewcontroller

我已经在我的项目中成功集成了three20框架,并且我已经扩展了TTPhotoViewController以添加一些其他功能.

现在我需要为TTPhotoViewController加载的TTPhotoView添加一些子视图.特别是我想在每个TTPhotoView加载后添加子视图.这些子视图表示图像上的合理区域,因此它们应与图像成比例缩放.用户可以点击子视图以获取有关图像的额外信息.

我不知道如何实现这种行为.我应该扩展TTPhotoView并确保TTPhotoViewController使用此扩展版本而不是其TTPhotoView吗?

有人能指出我正确的方向吗?谢谢

ggo*_*d75 5

解决了TTPhotoView(TapDetectingPhotoView)的子类,然后将我的所有子视图添加到该子类.主要问题是照片切换,因为TTPhotoViewController(特别是其内部TTScrollView)在切换操作期间重用TTPhotoView.因此,例如,如果将子视图添加到TTPhotoView子类并尝试切换到下一张照片,则子视图可能会在此处,因为TTPhotoView会重复使用.为了解决这个问题,我决定每次发生照片切换时添加和删除所有子视图(请参阅TTPhotoViewController :: didMoveToPhoto).通过这种方式,我确信每个photoview都有其子视图.

在这里我的实施(只有卓越的方法)希望这些帮助!

PhotoViewController.h:

#import "TapDetectingPhotoView.h"


@interface PhotoGalleryController : TTPhotoViewController <TTScrollViewDelegate, TapDetectingPhotoViewDelegate> {

    NSArray *images;
}
@property (nonatomic, retain) NSArray *images;
@end
Run Code Online (Sandbox Code Playgroud)

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...
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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];
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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];
}
Run Code Online (Sandbox Code Playgroud)