如何使用自动布局保持圆形imageView轮?

时间:2015-09-02 20:54:54

标签: ios swift xcode autolayout ios-autolayout

如何将矩形图像视图转换为可以在自动布局中保持形状而不设置宽度和高度限制的圆形图像视图?从而允许imageView定义它的大小,并且相对于周围的对象,它的大小越来越小,具有前导,尾随,顶部和底部约束。

前几天我问了一个类似的问题,但我认为这可能会以更简洁的方式提出。非常感谢!

修改

好的,我开始尝试尽可能简单。我有一个名为" Cell"和一个名为" dog"的UIImageView在细胞内,这就是它。我没有"无法同时满足约束"在控制台中,只有两个使用自动布局的简单视图。我还在尝试使用此代码来绕过UIImageView:

profileImageView.layer.cornerRadius = profileImageView.frame.size.width / 2
profileImageView.clipsToBounds = true

这是单元格约束设置:

screenshot 1

以下是配置文件pic约束设置:

screenshot 2

这是没有代码的结果,没有舍入,但很好和正方形:

screenshot 3

以下是圆形代码的结果:

screenshot 4

这对我来说没有意义,因为没有舍入代码,图像是方形的,并且代码是菱形的。如果它不是一个没有问题的圆圈吗?

编辑2

这是当我删除底部约束并为superview添加相同高度的.637乘数时会发生什么。

screenshot 5

15 个答案:

答案 0 :(得分:70)

很遗憾,您无法使用cornerRadius和自动布局执行此操作 - CGLayer不受自动布局的影响,因此视图大小的任何更改都不会更改一旦设置的半径,正如你所注意到的那样,圆形会失去它的形状。

您可以创建UIImageView的自定义子类并覆盖layoutSubviews,以便每次更改imageview的边界时设置cornerRadius

修改

示例可能如下所示:

class Foo: UIImageView {
    override func layoutSubviews() {
        super.layoutSubviews()

        let radius: CGFloat = self.bounds.size.width / 2.0

        self.layer.cornerRadius = radius
    }
}

显然,您必须将Foobar实例的宽度限制为与高度相同(以保持圆形)。您可能还希望将Foobar实例的contentMode设置为UIViewContentMode.ScaleAspectFill,以便它知道如何绘制图像(这意味着图像可能会被裁剪)。

答案 1 :(得分:31)

在viewWillLayoutSubviews中设置半径将解决问题

override func viewWillLayoutSubviews() {
  super.viewWillLayoutSubviews()
  profileImageView.layer.cornerRadius = profileImageView.frame.height / 2.0
}

答案 2 :(得分:10)

在.h文件中创建新界面,如

@interface CornerClip : UIImageView

@end

和.m文件中的实现,如

@implementation cornerClip


-(void)layoutSubviews
{
    [super layoutSubviews];

    CGFloat radius = self.bounds.size.width / 2.0;

    self.layer.cornerRadius = radius;

}

@end

现在只需将课程作为" CornerClip"到你的imageview。 100%工作......享受

答案 3 :(得分:4)

当您将一个视图添加为另一个视图时,网状视图的高度不一定与其超视图相同。这就是问题所在。解决方案是不将您的imageView添加为子视图,而是将其放在backgroundView之上。在下面的图片中,我使用UILabel作为我的backgroundView。

screenshot

同样在您的情况下,当您设置cornerRadius时,请使用:let radius: CGFloat = self.bounds.size.height / 2.0

答案 4 :(得分:3)

首先,我要提到的是,如果宽度和高度相等,则只能为您的UIView / UIImageView设置一个圆形。了解这一点很重要。在所有其他情况下(当width!= height时),您将不会得到圆形,因为UI实例的初始形状是矩形。

好的,因此,UIKit SDK为开发人员提供了一种机制,可以操纵UIview的 layer 实例以某种方式更改层的任何参数,包括设置mask来替换初始形状自定义的UIView元素。这些工具是 IBDesignable / IBInspectable 。目的是直接通过Interface Builder预览我们的自定义视图。

