【问题标题】:How do I prevent a button's background image from stretching?如何防止按钮的背景图像拉伸?
【发布时间】:2012-01-30 07:51:57
【问题描述】:

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

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

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

提前致谢!

【问题讨论】:

  • 你真的需要它作为背景图片吗?您是否需要实际编写文本或在其上放置另一个图像?如果没有,请使用图像而不是背景图像,因为默认情况下只有背景图像会被拉伸以匹配框架。
  • @Raphael 这些答案都不够吗?

标签: ios cocoa-touch uiimageview uibutton uikit


【解决方案1】:

您可以使用 uibutton.imageView.contentMode 不拉伸:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(posX, posY, widthButton, heightButton);
    [button setTitle:@"" forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:@"imageNamed"] forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:@"imageNamedHighlighted"] forState:UIControlStateHighlighted];
    button.imageView.contentMode = UIViewContentModeScaleAspectFit;
    [button addTarget:self action:@selector(functionMenu:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview: button];

【讨论】:

    【解决方案2】:

    Zoltán Matók answer 的 Swift 版本

    只是我使用 SnapKit 进行自动布局和语法糖的代码副本然后用于初始化的库,它应该与普通 Apple 的编程布局方式类似。

       let backButton = UIButton(type: .custom).then { (button) in
            let image = UIImage(named: "backButtonIcon")?.withRenderingMode(.alwaysOriginal)
            let imageView = UIImageView(image: image)
            button.addSubview(imageView)
            imageView.snp.makeConstraints { (make) in
                make.center.equalTo(button.snp.center)
            }
            button.bringSubviewToFront(imageView)
            button.contentMode = .scaleAspectFit
            button.backgroundColor = .clear
            button.isUserInteractionEnabled = true
            button.isEnabled = true
            
            
            button.imageView?.contentMode = .scaleAspectFit
            button.imageView?.snp.makeConstraints({ (make) in
                make.height.width.equalTo(24)
            })
            button.snp.makeConstraints { (make) in
                make.height.width.equalTo(24)
            }
        }
    
    

    【讨论】:

      【解决方案3】:

      可能会帮助某人

      button.subviews.first?.contentMode = .scaleAspectFit
      

      【讨论】:

        【解决方案4】:

        很简单:

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

        【讨论】:

        • 这对我有用,只要确保您的按钮类型从属性检查器设置为自定义。
        【解决方案5】:

        也偶然发现了这个问题。

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

        我有一个 100x40 的按钮和 100x100 的图像,它会显得挤压,不适合,正如人们从“Aspect Fit”选项中推断的那样。实际上,这些视图选项都没有效果。

        我只需要重新调整它以使其适合按钮,然后使用 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];
        

        【讨论】:

          【解决方案6】:

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

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

          请参阅bradley's 答案,这里: https://stackoverflow.com/a/20303841/1147286


          原答案:

          不要调用-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. 创建图像视图
          2. 设置内容模式和框架
          3. 我还设置了一个可识别的标签,这样当屏幕旋转时,我可以很容易地在按钮的子视图中找到我的自定义 imageView 并重置它的框架
          4. 将其作为子视图添加到按钮
          5. 将按钮的正面 imageView 放在最前面,这样我们的自定义 imageView 就不会重叠了

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

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

          【讨论】:

            【解决方案7】:

            使用按钮的标题插图可能是最简洁和最简单的方法。

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

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

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

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

                Answerbot 用正确和正确的做法来回答这个问题。不要与操作系统抗争并按预期使用东西总是好的建议。但是,有时您需要打破规则。

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

                需要代码?

                - (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;
                    }
                }  
                

                这项工作的灵感来自here

                【讨论】:

                  【解决方案10】:

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

                  【讨论】:

                    【解决方案11】:

                    很多人在按钮图像方面犯了同样的错误,然后跳过箍试图使按钮按他们期望的那样工作。让我们一劳永逸地解决这个问题:

                    UIButton 可以显示两种类型的图像——前景图像和背景图像。按钮的背景图像应替换按钮的背景纹理。因此,它拉伸以填充整个背景是有意义的。但是,按钮的前景图像应该是一个图标,可能会或可能不会显示在文本旁边;它不会拉伸。如果框架小于图像,它可能会收缩,但不会拉伸。您甚至可以使用 Interface Builder 中的 Control 对齐属性来设置前景图像的对齐方式。

                    按钮的前景和背景图像可以用这样的代码设置:

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

                    【讨论】:

                    • 当您需要在其顶部显示非拉伸图像时,您会怎么做?
                    • 很奇怪,每当我设置 UIButton 图像属性时,标题文本就会消失。有没有办法防止这种情况?编辑:哦,文字偏右了..奇怪,我想我会玩调整,直到它直接位于前景图像下方
                    • @powerj1984 如果您希望文本位于图像顶部,您应该使用 backgroundImage。前景图像应替换文本或与文本并排放置。如果您正在调整文本以强制它位于前景图像的顶部,那么您做错了。
                    • @ZakyGerman 如果您需要在背景中放置非拉伸图像,您仍应使用背景图像属性。只要您使按钮的大小与背景图像相同,它就不会拉伸。
                    • 我目前正在我的应用程序集中看到一张图像,其中“setImage()”被拉伸以填充按钮。我不知道这个答案的内容是否不再正确,或者是否有我不知道的东西。我倾向于假设后者,但我认为值得一提。
                    【解决方案12】:

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

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

                    【讨论】:

                    • 这实际上是一个糟糕的建议,因为图像不会成为按钮的一部分,也不会反映状态变化(这会破坏将图像作为按钮一部分的目的)。跨度>
                    • 为此,您可以在点击按钮时更改图像以模拟状态更改
                    • @ozba 按钮已支持图像的状态更改。在清除按钮后面添加背景图像来模仿带有图像的按钮几乎从来都不是一个好主意,而且通常是一个非常糟糕的主意。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-11-12
                    • 1970-01-01
                    • 2010-12-09
                    • 1970-01-01
                    • 2017-01-18
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多