ios 如何防止按钮的背景图像拉伸?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8675590/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:04:22  来源:igfitidea点击:

How do I prevent a button's background image from stretching?

ioscocoa-touchuiimageviewuibuttonuikit

提问by Raphael Caixeta

I'm allocating a UIButtonTypeCustom UIButton to a UIView with a background image that is smaller than the button's frame. Reason why the image is smaller is because I'm trying to add more of a "target area" for the UIButton. However, the image is being scaled to the full size of the frame, rather than just being the image's size.

我将 UIButtonTypeCustom UIButton 分配给背景图像小于按钮框架的 UIView。图像较小的原因是我试图为 UIButton 添加更多的“目标区域”。但是,图像被缩放到框架的完整大小,而不仅仅是图像的大小。

I have tried setting the UIButton and UIButton's imageView contentMode property to "UIViewContentModeScaleAspectFit", but no luck, the image still gets stretched out.

我已经尝试将 UIButton 和 UIButton 的 imageView contentMode 属性设置为“UIViewContentModeScaleAspectFit”,但没有运气,图像仍然被拉伸。

Is there a way to do what I'm trying to do programmatically?

有没有办法以编程方式做我想要做的事情?

Thanks in advance!

提前致谢!

回答by memmons

A lot of people make the same mistake you do in regards to button images and then jump through hoops trying to make the button behave as they expect it to. Let's clear this up once and for all:

很多人在按钮图像方面犯了与您相同的错误,然后跳过箍试图使按钮按照他们的预期运行。让我们一劳永逸地解决这个问题:

A UIButtonhas two types of images it can display -- a foreground image and a background image. The background image for a button is expected to replace the button's background texture. As such, it makes sense that it stretches to fill the entire background. However, the button's foreground image is expected to be an icon that may or may not display alongside text; it will not stretch.It mayshrink if the frame is smaller than the image, but it will not stretch. You can even set the alignment of the foreground image using the Control alignment properties in Interface Builder.

AUIButton可以显示两种类型的图像——前景图像和背景图像。按钮的背景图像应替换按钮的背景纹理。因此,它延伸以填充整个背景是有道理的。但是,按钮的前景图像应该是一个图标,可能会或可能不会与文本一起显示;它不会伸展。如果框架小于图像,它可能会缩小,但不会拉伸。您甚至可以使用界面生成器中的控制对齐属性设置前景图像的对齐方式。

A button's foreground and background image can be set in code like this:

按钮的前景和背景图像可以在代码中设置,如下所示:

// stretchy
[self setBackgroundImage:backgroundImage forState:UIControlStateNormal];  

// not stretchy
[self setImage:forgroundImage forState:UIControlStateNormal]; 

回答by Zoltán Matók

You don't have access to the background imageView, but there is fully working workaround:

您无权访问背景图像视图,但有完全可行的解决方法:

EDIT: There is an even better workaround then what I posted originally. You can create a UIImage from any color,and call -setBackgroundImage:forState.

编辑:有一个比我最初发布的更好的解决方法。您可以从任何颜色创建UIImage,并调用-setBackgroundImage:forState.

See bradley'sanswer, here: https://stackoverflow.com/a/20303841/1147286

bradley's在这里查看答案:https: //stackoverflow.com/a/20303841/1147286



Original answer:

原答案:

Instead of calling -setBackgroundImage:forState:, create a new UIImageView and add it as a subview of the button.

而不是调用-setBackgroundImage:forState:,创建一个新的 UIImageView 并将其添加为按钮的子视图。

