将 UIImage 放入 UIButton 的简单方法

发布于 2024-10-08 08:23:48 字数 663 浏览 4 评论 0原文

我的 iPhone 应用程序中有一个 UIButton。我将其大小设置为 100x100。

我有一个 400x200 的图像,我希望在按钮中显示它。

按钮仍然需要保持在 100x100...并且我希望图像缩小以适应...但是 保持正确的纵横比。

我想这就是“Aspect Fit”的用途。

我是否将我的图像包含在 setImage 或 setBackgroundImage 中?

我是否为按钮设置了 AspectFit?或图像?或者背景图片?

(我需要较小的图像来增加尺寸。而较大的图像应该减小尺寸。 始终将按钮保持在 100x100。)

我已经尝试了上述所有组合的无数种组合......但我似乎无法得到 一切同时工作:

  • 不要更改按钮的大小 100x100。
  • 不要破坏图像的纵横比。
  • 始终增加小图像以适合按钮。
  • 始终缩小大图像以适合按钮。
  • 切勿剪掉任何图像边缘。
  • 永远不要需要“将 UIButtons 放在所有 UIimages 上”技巧。
  • 不需要每个人都升级到v4.2.1只是为了使用新的框架方法。

我看到了这么多的应用程序,有这么多功能齐全的图像按钮……我不敢相信我无法弄清楚这个非常简单、非常常见的事情。

啊。

I have a UIButton in my iPhone app. I set its size to 100x100.

I have an image that is 400x200 that I wish to display in the button.

The button STILL needs to stay at 100x100... and I want the image to downsize to fit... but
keep the correct aspect ratio.

I thought that's what "Aspect Fit" was used for.

Do I include my image with setImage, or setBackgroundImage?

Do I set AspectFit for the button? or the image? or the background image?

(I need the smaller images to INCREASE in size. While larger images should DESCREASE in size.
Always keeping the button at 100x100.)

I've tried countless combinations of all of the above... and I just can't seem to get
everything to work at the same time:

  • Don't change the button's size of 100x100.
  • Don't destroy the image's aspect ratio.
  • Always increase small images to fit the button.
  • Always decrease large images to fit the button.
  • Never clip any of the image edges.
  • Never require the "put UIButtons over all your UIimages" hack.
  • Don't require everyone to upgrade to v4.2.1 just to use new framework methods.

I see so many apps, with so many fully-working image-buttons... that I can't believe I can't figure out this very simple, very common thing.

Ugh.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

柳絮泡泡 2024-10-15 08:23:48

UIButton 已损坏。这就是简短的答案。其 image 和 backgroundImage 属性中的 UIImageView 不遵守 UIViewContentMode 设置。它们是只读属性,虽然这些 UIImageView 的 UIImage 内容可以通过 setImage:setBackgroundImage: 方法设置,但内容模式不可以。

解决方案是首先在包中提供适当大小的图像,或者放置一个 UIImageView,按照您想要的方式配置它,然后在其顶部放置一个清晰的“自定义”UIButton。我保证,这就是您见过的所有那些精美的专业应用程序都使用过的技巧。我们都必须这样做。

UIButton is broken. That's the short answer. The UIImageViews in its image and backgroundImage properties don't respect UIViewContentMode settings. They're read-only properties, and while the UIImage contents of those UIImageViews can be set through setImage: and setBackgroundImage: methods, the content mode can't be.

The solution is either to provide properly-sized images in your bundle to begin with, or to put a UIImageView down, configure it the way you want it, and then put a clear "custom" UIButton over top of it. That's the hack all those fancy professional apps you've seen have used, I promise. We're all having to do it.

淑女气质 2024-10-15 08:23:48
UIImage *img = [UIImage imageNamed:@"yourImageName"];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
[button setImage:img forState:UIControlStateNormal];
UIImage *img = [UIImage imageNamed:@"yourImageName"];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
[button setImage:img forState:UIControlStateNormal];
情泪▽动烟 2024-10-15 08:23:48

为了正确地做到这一点,我实际上会以编程方式调整图像大小并操作图像以获得所需的宽高比。这避免了对任何视图层次结构黑客的需要,并且还减少了对单个操作(而不是每次重绘)的任何性能影响。

