幅と高さの制限を設定せずに自動レイアウトで形状を保持できる円形の画像ビューに長方形の画像ビューを変更するにはどうすればよいですか?これにより、imageViewがそのサイズを定義し、前後の制約を使用して、周囲のオブジェクトに比べてサイズを大きくしたり小さくしたりできます。
先日、同様の質問をしましたが、これはもっと簡潔な方法で提起されると思います。本当にありがとう!
[〜#〜] edit [〜#〜]
わかりました、私はこれを可能な限り簡単にするためにやり直しました。 「Cell」という名前のビューと、セル内に「dog」という名前のUIImageViewがあります。コンソールには「制約を同時に満たすことができません」ということはもうありません。自動レイアウトを使用する2つの単純なビューです。私はまだこのコードを使用してUIImageViewを丸めようとしています:
profileImageView.layer.cornerRadius = profileImageView.frame.size.width / 2
profileImageView.clipsToBounds = true
セル制約のセットアップは次のとおりです。
プロファイルpic制約のセットアップは次のとおりです。
以下は、コードなし、丸めなし、ニースと正方形の結果です。
丸めるコードの結果は次のとおりです。
丸みを帯びたコードがないと画像が正方形になり、コードがあるとダイヤモンドの形になるため、これは意味がありません。正方形の場合、問題のない円ではないでしょうか?
EDIT 2
下の制約を削除し、スーパービューと同じ高さの.637の乗数を追加すると、次のようになります。
残念ながら、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
インスタンスのcontentMode
をUIViewContentMode.ScaleAspectFill
に設定して、画像の描画方法を知ることもできます(これは、画像が切り取られる可能性が高いことを意味します)。
ViewWillLayoutSubviewsで半径を設定すると問題が解決します
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
profileImageView.layer.cornerRadius = profileImageView.frame.height / 2.0
}
.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%作業中...お楽しみください
まず最初に、幅と高さが等しい場合、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メニューに表示される新しいオプションが表示されます(詳細はスクリーンショット)。
最終結果はこのようになるはずです。
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)
}
私のハッキングソリューションを使用すると、フレームサイズの変更に加えて、スムーズなコーナー半径アニメーションが得られます。
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()
})
それは美しくはなく、複雑なマルチアニメーションでは機能しないかもしれませんが、質問には答えます。
私は同じ問題を抱えており、ここで何が起こったのかがわかりました。いくつかのアイデアがあなたを助けることができることを願っています:けん引の間に異なるものがあります:
viewDidLoad
のprofileImageViewviewDidLoad
の場合とストーリーボードの場合、バインドされたフレームのサイズは異なります。ビューが異なるデバイスサイズに合わせてサイズ変更されるためです。 print(profileImageView.bounds.size)
viewDidLoad
およびviewDidAppear
で試すことができます。設定したviewDidLoadでサイズを確認できますcornerRadius
は実際の「実行中」サイズではありません。
ヒント:ImageViewのサブクラスを使用して回避するか、ストーリーボードで使用しないでください。
カスタムIBInspectable cornerRadiusPercentを追加したので、コードなしで実行できます。
拡張
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)
}
}
}
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)
}
}
}
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)
}
}
UIImageViewをサブクラス化した場合。次に、この魔法のコードを追加します。
記述:Swift
override func layoutSubviews() {
super.layoutSubviews()
if self.isCircular! {
self.layer.cornerRadius = self.bounds.size.width * 0.50
}
}
私はiOSのネイティブ開発は初めてですが、同じ問題があり、解決策を見つけました。
したがって、緑の背景には次の制約があります。
_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は画像の幅/高さの制約乗数です。