因此,使用这些关键字,我们可以编写我们的自定义类,无论我们是否需要为UI元素加圆角,该类仅处理单个条件。

例如,让我们创建从 UIImageView 扩展的类。

@IBDesignable
class UIRoundedImageView: UIImageView {

    @IBInspectable var isRoundedCorners: Bool = false {
        didSet { setNeedsLayout() }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if isRoundedCorners {
            let shapeLayer = CAShapeLayer()
            shapeLayer.path = UIBezierPath(ovalIn:
                CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.width, height: bounds.height
            )).cgPath
            layer.mask = shapeLayer
        }
        else {
            layer.mask = nil
        }

    }

}

为UIImageView元素(狗图片所在的位置)设置类名称后,在情节提要中,您将获得一个新选项,该选项出现在 Attributes Inspector 菜单中(详细信息在屏幕截图中)

最终结果应该像这样。

答案 5 :(得分:1)

使用我的hacky解决方案,您将获得平滑的角半径动画以及帧大小更改。

假设你有ViewSubclass:UIView。它应包含以下代码:

class ViewSubclass: UIView {
    var animationDuration : TimeInterval?
    let imageView = UIImageView()
    //some imageView setup code

    override func layoutSubviews() {
        super.layoutSubviews()

        if let duration = animationDuration {
            let anim = CABasicAnimation(keyPath: "cornerRadius")
            anim.fromValue = self.imageView.cornerRadius
            let radius = self.imageView.frame.size.width / 2
            anim.toValue = radius
            anim.duration = duration
            self.imageView.layer.cornerRadius = radius
            self.imageView.layer.add(anim, forKey: "cornerRadius")
        } else {
            imageView.cornerRadius = imageView.frame.size.width / 2
        }

        animationDuration = nil
    }
}

然后你必须这样做:

let duration = 0.4 //For example
instanceOfViewSubclass.animationDuration = duration
UIView.animate(withDuration: duration, animations: { 
    //Your animation
    instanceOfViewSubclass.layoutIfNeeded()
})

它不漂亮,可能无法用于复杂的多动画,但确实可以回答这个问题。

答案 6 :(得分:0)

我有同样的问题,现在我得到了这里发生的事情,希望一些想法可以帮助你: 丝束之间有一些不同的东西:

  1. 您在storyboard中的profileImageView
  2. 您在viewDidLoad
  3. 中的profileImageView

    viewDidLoad和故事板中绑定和帧的大小不同,只是因为视图针对不同的设备大小调整大小。 您可以在print(profileImageView.bounds.size) viewDidLoadviewDidAppear中尝试cornerRadius,你会发现你设置的viewDidLo中的大小require 'eventmachine' require 'em-http' require 'json' http = EM::HttpRequest.new("api_url", :keepalive => true, :connect_timeout => 0, :inactivity_timeout => 0) EventMachine.run do s = http.get({'accept' => 'application/json'}) s.stream do |data| puts data end s.errback do puts "FATAL EM STOPPED: #{response.error}" EM.stop end end 不是真正的“正在运行”大小。

    给你的提示: 您可以使用ImageView的子类来避免它,或者不在故事板中使用它,

答案 7 :(得分:0)

如果您已经将UIImageView子类化了。然后只需在其中添加这段神奇的代码。

写于: Swift 3

override func layoutSubviews() {
    super.layoutSubviews()
    if self.isCircular! {
        self.layer.cornerRadius = self.bounds.size.width * 0.50
    }
}

答案 8 :(得分:0)

基于omaralbeik's answer

的快速4 + 干净解决方案
import UIKit

extension UIImageView {

    func setRounded(borderWidth: CGFloat = 0.0, borderColor: UIColor = UIColor.clear) {
        layer.cornerRadius = frame.width / 2
        layer.masksToBounds = true
        layer.borderWidth = borderWidth
        layer.borderColor = borderColor.cgColor
    }
}

UIViewController中的示例用法

1。简单舍入的UIImageView

override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        imageView.setRounded()
    }