这段(未经测试的)代码应该有助于说明我的意思:

CGSize imageSize = image.size;
CGFloat currentAspect = imageSize.width / imageSize.height;

// for purposes of illustration
CGFloat targetWidth = 100;
CGFloat targetHeight = 100;
CGFloat targetAspect = targetWidth / targetHeight;

CGFloat newWidth, newHeight;

if (currentAspect > targetAspect) {
    // width will end up at 100, height needs to be smaller
    newWidth = targetWidth;
    newHeight = targetWidth / currentAspect;
} else {
    // height will end up at 100, width needs to be smaller
    newHeight = targetHeight;
    newWidth = targetHeight * currentAspect;
}

size_t bytesPerPixel = 4;

// although the image will be resized to { newWidth, newHeight }, it needs
// to be padded with empty space to provide the aspect fit behavior
//
// use calloc() to clear the data as it's allocated
void *imageData = calloc(targetWidth * targetHeight, bytesPerPixel);

if (!imageData) {
    // error out
    return;
}

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if (!colorSpace) {
    // error out
    return;
}

CGContextRef context = CGBitmapContextCreate(
    imageData,
    targetWidth,
    targetHeight,
    8, // bits per component
    targetWidth * bytesPerPixel, // bytes per row
    colorSpace,
    kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst
);

CGColorSpaceRelease(colorSpace);

// now we have a context to draw the original image into
// in doing so, we want to center it, so prepare the geometry
CGRect drawRect = CGRectMake(
    floor((targetWidth - newWidth) / 2),
    floor((targetHeight - newHeight) / 2),
    round(newWidth),
    round(newHeight)
);

CGContextDrawImage(context, drawRect, image.CGImage);

// now that the bitmap context contains the aspect fit image with transparency
// letterboxing, we want to pull out a new image from it
CGImageRef newImage = CGBitmapContextCreateImage(context);

// destroy the temporary context
CGContextRelease(context);
free(imageData);

// and, finally, create a new UIImage
UIImage *newUIImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);

如果其中任何部分不清楚,请告诉我。

To do this correctly, I would actually programmatically resize and manipulate the image to get the desired aspect ratio. This avoids the need for any view hierarchy hacks, and also reduces any performance hit to a single operation, instead of every redraw.

This (untested) code should help illustrate what I mean:

CGSize imageSize = image.size;
CGFloat currentAspect = imageSize.width / imageSize.height;

// for purposes of illustration
CGFloat targetWidth = 100;
CGFloat targetHeight = 100;
CGFloat targetAspect = targetWidth / targetHeight;

CGFloat newWidth, newHeight;

if (currentAspect > targetAspect) {
    // width will end up at 100, height needs to be smaller
    newWidth = targetWidth;
    newHeight = targetWidth / currentAspect;
} else {
    // height will end up at 100, width needs to be smaller
    newHeight = targetHeight;
    newWidth = targetHeight * currentAspect;
}

size_t bytesPerPixel = 4;

// although the image will be resized to { newWidth, newHeight }, it needs
// to be padded with empty space to provide the aspect fit behavior
//
// use calloc() to clear the data as it's allocated
void *imageData = calloc(targetWidth * targetHeight, bytesPerPixel);

if (!imageData) {
    // error out
    return;
}

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if (!colorSpace) {
    // error out
    return;
}

CGContextRef context = CGBitmapContextCreate(
    imageData,
    targetWidth,
    targetHeight,
    8, // bits per component
    targetWidth * bytesPerPixel, // bytes per row
    colorSpace,
    kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst
);

CGColorSpaceRelease(colorSpace);

// now we have a context to draw the original image into
// in doing so, we want to center it, so prepare the geometry
CGRect drawRect = CGRectMake(
    floor((targetWidth - newWidth) / 2),
    floor((targetHeight - newHeight) / 2),
    round(newWidth),
    round(newHeight)
);

CGContextDrawImage(context, drawRect, image.CGImage);

