简体   繁体   中英

Move UIImage inside UIImageView

I have an UIImageView (red squares) that will display a UIImage that must be scaled (I can receive images greater or smaller that the UIImageView ). After scaling it, the showed part of the UIImage is the center of it.

What I need is to show the part of the image in the blue squares, how can I archive it?

I'm only able to get the image size (height and width), but it display the original size, when it's supposed to be the scaled one.

self.viewIm = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 120, 80)];
self.viewIm.backgroundColor = [UIColor greenColor];
self.viewIm.layer.borderColor = [UIColor redColor].CGColor;
self.viewIm.layer.borderWidth = 5.0;
UIImage *im = [UIImage imageNamed:@"benjen"];
self.viewIm.image = im;
self.viewIm.contentMode = UIViewContentModeScaleAspectFill;
//    self.viewim.clipsToBounds = YES;
[self.view addSubview:self.viewIm];

在此输入图像描述

To do what you're trying to do, I'd recommend looking into CALayer 's contentsRect property.

Since seeing your answer, I've been trying to work out the proper solution for a while, but the mathematics escapes me because contentsRect: 'sx and y parameters seem sort of mysterious... But here's some code that may point you in the right direction...

float imageAspect = self.imageView.image.size.width/self.imageView.image.size.height;
float imageViewAspect = self.imageView.frame.size.width/self.imageView.frame.size.height;

if (imageAspect > imageViewAspect) {
    float scaledImageWidth = self.imageView.frame.size.height * imageAspect;
    float offsetWidth = -((scaledImageWidth-self.imageView.frame.size.width)/2);
    self.imageView.layer.contentsRect = CGRectMake(offsetWidth/self.imageView.frame.size.width, 0.0, 1.0, 1.0);
} else if (imageAspect < imageViewAspect) {
    float scaledImageHeight = self.imageView.frame.size.width * imageAspect;
    float offsetHeight = ((scaledImageHeight-self.imageView.frame.size.height)/2);
    self.imageView.layer.contentsRect = CGRectMake(0.0, offsetHeight/self.imageView.frame.size.height, 1.0, 1.0);
}

Try something like this:

CGRect cropRect = CGRectMake(0,0,200,200);
CGImageRef imageRef = CGImageCreateWithImageInRect([ImageToCrop CGImage],cropRect);
UIImage *image = [UIImage imageWithCGImage:imageRef]; 
CGImageRelease(imageRef);

I found a very good approximation on this answer . In that, the category resize the image, and use the center point to crop after that. I adapt it to crop using (0,0) as origin point. As I don't really need a category, I use it as a single method.

- (UIImage *)imageByScalingAndCropping:(UIImage *)image forSize:(CGSize)targetSize {
    UIImage *sourceImage = image;
    UIImage *newImage = nil;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetSize.width;
    CGFloat scaledHeight = targetSize.height;

    if (CGSizeEqualToSize(image.size, targetSize) == NO) {
        if ((targetSize.width / image.size.width) > (targetSize.height / image.size.height)) {
            scaleFactor = targetSize.width / image.size.width; // scale to fit height
        } else {
            scaleFactor = targetSize.height / image.size.height; // scale to fit width
        }

        scaledWidth  = image.size.width * scaleFactor;
        scaledHeight = image.size.height * scaleFactor;
    }

    UIGraphicsBeginImageContext(targetSize); // this will crop

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = CGPointZero;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage == nil) {
        NSLog(@"could not scale image");
    }

    //pop the context to get back to the default
    UIGraphicsEndImageContext();

    return newImage;
}

And my call is something like this:

self.viewIm = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 120, 80)];
self.viewIm.image = [self imageByScalingAndCropping:[UIImage imageNamed:@"benjen"] forSize:CGSizeMake(120, 80)];
[self.view addSubview:self.viewIm];

I've spent some time on this and finally created a Swift 3.2 solution (based on one of my answers on another thread, as well as one of the answers above). This code only allows for Y translation of the image, but with some tweaks anyone should be able to add horizontal translation as well ;)

let yOffset: CGFloat = 20
myImageView.contentMode = .scaleAspectFill

//scale image to fit the imageView's width (maintaining aspect ratio), but allow control over the image's Y position
UIGraphicsBeginImageContextWithOptions(myImageView.frame.size, myImageView.isOpaque, 0.0)
let ratio = myImage.size.width / myImage.size.height
let newHeight = myImageView.frame.width / ratio
let rect = CGRect(x: 0, y: -yOffset, width: myImageView.frame.width, height: newHeight)
myImage.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext() ?? myImage
UIGraphicsEndImageContext()

//set the new image
myImageView.image = newImage

Now you can adjust how far down or up you need the image to be by changing the yOffset .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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