Расширьте TTPhotoViewController с помощью пользовательского TTPhotoView

Я успешно интегрировал three20 платформу в своем проекте, и я расширил TTPhotoViewController для добавления некоторой дальнейшей функциональности.

Теперь я должен добавить некоторые подпредставления к TTPhotoView, загруженному TTPhotoViewController. В особенности я хотел бы добавить что подпредставления после каждого TTPhotoView, как загружено. Эти подпредставления представляют разумную область по изображению, таким образом, они должны масштабироваться пропорционально с изображением. Пользователь может коснуться подпредставления для получения дополнительной информации об изображении.

Я не знаю, как реализовать это поведение. Я должен расширить TTPhotoView и удостовериться, что TTPhotoViewController используют эту расширенную версию вместо ее TTPhotoView?

Кто-то мог указать на меня на правильное направление?Спасибо

5
задан ggould75 7 June 2010 в 17:18
поделиться

3 ответа

Решено создание подкласса 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.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];
}
5
ответ дан 14 December 2019 в 13:27
поделиться

Интересный вопрос. Facebook имеет аналогичную функциональность со своими тегами. Их теги не масштабируются пропорционально изображению. Фактически, они даже не показывают теги, если вы увеличили масштаб. Я не знаю, поможет ли это вам, но я бы посмотрел, как (если) three20 обрабатывает теги, а затем, возможно, попытался бы расширить это.

0
ответ дан 14 December 2019 в 13:27
поделиться

Некоторые идеи:

Подкласс TTPhotoView , затем переопределите createPhotoView в вашем TTPhotoViewController :

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

Попробуйте переопределить частный метод (да, плохая практика , но привет) setImage: в TTPhotoView подкласс:

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

В общем, посмотрите на реализации заголовков и (для частных методов) TTPhotoViewController и TTPhotoView . Установите несколько точек останова, чтобы выяснить, что для чего нужно :)

1
ответ дан 14 December 2019 в 13:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: