调整动画大小后UIButton不尊重Aspect Fill contentMode

Posted

技术标签:

【中文标题】调整动画大小后UIButton不尊重Aspect Fill contentMode【英文标题】:UIButton not respect Aspect Fill contentMode after resizing animation 【发布时间】:2014-10-08 17:49:23 【问题描述】:

我正在使用自动布局。以下是视图的初始状态。

中间是一个包含在视图中的按钮。按钮有contentMode Aspect Fill,图片设置为按钮的背景图。

然后我用下面的代码对视图进行变换,将中心卡片放大以填满屏幕,并将图像移动到视图的顶部:

cardTrailingSpaceConstraint.constant = 0
cardLeadingSpaceConstraint.constant = 0
cardView.removeConstraint(cardAspectRatioConstraint)
let cardHeightConstraint = NSLayoutConstraint(item: cardView, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 1.0, constant: 0)
view.addConstraint(cardHeightConstraint)

dishImageButton.removeConstraint(dishButtonBottomSpaceConstraint)
let dishButtonHeightConstraint = NSLayoutConstraint(item: dishImageButton, attribute: .Height, relatedBy: .Equal, toItem: cardView, attribute: .Height, multiplier: 0.2, constant: 0)
cardView.addConstraint(dishButtonHeightConstraint)

cardView.setNeedsUpdateConstraints()
UIView.animateWithDuration(0.7, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.7, options: nil, animations:  [unowned self] () -> Void in
    self.cardHeader.alpha = 0
    self.cardView.layer.cornerRadius = 0
    self.cardView.layoutIfNeeded()

    )  [unowned self] (finished) -> Void in

        

结果是:

然而,这不是我想要的。该按钮不尊重 contentMode,然后图像被拉伸。

谁能告诉我如何维护按钮的Aspect Fill contentMode?

【问题讨论】:

【参考方案1】:
    将按钮类型设置为 UIButtonTypeCustom(故事板或 xib 中的“自定义”)。 设置按钮的图像,而不是按钮的背景图像。 在viewDidLoad 中,将button.imageView.contentMode 设置为UIViewContentMode.ScaleAspectFill

【讨论】:

为我工作。请记住在 #3 上将其绑定到 IBOutlet 以获得正确的按钮。 这很好用,但现在我遇到了约束问题。如何将约束目标设置为图像按钮,而不是背景按钮图像? 在 Swift 5.2 上工作。我的问题是我设置的是背景图像而不是图像。谢谢!【参考方案2】:

斯威夫特 3