UIImageView *bgImageView = [[UIImageView alloc] initWithImage:img];
bgImageView.contentMode = UIViewContentModeScaleAspectFit;
[bgImageView setFrame:CGRectMake(0, 0, videoButton.frame.size.width, videoButton.frame.size.height)];
bgImageView.tag = 99;
[yourButton addSubview:bgImageView];
[yourButton bringSubviewToFront:yourButton.imageView];
  1. Create the imageview
  2. Set the content mode and frame
  3. I also set a recognizable tag, so that when the screen rotates I can easily find my custom imageView in the button's subviews and reset its frame
  4. Add it as a subview to the button
  5. Bring the frontal imageView of the button to the frontso our custom imageView doesn't overlap it
  1. 创建图像视图
  2. 设置内容模式和框架
  3. 我还设置了一个可识别的标签,以便在屏幕旋转时我可以轻松地在按钮的子视图中找到我的自定义 imageView 并重置其框架
  4. 将其作为子视图添加到按钮
  5. 将按钮的正面 imageView 放在前面,这样我们的自定义 imageView 就不会与它重叠

When the button needs to rotate just find the imageView by its tag and reset its frame:

当按钮需要旋转时,只需通过其标签找到 imageView 并重置其框架:

UIImageView *bgImageView = (UIImageView *)[button viewWithTag:99];
[bgImageView setFrame:CGRectMake(0, 0, newWidth, newHeight)];

回答by Boris Gafurov

Stumbled on this problem too.

也偶然发现了这个问题。

