简体   繁体   English

如何在全屏 UIScrollView 中居中 UIImageView?

[英]How do I center a UIImageView within a full-screen UIScrollView?

In my application, I would like to present the user with a full-screen photo viewer much like the one used in the Photos app.在我的应用程序中,我想向用户展示一个全屏照片查看器,就像照片应用程序中使用的那样。 This is just for a single photo and as such should be quite simple.这仅适用于单张照片,因此应该非常简单。 I just want the user to be able to view this one photo with the ability to zoom and pan.我只希望用户能够通过缩放和平移功能查看这张照片。

I have most of it working.我有大部分工作。 And, if I do not center my UIImageView, everything behaves perfectly.而且,如果我不将 UIImageView 居中,则一切都会完美运行。 However, I really want the UIImageView to be centered on the screen when the image is sufficiently zoomed out.但是,当图像被充分缩小时,我真的希望 UIImageView 在屏幕上居中。 I do not want it stuck to the top-left corner of the scroll view.我不希望它卡在滚动视图的左上角。

Once I attempt to center this view, my vertical scrollable area appears to be greater than it should be.一旦我尝试将这个视图居中,我的垂直可滚动区域似乎比它应该的要大。 As such, once I zoom in a little, I am able to scroll about 100 pixels past the top of the image.因此,一旦我放大一点,我就可以滚动超过图像顶部约 100 像素。 What am I doing wrong?我究竟做错了什么?

@interface MyPhotoViewController : UIViewController <UIScrollViewDelegate>
{
    UIImage* photo;
    UIImageView *imageView;
}
- (id)initWithPhoto:(UIImage *)aPhoto;
@end

@implementation MyPhotoViewController

- (id)initWithPhoto:(UIImage *)aPhoto
{
    if (self = [super init])
    {
        photo = [aPhoto retain];

        // Some 3.0 SDK code here to ensure this view has a full-screen
        // layout.
    }

    return self;
}

- (void)dealloc
{
    [photo release];
    [imageView release];
    [super dealloc];
}

- (void)loadView
{
    // Set the main view of this UIViewController to be a UIScrollView.
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    [self setView:scrollView];
    [scrollView release];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Initialize the scroll view.
    CGSize photoSize = [photo size];
    UIScrollView *scrollView = (UIScrollView *)[self view];
    [scrollView setDelegate:self];
    [scrollView setBackgroundColor:[UIColor blackColor]];

    // Create the image view. We push the origin to (0, -44) to ensure
    // that this view displays behind the navigation bar.
    imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, -44.0,
        photoSize.width, photoSize.height)];
    [imageView setImage:photo];
    [scrollView addSubview:imageView];

    // Configure zooming.
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    CGFloat widthRatio = screenSize.width / photoSize.width;
    CGFloat heightRatio = screenSize.height / photoSize.height;
    CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
    [scrollView setMaximumZoomScale:3.0];
    [scrollView setMinimumZoomScale:initialZoom];
    [scrollView setZoomScale:initialZoom];
    [scrollView setBouncesZoom:YES];
    [scrollView setContentSize:CGSizeMake(photoSize.width * initialZoom,
        photoSize.height * initialZoom)];

    // Center the photo. Again we push the center point up by 44 pixels
    // to account for the translucent navigation bar.
    CGPoint scrollCenter = [scrollView center];
    [imageView setCenter:CGPointMake(scrollCenter.x,
        scrollCenter.y - 44.0)];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlackTranslucent];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [[[self navigationController] navigationBar] setBarStyle:UIBarStyleDefault];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return imageView;
}

@end

This code should work on most versions of iOS (and has been tested to work on 3.1 upwards).这段代码应该适用于大多数 iOS 版本(并且已经过测试可以在 3.1 以上版本上工作)。

It's based on the Apple WWDC code for PhotoScroller .它基于PhotoScrollerApple WWDC 代码

Add the below to your subclass of UIScrollView , and replace tileContainerView with the view containing your image or tiles:将以下内容添加到UIScrollView的子类中,并将tileContainerView替换为包含图像或图块的视图:

- (void)layoutSubviews {
    [super layoutSubviews];

    // center the image as it becomes smaller than the size of the screen
    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = tileContainerView.frame;

    // center horizontally
    if (frameToCenter.size.width < boundsSize.width)
        frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
    else
        frameToCenter.origin.x = 0;

    // center vertically
    if (frameToCenter.size.height < boundsSize.height)
        frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
    else
        frameToCenter.origin.y = 0;

    tileContainerView.frame = frameToCenter;
}

Have you checked out the UIViewAutoresizing options?您是否检查过 UIViewAutoresizing 选项?

(from the documentation) (来自文档)

UIViewAutoresizing
Specifies how a view is automatically resized.

enum {
   UIViewAutoresizingNone                 = 0,
   UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
   UIViewAutoresizingFlexibleWidth        = 1 << 1,
   UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
   UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
   UIViewAutoresizingFlexibleHeight       = 1 << 4,
   UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;

Are you using IB to add the scroll view?您是否使用 IB 添加滚动视图? Change the autosizing options of the scrollview to the attached image.将滚动视图的自动调整选项更改为附加图像。 替代文字

I think the reason behind it is because the zoomScale applies to the whole contentSize, regardless of the actual size of the subview inside the scrollView (in your case it's an imageView).我认为其背后的原因是因为 zoomScale 适用于整个 contentSize,而不管 scrollView 内子视图的实际大小(在您的情况下它是一个 imageView)。 The contentSize height seems to be always equal or greater than the height of the scrollView frame, but never smaller. contentSize 高度似乎总是等于或大于 scrollView 框架的高度,但永远不会更小。 So when applying a zoom to it, the height of the contentSize gets multiplied by the zoomScale factor as well, that's why you're getting an extra 100-something pixels of vertical scroll.因此,当对其应用缩放时, contentSize 的高度也会乘以 zoomScale 因子,这就是为什么您会获得额外的 100 像素左右的垂直滚动。

You probably want to set the bounds of the scroll view = bounds of the image view, and then center the scroll view in its containing view.您可能希望设置滚动视图的边界 = 图像视图的边界,然后将滚动视图置于其包含视图的中心。 If you place a view inside a scroll view at an offset from the top, you will get that empty space above it.如果您将视图放置在滚动视图内与顶部偏移的位置,您将在其上方获得空白空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM