A different Gold Solution


#1

I wanted slightly different behavior from the solution than was presented in other posts.

  1. As other people have noted, the coupling between the 600x600 size in ItemsViewController and ImageViewController is a little awkward.
  2. I decided it would be nice to have the popup be sized with the same aspect ratio as the image and have the image initially zoomed to exactly fill the popup and have a maximum zoom of 10x. Since the image is initially scaled exactly to fit the popup, I don’t need to worry about setting the contentOffset property to center the image.

To help with 1), I created a property in ImageViewController to hold the scaleFactor. That way the ItemsViewController would “decide” the size and set the property in the ImageViewController. That way, the ImageViewController would be told by the presenting controller and not coupled to any specific size. Also, if another ViewController wanted to create a popup with a different size, it could.

Here goes…

[code]@interface ImageViewController : UIViewController
{
__weak IBOutlet UIImageView *imageView;
__weak IBOutlet UIScrollView *scrollView;
}
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, readwrite) float scaleFactor;

@end[/code]

In order to prevent undesired effects if the programmer “forgot” to set the scaleFactor, it should be defaulted to 1. (0 would be a very bad default value)

In ImageViewController…

[code]- (id)init
{
self = [super init];

if (self) {
    [self setScaleFactor:1.0];
}
return self;

}

  • (void)viewWillAppear:(BOOL)animated
    {
    [super viewWillAppear];

    CGSize sz = [[self image] size];
    [scrollView setContentSize:sz];

    [scrollView setMinimumZoomScale:[self scaleFactor]];
    [scrollView setMaximumZoomScale:[self scaleFactor] * 10.0];

    [scrollView setDelegate:self];
    [imageView setFrame:CGRectMake(0, 0, sz.width, sz.height)];

    [scrollView setZoomScale: [self scaleFactor]];

    [imageView setImage:[self image]];

}

  • (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
    return imageView;
    }
    [/code]

In ItemsViewController…

[code]- (void)showImage:(id)sender atIndexPath:(NSIndexPath *)ip
{
NSLog(@“Going to show the image for %@”, ip);

// Get the item for the index path
BNRItem *i = [[[BNRItemStore defaultStore] allItems] objectAtIndex:[ip row]];

NSString *imageKey = [i imageKey];

// If there is no image, we don't need to display anything
UIImage *img = [[BNRImageStore defaultImageStore] imageForKey];
if(!img)
    return;

// Make a rectangle that the frame of the button relative to 
// our table view
CGRect rect = [[self view] convertRect:[sender bounds] fromView:sender];

// Create a new ImageViewController and set its image
ImageViewController *ivc = [[ImageViewController alloc] init];
[ivc setImage:img];

// Present a popover with its maximum dimension = 600 and the same aspect ratio as the image
float scaleFactor = MIN(600/img.size.width, 600/img.size.height);

// Set scale factor for imageViewController
[ivc setScaleFactor:scaleFactor];

imagePopover = [[UIPopoverController alloc] initWithContentViewController:ivc];
[imagePopover setDelegate:self];

[imagePopover setPopoverContentSize:CGSizeMake(img.size.width * scaleFactor, img.size.height * scaleFactor)];
[imagePopover presentPopoverFromRect:rect 
                              inView:[self view] 
            permittedArrowDirections:UIPopoverArrowDirectionAny 
                            animated:YES];

}
[/code]


#2

I know, that´s an old post, but I was interested in the gold challenge solutions around here. This one has my spirit of “what I did is what they said, but it can be better”. So I tried and made my own solution with the aspect ratio of the popover fitting the image, and the imageViewController doing everything else.

The benefit is, that I can use the imageViewController in any other superview, and the behavior stays the same. I don´t need to know anything about it to do so. If the ratio of the superview does not match, it simply will adjust its width to it, not fit perfectly, though.

//ViewWillAppear method in imageViewController.m -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear]; if([self image]) { CGSize sz = [[self image]size]; [scrollView setContentSize:sz]; [scrollView setBounds:[scrollView superview].bounds]; float initialZoomValue = scrollView.superview.bounds.size.width/sz.width; float imageViewOriginX = scrollView.bounds.size.width/2-(sz.width*initialZoomValue)/2; float imageViewOriginY = scrollView.bounds.size.height/2-(sz.height*initialZoomValue)/2; [imageView setFrame:CGRectMake(imageViewOriginX, imageViewOriginY, sz.width*initialZoomValue, sz.height*initialZoomValue)]; [scrollView setMaximumZoomScale:10.0]; [scrollView setMinimumZoomScale:1]; [scrollView setDelegate:self]; [imageView setImage:[self image]]; } }

and in itemsViewController.m (in order to fit the aspect ratio of the image)

....		
float aspectRatio = img.size.width/img.size.height;
[imagePopover setPopoverContentSize:CGSizeMake(600, 600/aspectRatio)];
....

(I wanted the contentViewController have the 600 as width, because otherwise the images were to small)