web-dev-qa-db-ja.com

自動レイアウトを使用して丸いimageViewを丸く保つ方法は?

幅と高さの制限を設定せずに自動レイアウトで形状を保持できる円形の画像ビューに長方形の画像ビューを変更するにはどうすればよいですか?これにより、imageViewがそのサイズを定義し、前後の制約を使用して、周囲のオブジェクトに比べてサイズを大きくしたり小さくしたりできます。

先日、同様の質問をしましたが、これはもっと簡潔な方法で提起されると思います。本当にありがとう!

[〜#〜] edit [〜#〜]

わかりました、私はこれを可能な限り簡単にするためにやり直しました。 「Cell」という名前のビューと、セル内に「dog」という名前のUIImageViewがあります。コンソールには「制約を同時に満たすことができません」ということはもうありません。自動レイアウトを使用する2つの単純なビューです。私はまだこのコードを使用してUIImageViewを丸めようとしています:

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

セル制約のセットアップは次のとおりです。

screenshot 1

プロファイルpic制約のセットアップは次のとおりです。

screenshot 2

以下は、コードなし、丸めなし、ニースと正方形の結果です。

screenshot 3

丸めるコードの結果は次のとおりです。

screenshot 4

丸みを帯びたコードがないと画像が正方形になり、コードがあるとダイヤモンドの形になるため、これは意味がありません。正方形の場合、問題のない円ではないでしょうか?

EDIT 2

下の制約を削除し、スーパービューと同じ高さの.637の乗数を追加すると、次のようになります。

screenshot 5

41
CHM

残念ながら、cornerRadiusと自動レイアウトを使用してこれを行うことはできません。CGLayerは自動レイアウトの影響を受けないため、ビューのサイズを変更しても、一度設定された半径は変更されません。円がその形を失うことに気づきました。

UIImageViewのカスタムサブクラスを作成し、layoutSubviewsをオーバーライドして、imageviewの境界が変わるたびにcornerRadiusを設定できます。

[〜#〜] edit [〜#〜]

例は次のようになります。

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

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

        self.layer.cornerRadius = radius
    }
}

そして、明らかに、[円を維持するために] Foobarインスタンスの幅を高さと同じに制限する必要があります。おそらく、FoobarインスタンスのcontentModeUIViewContentMode.ScaleAspectFillに設定して、画像の描画方法を知ることもできます(これは、画像が切り取られる可能性が高いことを意味します)。

72
Rupert

ViewWillLayoutSubviewsで半径を設定すると問題が解決します

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

.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」としてクラスを与えます。 100%作業中...お楽しみください

11

まず最初に、幅と高さが等しい場合、UIView/UIImageViewonlyの円形状を取得できることに言及する必要があります。理解することが重要です。他のすべての場合(幅!=高さの場合)、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メニューに表示される新しいオプションが表示されます(詳細はスクリーンショット)。

最終結果はこのようになるはずです。

4
Hamsternik

あるビューを別のビューのサブビューとして追加すると、ネットビューは必ずしもスーパービューと同じ高さになるとは限りません。それが問題のようです。解決策は、imageViewをサブビューとして追加するのではなく、backgroundViewの上に配置することです。以下の画像では、UILabelをbackgroundViewとして使用しています。

screenshot

また、あなたの場合、cornerRadiusを設定するときは、これを使用します:let radius: CGFloat = self.bounds.size.height / 2.0

4
Randel G. Smith

Swift 4 +omaralbeik's answer に基づくクリーンなソリューション

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)
    }
1
Maverick

私のハッキングソリューションを使用すると、フレームサイズの変更に加えて、スムーズなコーナー半径アニメーションが得られます。

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

それは美しくはなく、複雑なマルチアニメーションでは機能しないかもしれませんが、質問には答えます。

1

私は同じ問題を抱えており、ここで何が起こったのかがわかりました。いくつかのアイデアがあなたを助けることができることを願っています:けん引の間に異なるものがあります:

  1. ストーリーボードのprofileImageView
  2. viewDidLoadのprofileImageView

viewDidLoadの場合とストーリーボードの場合、バインドされたフレームのサイズは異なります。ビューが異なるデバイスサイズに合わせてサイズ変更されるためです。 print(profileImageView.bounds.size)viewDidLoadおよびviewDidAppearで試すことができます。設定したviewDidLoadでサイズを確認できますcornerRadiusは実際の「実行中」サイズではありません。

ヒント:ImageViewのサブクラスを使用して回避するか、ストーリーボードで使用しないでください。

0
livinspring

カスタムIBInspectable cornerRadiusPercentを追加したので、コードなしで実行できます。

enter image description here

  1. 拡張

    extension UIView {
    
    @IBInspectable var cornerRadiusPercent: CGFloat {
        get {
           return 0
        }
        set {
            if newValue == 0
            {
                 self.setObjectTag(nil)
                return
            }
    
            let watcher = CornerRadiusPercent(view: self, percent: newValue)
    
            self.setObjectTag(watcher)
        }
    }
    }
    
  2. CornerRadiusPercent

    class CornerRadiusPercent : NSObject{
    
    weak var view:UIView?
    let percent:CGFloat
    
    init(view:UIView, percent:CGFloat) {
        self.view = view
        self.percent = percent
    
        super.init()
    
        view.layer.cornerRadius = view.bounds.width * percent
        view.addObserver(self, forKeyPath: "bounds", options: [], context: nil)
    }
    
    deinit {
        view?.removeObserver(self, forKeyPath: "bounds")
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    
        if keyPath == "bounds", let view = self.view
        {
            view.layer.cornerRadius = view.bounds.width * percent            
            view.setObjectTag(nil)
        }
    
    }
    
    }
    
  3. ObjectTag

    extension NSObject {
    
    fileprivate struct ObjectTagKeys {
        static var ObjectTag = "ObjectTag"
    }
    
    func setObjectTag(_ tag:Any!) {
        objc_setAssociatedObject(self, &ObjectTagKeys.ObjectTag, tag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    
    func getObjectTag() -> Any
    {
        return objc_getAssociatedObject(self, &ObjectTagKeys.ObjectTag)
    }
    
    }
    
0
Chen Jiling

UIImageViewをサブクラス化した場合。次に、この魔法のコードを追加します。

記述:Swift

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

私は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
_

on viewWillLayoutSubviews() method角の半径を

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

基本的に、画像の高さを計算してから2で割るだけです。0.2はbackgroungViewの高さの制約乗数で、0.8は画像の幅/高さの制約乗数です。

0
Vasil Kanev