Adding image programmatically, as memmons thoroughly explained, did not help:(

正如 memmons 彻底解释的那样,以编程方式添加图像并没有帮助:(

I had a button 100x40 and image 100x100, it would appear squeezed, not fitted, as one would infer from "Aspect Fit" option. Actually, non of those view options had an effect.

我有一个 100x40 的按钮和 100x100 的图像,它看起来是被挤压的,而不是适合的,就像从“Aspect Fit”选项中推断出来的那样。实际上,这些视图选项都没有效果。

I just had to rescale it so it would fit on a button, then use setImage:

我只需要重新缩放它以便它适合按钮,然后使用 setImage:

UIImage *img=[UIImage imageNamed:@"myimage.png"];
CGImageRef imgRef = [img CGImage];
CGFloat imgW = CGImageGetWidth(imgRef);
CGFloat imgH = CGImageGetHeight(imgRef);
CGFloat btnW = myBttn.frame.size.width;
CGFloat btnH = myBttn.frame.size.height;
//get lesser button dimension
CGFloat minBtn=btnW;
if (btnW>btnH) {
    minBtn=btnH;
}
//calculate scale using greater image dimension
CGFloat scl=imgH/minBtn;
if (imgW>imgH) {
    scl=imgW/minBtn;
}
//scale image
UIImage *scaledImage = [UIImage imageWithCGImage:[img CGImage] scale:(img.scale * scl) orientation:(img.imageOrientation)];
//clean up
UIGraphicsEndImageContext();
//set it on a button
[myBttn setImage:scaledImage forState:UIControlStateNormal];

回答by AntonyG

The cleanest and easiest way it probably to use the title insets of the button.

最干净和最简单的方法可能是使用按钮的标题插入。

You set your image as the button image, and then you change the left title inset to match minus the width of your image:

您将图像设置为按钮图像,然后更改左侧标题插图以匹配减去图像的宽度:

myButton.titleEdgeInsets = UIEdgeInsetsMake(0, -myImage.width, 0, 0)

This will move the text back where it was before the image was added to its left. You can also use this value to add some padding to you button.

这会将文本移回图像添加到其左侧之前的位置。您还可以使用此值为您的按钮添加一些填充。

回答by Ronen

It is simple as:

它很简单:

    ImageBn.imageView?.contentMode = .scaleAspectFit
    ImageBn.setImage(chosenImage, for: .normal)

回答by ARSHWIN DENUEV LAL

might help someone

可能会帮助某人

button.subviews.first?.contentMode = .scaleAspectFit

回答by Epsilon3

Another consideration is the BaseLine constraint. If your buttons have this constraint set (depicted as a horizontal or vertical line through multiple controls on your layout), it will cause your images to stretch without stretching the underlying button control. If your button is otherwise properly constrained (leading/trailing and top/bottom spaces, and etc...) removing the BaseLine constraint should have no impact on the layout, while allowing the foreground image to scale properly to the underlying button shape.

另一个考虑因素是 BaseLine 约束。如果您的按钮设置了此约束(通过布局上的多个控件描绘为水平或垂直线),它将导致您的图像拉伸而不拉伸底层按钮控件。如果您的按钮以其他方式受到适当约束(前导/尾随和顶部/底部空格等),则删除 BaseLine 约束应该不会对布局产生影响,同时允许前景图像正确缩放到基础按钮形状。

回答by LEO

Answerbot answers the question with what is proper and correct to do. Don't fight the OS and use things as intended is always good advice. However, sometimes you need to break the rules.

Answerbot 以正确和正确的方式回答问题。不要与操作系统作斗争并按预期使用事物总是很好的建议。但是,有时您需要打破规则。

I was able to mask the enlarged background image (not prevent it) by overlaying it with a black CAlayer then overlaying again with a properly resized image CAlayer. This was all done by creating a subclass of UIButton and overwriting the setHighlighted method.

我能够通过用黑色 CAlayer 覆盖放大的背景图像(而不是阻止它),然后用适当调整大小的图像 CAlayer 再次覆盖它。这一切都是通过创建 UIButton 的子类并覆盖 setHighlighted 方法来完成的。

NEED CODE?

需要代码?

- (void)setHighlighted:(BOOL)highlighted
{
super.highlighted = highlighted;

//
//Whenever an image needs to be highlighted, create a dimmed new image that is correctly       sized. Below it is a englarged stretched image.
//
if (highlighted != _previousHighlightedSate)
{
    _previousHighlightedSate = highlighted;

    if (highlighted)
    {
        //Create a black layer so image can dim
        _blackLayer = [CALayer layer];
        _blackLayer.bounds = self.bounds;
        CGRect rect = _blackLayer.bounds;
        rect.size.width = rect.size.width*2;
        rect.size.height = rect.size.height*2;
        _blackLayer.bounds = rect;
        _blackLayer.backgroundColor = [[UIColor blackColor] CGColor];

        //create image layer
        _nonStretchImageLayer = [CALayer layer];
        _nonStretchImageLayer.backgroundColor = [UIColor blackColor].CGColor;
        _nonStretchImageLayer.bounds = CGRectMake(0  , 0, self.bounds.size.width, self.bounds.size.height);
        _nonStretchImageLayer.frame = CGRectMake(0  , 0, self.bounds.size.width, self.bounds.size.height);
        _nonStretchImageLayer.contentsGravity = kCAGravityResizeAspect;//default is to resize
        _nonStretchImageLayer.contents = (id)self.imageView.image.CGImage;
        _nonStretchImageLayer.opacity = 0.5;

        //add layers to image view
        [self.imageView.layer addSublayer:_blackLayer];
        [self.imageView.layer addSublayer:_nonStretchImageLayer];
    }
    else
    {
        //remove from image view
        [_blackLayer removeFromSuperlayer];
        [_nonStretchImageLayer removeFromSuperlayer];

        //nil them out.
        _blackLayer = nil;
        _nonStretchImageLayer = nil;
    }
}  

Inspiration for this work around came from here

这项工作的灵感来自这里

回答by MacMark

I guess the easiest solution is to use UIImage's resizableImageWithCapInsets method. Use UIEdgeInsetsMake to configure the free spaces.

我想最简单的解决方案是使用 UIImage 的 resizableImageWithCapInsets 方法。使用 UIEdgeInsetsMake 配置可用空间。

回答by ozba

What you need to do is add your image as a UIImageView.

您需要做的是将您的图像添加为 UIImageView。

Than add a button with transperent background (UIColor ClearColor) on top of it with your desired width and height.

然后在其顶部添加一个具有透明背景(UIColor ClearColor)的按钮,并具有所需的宽度和高度。