UIImageView 捏缩放和重新定位以适应覆盖

Posted

技术标签:

【中文标题】UIImageView 捏缩放和重新定位以适应覆盖【英文标题】:UIImageView pinch zoom and reposition to fit overlay 【发布时间】:2014-03-17 23:29:38 【问题描述】:

我正在使用 UIImagePickerView 从相机或相机胶卷中抓取照片。当用户“选择”图像时,我将图像插入到 UIImageView 上,该 UIImageView 嵌套在 UIScrollView 中以允许捏/平移。我在图像视图上方有一个叠加层,它表示图像将被裁剪到的区域(就像 UIImagePickerView 的 .allowEditing 属性为 YES 时一样)。

Apple 提供的“allowEditing”功能也有我在代码中看到的相同问题(这就是为什么我首先尝试自己编写它,并且我需要在叠加层中自定义形状)。问题是我似乎找不到一个好方法来让用户在所有图像上平移。始终有部分图像无法放置在裁剪窗口中。它始终是图像边缘(可能是外部 10%)周围的内容,无法平移到裁剪窗口中。

在上图中,顶部和底部的棕色区域是滚动视图的背景颜色。图像视图的大小与图像一致。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 

    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];

    // Calculate what height/width we'll need for our UIImageView.
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    float width = 0.0f, height = 0.0f;
    if (image.size.width > image.size.height) 
        width = screenSize.width;
        height =  image.size.height / (image.size.width/screenSize.width);
     else 
        height = screenSize.height;
        width = image.size.width / (image.size.height/screenSize.height);
    

    if (width > screenSize.width) 
        height /= (width/screenSize.width);
        width = screenSize.width;
    
    if (height > screenSize.height) 
        width /= (height/screenSize.height);
        height = screenSize.height;
    

    // Update the image view to the size of the image and center it.
    // Image view is a subview of the scroll view.
    imageView.frame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
    imageView.image = image;
    // Setup our scrollview so we can scroll and pinch zoom the image!
    imageScrollView.contentSize = CGSizeMake(screenSize.width, screenSize.height);

    // Close the picker.
    [[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];

我考虑过监控滚动视图的滚动位置和缩放级别,并禁止图像的一侧进入图像的裁剪“最佳位置”。然而,这似乎是过度设计。

有谁知道实现这个的方法吗?

【问题讨论】:

***.com/a/66396409/2033377我在这里回答了这个问题。 【参考方案1】:

我是个白痴。睡个好觉能带来多大的改变 ;-) 希望它能在未来对某人有所帮助。

设置正确的滚动视图 contentSizecontentInset 就可以了。工作代码如下。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 

    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];

    // Change the frame of the image view so that it fits the image!
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    float width = 0.0f, height = 0.0f;
    if (image.size.width > image.size.height) 
        width = screenSize.width;
        height = image.size.height / (image.size.width/screenSize.width);
     else 
        height = screenSize.height;
        width = image.size.width / (image.size.height/screenSize.height);
    

    // Make sure the new height and width aren't bigger than the screen
    if (width > screenSize.width) 
        height /= (width/screenSize.width);
        width = screenSize.width;
    
    if (height > screenSize.height) 
        width /= (height/screenSize.height);
        height = screenSize.height;
    

    CGRect overlayRect = cropOverlay.windowRect;

    imageView.frame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
    imageView.image = image;

    // Setup our scrollview so we can scroll and pinch zoom the image!
    imageScrollView.contentSize = imageView.frame.size;
    imageScrollView.contentInset = UIEdgeInsetsMake(overlayRect.origin.y - imageView.frame.origin.y,
                                                    overlayRect.origin.x,
                                                    overlayRect.origin.y + imageView.frame.origin.y,
                                                    screenSize.width - (overlayRect.origin.x + overlayRect.size.width));

    // Dismiss the camera's VC
    [[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];

滚动视图和图像视图是这样设置的:

imageScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
imageScrollView.showsHorizontalScrollIndicator = NO;
imageScrollView.showsVerticalScrollIndicator = NO;
imageScrollView.backgroundColor = [UIColor blackColor];
imageScrollView.userInteractionEnabled = YES;
imageScrollView.delegate = self;
imageScrollView.minimumZoomScale = MINIMUM_SCALE;
imageScrollView.maximumZoomScale = MAXIMUM_SCALE;
[self.view addSubview:imageScrollView];

imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.backgroundColor = [UIColor grayColor]; // I had this set to gray so I could see if/when it didn't align properly in the scroll view.  You'll likely want to change it to black
[imageScrollView addSubview:imageView];

编辑 3-21-14 更新、更好、更好地实现了计算在屏幕和滚动视图中放置图像的位置的方法。那么有什么更好的呢?这个新实现将检查设置到滚动视图中的任何宽度或高度较小的图像,并调整图像视图的框架,使其扩展为至少与宽度或高度一样 叠加矩形,因此您不必担心您的用户会选择不适合您的叠加的图像。耶!

- (void)imagePickerController:(UIImagePickerController *)pickerUsed didFinishPickingMediaWithInfo:(NSDictionary *)info 

    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];

    // Change the frame of the image view so that it fits the image!
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    float width = 0.0f, height = 0.0f;
    if (image.size.width > image.size.height) 
        width = screenSize.width;
        height = image.size.height / (image.size.width/screenSize.width);
     else 
        height = screenSize.height;
        width = image.size.width / (image.size.height/screenSize.height);
   

   CGRect overlayRect = cropOverlay.windowRect;

    // We should check the the width and height are at least as big as our overlay window
    if (width < overlayRect.size.width) 
        float ratio = overlayRect.size.width / width;
        width *= ratio;
        height *= ratio;
    
    if (height < overlayRect.size.height) 
        float ratio = overlayRect.size.height / height;
        height *= ratio;
        width *= ratio;
    

    CGRect imageViewFrame = CGRectMake((screenSize.width - width) / 2, (screenSize.height - height) / 2, width, height);
    imageView.frame = imageViewFrame;
    imageView.image = image;

    // Setup our scrollview so we can scroll and pinch zoom the image!
    imageScrollView.contentSize = imageView.frame.size;
    imageScrollView.contentInset = UIEdgeInsetsMake(overlayRect.origin.y - imageView.frame.origin.y,
                                                    (imageViewFrame.origin.x * -1) + overlayRect.origin.x,
                                                    overlayRect.origin.y + imageView.frame.origin.y,
                                                    imageViewFrame.origin.x + (screenSize.width - (overlayRect.origin.x + overlayRect.size.width)));

    // Calculate the REAL minimum zoom scale!
    float minZoomScale = 1 - MIN(fabsf(fabsf(imageView.frame.size.width) -  fabsf(overlayRect.size.width)) /  imageView.frame.size.width,
                           fabsf(fabsf(imageView.frame.size.height) - fabsf(overlayRect.size.height)) / imageView.frame.size.height);
    imageScrollView.minimumZoomScale = minZoomScale;

    // Dismiss the camera's VC
    [[picker presentingViewController] dismissViewControllerAnimated:YES completion:NULL];

【讨论】:

以上是关于UIImageView 捏缩放和重新定位以适应覆盖的主要内容,如果未能解决你的问题,请参考以下文章

在滚动视图内的 UIImageView 上捏缩放效果?

使用 AutoLayout 缩放 UIImageView 以适应宽度

UIScrollView 中的 UIImageView 不是全屏和捏缩放

如何在不使用 UIImageView 的情况下捏缩放 UIImage?

iOS UIScrollView捏缩放添加空白

以全分辨率从 UIScrollView 中捕获缩放的 UIImageView