2。带有边框宽度和颜色的圆形UIImageView

override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        imageView.setRounded(borderWidth: 1.0, borderColor: UIColor.red)
    }

答案 9 :(得分:0)

我对iOS本机开发非常陌生,但是我遇到了同样的问题并找到了解决方案。

this was the goal

因此绿色背景具有以下限制:

backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.topAnchor.constraint(equalTo: superview!.safeAreaLayoutGuide.topAnchor).isActive = true
backgroundView.leftAnchor.constraint(equalTo: superview!.leftAnchor).isActive = true
backgroundView.widthAnchor.constraint(equalTo: superview!.widthAnchor).isActive = true
backgroundView.heightAnchor.constraint(equalTo: superview!.heightAnchor, multiplier: 0.2).isActive = true

图片限制:

avatar.translatesAutoresizingMaskIntoConstraints = false
avatar.heightAnchor.constraint(equalTo: backgroundView.heightAnchor, multiplier: 0.8).isActive = true
avatar.widthAnchor.constraint(equalTo: backgroundView.heightAnchor, multiplier: 0.8).isActive = true
avatar.centerYAnchor.constraint(equalTo: backgroundView.centerYAnchor, constant: 0).isActive = true
avatar.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 20).isActive = true

viewWillLayoutSubviews()方法上,我设置了拐角半径

avatar.layer.cornerRadius = (self.frame.height * 0.2 * 0.8) / 2

基本上,我只是计算图像的高度,然后将其除以2。0.2是backgroungView高度约束乘数,0.8是图像宽度/高度约束乘数。

答案 10 :(得分:0)

编写此代码

override viewDidLayoutSubViews() {
profileImageView.layer.cornerRadius = profileImageView.frame.size.width / 2
profileImageView.clipsToBounds = true

}

在这种情况下,它将在您调用角半径代码的第一个代码中计算自动布局计算之后调用,然后再计算视图的实际大小,因为它是使用宽高比动态计算的,实际角半径是在等于宽度和视图的高度

答案 11 :(得分:0)

解决方案裁剪图像

[imageView setImage:[[imageView image] imageWithRoundedCorners:imageView.image.size.width/2]];
imageView.contentMode = UIViewContentModeScaleAspectFill;

我一直在寻找个人资料图片的相同解决方案。经过一番尝试之后,我了解了一些可行的方法,这是确保其安全的好方法。您可以使用以下功能从原始图像裁剪出圆形图像,然后不必担心拐角半径。

即使您的视图大小发生变化,也要发布此图片,使图像保持圆形并看起来不错。

答案 12 :(得分:-1)

imageView添加1:1宽高比约束,使其保持圆形,尽管有任何高度或宽度变化。

答案 13 :(得分:-1)

我添加了自定义IBInspectable cornerRadiusPercent,因此您无需任何代码即可完成操作。

class RoundButton: UIButton {

    override var bounds: CGRect {
        didSet {
            updateCornerRadius()
        }
    }


    //private var cornerRadiusWatcher : CornerRadiusPercent?
    @IBInspectable var cornerRadiusPercent: CGFloat = 0 {

        didSet {
            updateCornerRadius()
        }
    }

    func updateCornerRadius()
    {
        layer.cornerRadius = bounds.height * cornerRadiusPercent
    }

}

答案 14 :(得分:-5)

可以通过为需要在运行时更改的约束创建IBOutlet来轻松完成。以下是代码:

  1. 为需要在运行时更改的约束创建IBOutlet

    @IBOutlet var widthConstraint: NSLayoutConstraint!
    
  2. viewDidLoad()中添加以下代码:

    self.widthConstraint.constant = imageWidthConstraintConstant()
    
  3. 下面的函数确定设备类型会相应地更改宽度约束。

    func imageWidthConstraintConstant() -> CGFloat {
    
        switch(self.screenWidth()) {
    
        case 375:
            return 100
    
        case 414:
            return 120
    
        case 320:
            return 77
    
        default:
            return 77
        }
    }