脱离 Rob 的回答:

    let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 80, height: 30))
    btn.setImage(UIImage(named: "albumsBtn"), for: UIControlState.normal)
    btn.imageView?.contentMode = UIViewContentMode.scaleAspectFit
    btn.addTarget(self.navigationController, action: #selector(CustomGalleryViewController.showAlbums(_:)), for:  UIControlEvents.touchUpInside)
    let item = UIBarButtonItem(customView: btn)
    self.navigationItem.leftBarButtonItem = item

【讨论】:

【参考方案3】:

在 Xcode 10.1 中,您可以使用界面生成器。在右侧的属性检查器中,使用 Control 部分,如下所示:

【讨论】:

【参考方案4】:

[btn setImage:forState:]用法之前试试这个:

    btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
    btn.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
斯威夫特 4
//Center
btn.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.center

//Left
btn.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left

//Right
btn.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.right

【讨论】:

【参考方案5】:

Swift 2.x 版本:

let myButton = UIButton(type: .Custom)
myButton.frame = CGRectMake(0, 0, 200, 20)
myButton.backgroundColor = UIColor.blackColor()
myButton.imageView.contentMode = .ScaleAspectFill // ALTERNATIVE:  .ScaleAspectFit
myButton.setImage(UIImage(named: "myImageName"), forState: .Normal)
myButton.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
view.addSubview(myButton)

【讨论】:

绝对!对我来说,直到我制作了自定义类型,它才起作用。谢谢。【参考方案6】:

斯威夫特 2

button.imageView?.contentMode = UIViewContentMode.ScaleAspectFit

所有内容模式:

  .ScaleToFill
   .ScaleAspectFit
   .ScaleAspectFill
   .Redraw 
   .Center 
   .Top
   .Bottom
   .Left
   .Right
   .TopLeft
   .TopRight
   .BottomLeft
   .BottomRight

【讨论】:

【参考方案7】:

斯威夫特 4.2

扩展

// Inspectable image content mode
extension UIButton 
    /// 0 => .ScaleToFill
    /// 1 => .ScaleAspectFit
    /// 2 => .ScaleAspectFill
    @IBInspectable
    var imageContentMode: Int 
        get 
            return self.imageView?.contentMode.rawValue ?? 0
        
        set 
            if let mode = UIViewContentMode(rawValue: newValue),
                self.imageView != nil 
                self.imageView?.contentMode = mode
            
        
    

更新:这个和其他答案在 ios 11 中对我不起作用。最接近的答案是 @Jaro 但我认为最好制作一个 UIImageView 并在它上面添加一个按钮,或者创建一个自定义的 UIImageView 类,它有一个手势识别器和点击动画。

【讨论】:

您应该在扩展行中添加 @IBDesignable 以使其在界面生成器中工作 SWIFT 4.2 extension UIButton /// 0 => .ScaleToFill /// 1 => .ScaleAspectFit /// 2 => .ScaleAspectFill @IBInspectable var imageContentMode: Int get return self.imageView ?.contentMode.rawValue ?? 0 设置 if let mode = UIView.ContentMode(rawValue: newValue), self.imageView != nil self.imageView?.contentMode = mode 【参考方案8】:

语言似乎有更新。

我不得不深入挖掘以获得 xscoder 解决方案:

myButton.imageView.contentMode = .ScaleAspectFill 

更新版本如下:

myButton.imageView?.contentMode = UIView.ContentMode.scaleAspectFit

【讨论】:

【参考方案9】:

斯威夫特

对于按钮有 contentMode Aspect Fill:

btn.contentHorizontalAlignment = .fill
btn.contentVerticalAlignment = .fill
btn.imageView?.contentMode = .scaleAspectFill

【讨论】:

【参考方案10】:

Swift 5.0 用于自定义 UIButton.scaleAspectFill 的代码

var mainImageButton : UIButton = 
    var imageButton = UIButton()
    imageButton.translatesAutoresizingMaskIntoConstraints = false
    imageButton.contentMode = .scaleAspectFit
    imageButton.backgroundColor = .white
    imageButton.layer.cornerRadius = 80 / 2

    // The short way
    imageButton.contentMode = .scaleAspectFit

    // The long way
    imageButton.imageView?.contentMode = UIView.ContentMode.scaleAspectFill

    imageButton.clipsToBounds = true
    return imageButton
()

【讨论】:

【参考方案11】:

可能会帮助某人

button.subviews.first?.contentMode = .scaleAspectFit

【讨论】:

【参考方案12】:

您可以对按钮进行子类化并添加以下内容:

class FitButton: UIButton 

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)


    

    override func layoutSubviews() 
        self.imageView?.contentMode = .scaleAspectFill
        self.contentHorizontalAlignment = .fill
        self.contentVerticalAlignment = .fill
        super.layoutSubviews()


    


【讨论】:

【参考方案13】:

当我为 BarButtonItem 使用自定义按钮时,此解决方案对我有用 1. 从服务器加载图片 2. 裁剪图像 3. 设置按钮图片 这是裁剪图像的功能:

extension UIImage 
  func crop(to:CGSize) -> UIImage 
    guard let cgimage = self.cgImage else  return self 

    let contextImage: UIImage = UIImage(cgImage: cgimage)

    let contextSize: CGSize = contextImage.size

    //Set to square
    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    let cropAspect: CGFloat = to.width / to.height

    var cropWidth: CGFloat = to.width
    var cropHeight: CGFloat = to.height

    if to.width > to.height  //Landscape
        cropWidth = contextSize.width
        cropHeight = contextSize.width / cropAspect
        posY = (contextSize.height - cropHeight) / 2
     else if to.width < to.height  //Portrait
        cropHeight = contextSize.height
        cropWidth = contextSize.height * cropAspect
        posX = (contextSize.width - cropWidth) / 2
     else  //Square
        if contextSize.width >= contextSize.height  //Square on landscape (or square)
            cropHeight = contextSize.height
            cropWidth = contextSize.height * cropAspect
            posX = (contextSize.width - cropWidth) / 2
        else //Square on portrait
            cropWidth = contextSize.width
            cropHeight = contextSize.width / cropAspect
            posY = (contextSize.height - cropHeight) / 2
        
    

    let rect: CGRect = CGRect(x : posX, y : posY, width : cropWidth, height : cropHeight)

    // Create bitmap image from context using the rect
    let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!

    // Create a new image based on the imageRef and rotate back to the original orientation
    let cropped: UIImage = UIImage(cgImage: imageRef, scale: self.scale, orientation: self.imageOrientation)

    cropped.draw(in: CGRect(x : 0, y : 0, width : to.width, height : to.height))

    return cropped
  

【讨论】:

以上是关于调整动画大小后UIButton不尊重Aspect Fill contentMode的主要内容,如果未能解决你的问题,请参考以下文章

动画 UIView 框架不尊重约束?

查找 UIButton 调整后的字体大小值?

是否可以通过 Aspect Fit 调整大小在 Core Graphics 中显示图像?

UIButton的imageView在调整大小时变得不隐藏

如何调整自定义 UIButton 的图像大小?

设置 UIButton 的 backgroundImage 时不调整大小,但定位