// now that the bitmap context contains the aspect fit image with transparency
// letterboxing, we want to pull out a new image from it
CGImageRef newImage = CGBitmapContextCreateImage(context);

// destroy the temporary context
CGContextRelease(context);
free(imageData);

// and, finally, create a new UIImage
UIImage *newUIImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);

Let me know if any part of that is unclear.

怪我鬧 2024-10-15 08:23:48

我认为 Dan 想说的(但从未说过)是这样做:

  • 使用“临时图像”为您调整大小。
  • 临时图像需要设置为 ASPECT FIT 和 HIDDEN。
  • 确保您的按钮设置为所需的尺寸,而不是设置为宽高比。
// Make a frame the same size as your button
CGRect aFrame = CGRectMake(0, 0, myButton.frame.size.width, myButton.frame.size.height);

// Set your temp-image to the size of your button
imgTemp.frame = aFrame;

// Put your image into the temp-image
imgTemp.image = anImage;

// Copy that resized temp-image to your button
[myButton setBackgroundImage:tempImage forState:UIControlStateNormal]; 

I think what Dan is trying to say (but without ever saying it) is to do this:

  • Use a "temp image" to do the resizing for you.
  • The temp-image needs to be set to ASPECT FIT and HIDDEN.
  • Make sure your button is set to your desired size, and NOT set to ASPECT FIT.
// Make a frame the same size as your button
CGRect aFrame = CGRectMake(0, 0, myButton.frame.size.width, myButton.frame.size.height);

// Set your temp-image to the size of your button
imgTemp.frame = aFrame;

// Put your image into the temp-image
imgTemp.image = anImage;

// Copy that resized temp-image to your button
[myButton setBackgroundImage:tempImage forState:UIControlStateNormal]; 
緦唸λ蓇 2024-10-15 08:23:48

因为我的尝试都没有成功……

也许我应该问这个。使用 UIButton 时:

当我使用 setImage 而不是 setBackgroundImage 时? (为什么两者都有?)

DO我使用“Aspect Fit”而不是“Center”时? (当我期望它们分别“保持纵横比”和“不调整任何大小”时,为什么两者似乎都拉伸了我的图像。)

最大的问题是:为什么如此常见的事情......如此巨大的混乱?

如果我能找到一种解决方法,例如:只需使用 UIImage 并检测 TAPS,那么这一切都可以解决。 (但这似乎是一个更大的代码噩梦。)

Apple,如果你试图让我的工作变得更容易......你反而让它变得更加混乱 400 倍。

Since none of my attempts have worked....

Maybe I should be asking this instead. When using a UIButton:

When DO I use setImage instead of setBackgroundImage? (Why are there both?)

When DO I use "Aspect Fit" instead of "Center"? (Why do both seem to stretch my images when I expect them to "keep aspect ratio" and "don't resize anything", respective.)

And the big question: Why is such a common thing... such a huge mess?

It would all be solved if I could find a work-around method like: Just use UIImage instead and detect TAPS. (But that seems to be even a LARGER nightmare of code.)

Apple, if you've tried to make my job easier... you have instead made it 400 times more confusing.

请帮我爱他 2024-10-15 08:23:48

将图像视图放在按钮上,为图像视图而不是按钮设置图像。

一切顺利。

Place a imageview over the button, set your image for the imageview and not for button.

All the best.

二智少女猫性小仙女 2024-10-15 08:23:48

我会将图像大小调整为 100x100,保持图像中包含的内容的纵横比。然后将 UIButton 的 backgroundImage 属性设置为图像。

I would resize the image to 100x100 maintaining the aspect ratio of the content contained in the image. Then set the backgroundImage property of the UIButton to the image.

世俗缘 2024-10-15 08:23:48

几天前我遇到了同样的问题并解决了它。请尝试用这个

[_profilePicBtn setImage:profilePic forState:UIControlStateNormal];
_profilePicBtn.imageView.contentMode = UIViewContentModeScaleAspectFit;

I faced same issue few days back and resolved it. Please try with this

[_profilePicBtn setImage:profilePic forState:UIControlStateNormal];
_profilePicBtn.imageView.contentMode = UIViewContentModeScaleAspectFit;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文