将按钮限制为 UIImageView 内的图像
Constrain button to image inside UIImageView
我有一个 UIImageView
并且用户可以设置图像以便 width/height
变化。我想在右上角添加一个 "x"- button
,但不是来自 UIImageView
,而是来自实际的 image
。
这是现在的样子。整个图就是UIImageView
,左边可以看到image
,右上角可以看到button
.
目前我是这样约束的:
theStackView.addArrangedSubview(self.imageView)
imageContainerView.addSubview(wishImageView)
imageContainerView.addSubview(deleteImageButton)
imageContainerView.heightAnchor.constraint(equalToConstant: 60).isActive = true
imageContainerView.isHidden = true
wishImageView.leadingAnchor.constraint(equalTo: imageContainerView.leadingAnchor, constant: 20).isActive = true
wishImageView.topAnchor.constraint(equalTo: imageContainerView.topAnchor, constant: 3).isActive = true
wishImageView.bottomAnchor.constraint(equalTo: imageContainerView.bottomAnchor, constant: 3).isActive = true
wishImageView.trailingAnchor.constraint(equalTo: imageContainerView.trailingAnchor, constant: -20).isActive = true
deleteImageButton.widthAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.heightAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.topAnchor.constraint(equalTo: wishImageView.topAnchor, constant: 5).isActive = true
deleteImageButton.trailingAnchor.constraint(equalTo: wishImageView.trailingAnchor, constant: -5).isActive = true
这显然是错误的,但有没有办法将其限制为实际的 image
?
使用您的图片宽度来定位按钮。粗略了解并平滑 UI
let imgWidth = iv.image?.size.width
NSLayoutConstraint.activate([
iv.leadingAnchor.constraint(equalTo: view.leadingAnchor),
iv.trailingAnchor.constraint(equalTo: view.trailingAnchor),
iv.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
iv.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
btn.widthAnchor.constraint(equalToConstant: 20),
btn.heightAnchor.constraint(equalToConstant: 20),
btn.leadingAnchor.constraint(equalTo: iv.leadingAnchor , constant: (imgWidth ?? 0) > iv.frame.width ? iv.frame.width-20 : imgWidth ?? 0),
//The issue happen when Image width is larger than the your imageview.Validate it for better result.
btn.topAnchor.constraint(equalTo: iv.topAnchor,constant: 10)
])
我整理了一个示例项目,repo 是 here。
基本上你需要做几件事:
- 计算 您的
UIImageView
帧大小以及显示在 scaledAspectFit
中的 UIMage
帧大小。
- 创建两个命名约束并在获得按钮框架后动态重新定位按钮。
首先,您需要记住帧可能要到 viewDidLayoutSubviews
才会真正设置。我创建了一个 UIImageView
扩展,可以轻松计算 UIImage
框架的实际位置。 (这是旧的但有效的代码。我相信它可以改进。)
extension UIImageView {
public var scaleFactor:CGFloat {
guard let image = self.image, self.frame != CGRect.zero else {
return 0.0
}
let frame = self.frame
let extent = image.size
let heightFactor = frame.height/extent.height
let widthFactor = frame.width/extent.width
if extent.height > frame.height || extent.width > frame.width {
if heightFactor < 1 && widthFactor < 1 {
if heightFactor > widthFactor {
return widthFactor
} else {
return heightFactor
}
} else if extent.height > frame.height {
return heightFactor
} else {
return widthFactor
}
} else if extent.height < frame.height && extent.width < frame.width {
if heightFactor < widthFactor {
return heightFactor
} else {
return widthFactor
}
} else {
return 1
}
}
public var imageSize:CGSize {
if self.image == nil {
return CGSize.zero
} else {
return CGSize(width: (self.image?.size.width)!, height: (self.image?.size.height)!)
}
}
public var scaledSize:CGSize {
guard let image = self.image, self.frame != CGRect.zero else {
return CGSize.zero
}
let factor = self.scaleFactor
return CGSize(width: image.size.width * factor, height: image.size.height * factor)
}
}
对于第二个项目符号,您需要创建两个 NSConstraint
类型的变量。为此,我改编了两年前的 :
var btnTop:NSLayoutConstraint!
var btnTrailing:NSLayoutConstraint!
并且在`viewDidLoad:
button.heightAnchor.constraint(equalToConstant: 20).isActive = true
button.widthAnchor.constraint(equalToConstant: 20).isActive = true
btnTop = button.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 10)
btnTop.isActive = true
btnTrailing = button.trailingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: -10)
btnTrailing.isActive = true
请注意,您需要为每个约束编写两行代码!我从来没有弄清楚为什么,但是如果你试图用实际约束添加 isActive
属性 编译器不知道变量的正确类型。
现在,您将所有这些联系在一起 viewDidLayoutSubviews
:
let scaledSize = imageView.scaledSize
var imageFrame = CGRect(origin: CGPoint.zero, size: scaledSize)
if scaledSize.width == imageView.frame.width {
// image fills view along width, calculate Y constant
imageFrame.origin.y = (imageView.frame.height - scaledSize.height) / 2
} else {
// image fills view along height, calculate X constant
imageFrame.origin.x = (imageView.frame.width - scaledSize.width) / 2
}
//btnTop.constant = imageFrame.width - 30
btnTop.constant = imageFrame.origin.y + 10
btnTrailing.constant = ((imageView.frame.width - imageFrame.width - imageFrame.origin.x) * -1) - 10
将按钮放在左上角 简单得多 - 我花了整整 20 分钟才得到正确的计算,使它变成右上角!
在我的测试项目中,我将这段代码封装在 repositionCloseButton()
中,只要应用程序显示新图像就会调用它。这应该适用于纵向和横向,以及纵向和横向图像 - 将 20x20 关闭按钮放置在距离图像右上角 10 点的位置。
我有一个 UIImageView
并且用户可以设置图像以便 width/height
变化。我想在右上角添加一个 "x"- button
,但不是来自 UIImageView
,而是来自实际的 image
。
这是现在的样子。整个图就是UIImageView
,左边可以看到image
,右上角可以看到button
.
目前我是这样约束的:
theStackView.addArrangedSubview(self.imageView)
imageContainerView.addSubview(wishImageView)
imageContainerView.addSubview(deleteImageButton)
imageContainerView.heightAnchor.constraint(equalToConstant: 60).isActive = true
imageContainerView.isHidden = true
wishImageView.leadingAnchor.constraint(equalTo: imageContainerView.leadingAnchor, constant: 20).isActive = true
wishImageView.topAnchor.constraint(equalTo: imageContainerView.topAnchor, constant: 3).isActive = true
wishImageView.bottomAnchor.constraint(equalTo: imageContainerView.bottomAnchor, constant: 3).isActive = true
wishImageView.trailingAnchor.constraint(equalTo: imageContainerView.trailingAnchor, constant: -20).isActive = true
deleteImageButton.widthAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.heightAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.topAnchor.constraint(equalTo: wishImageView.topAnchor, constant: 5).isActive = true
deleteImageButton.trailingAnchor.constraint(equalTo: wishImageView.trailingAnchor, constant: -5).isActive = true
这显然是错误的,但有没有办法将其限制为实际的 image
?
使用您的图片宽度来定位按钮。粗略了解并平滑 UI
let imgWidth = iv.image?.size.width
NSLayoutConstraint.activate([
iv.leadingAnchor.constraint(equalTo: view.leadingAnchor),
iv.trailingAnchor.constraint(equalTo: view.trailingAnchor),
iv.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
iv.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
btn.widthAnchor.constraint(equalToConstant: 20),
btn.heightAnchor.constraint(equalToConstant: 20),
btn.leadingAnchor.constraint(equalTo: iv.leadingAnchor , constant: (imgWidth ?? 0) > iv.frame.width ? iv.frame.width-20 : imgWidth ?? 0),
//The issue happen when Image width is larger than the your imageview.Validate it for better result.
btn.topAnchor.constraint(equalTo: iv.topAnchor,constant: 10)
])
我整理了一个示例项目,repo 是 here。
基本上你需要做几件事:
- 计算 您的
UIImageView
帧大小以及显示在scaledAspectFit
中的UIMage
帧大小。 - 创建两个命名约束并在获得按钮框架后动态重新定位按钮。
首先,您需要记住帧可能要到 viewDidLayoutSubviews
才会真正设置。我创建了一个 UIImageView
扩展,可以轻松计算 UIImage
框架的实际位置。 (这是旧的但有效的代码。我相信它可以改进。)
extension UIImageView {
public var scaleFactor:CGFloat {
guard let image = self.image, self.frame != CGRect.zero else {
return 0.0
}
let frame = self.frame
let extent = image.size
let heightFactor = frame.height/extent.height
let widthFactor = frame.width/extent.width
if extent.height > frame.height || extent.width > frame.width {
if heightFactor < 1 && widthFactor < 1 {
if heightFactor > widthFactor {
return widthFactor
} else {
return heightFactor
}
} else if extent.height > frame.height {
return heightFactor
} else {
return widthFactor
}
} else if extent.height < frame.height && extent.width < frame.width {
if heightFactor < widthFactor {
return heightFactor
} else {
return widthFactor
}
} else {
return 1
}
}
public var imageSize:CGSize {
if self.image == nil {
return CGSize.zero
} else {
return CGSize(width: (self.image?.size.width)!, height: (self.image?.size.height)!)
}
}
public var scaledSize:CGSize {
guard let image = self.image, self.frame != CGRect.zero else {
return CGSize.zero
}
let factor = self.scaleFactor
return CGSize(width: image.size.width * factor, height: image.size.height * factor)
}
}
对于第二个项目符号,您需要创建两个 NSConstraint
类型的变量。为此,我改编了两年前的
var btnTop:NSLayoutConstraint!
var btnTrailing:NSLayoutConstraint!
并且在`viewDidLoad:
button.heightAnchor.constraint(equalToConstant: 20).isActive = true
button.widthAnchor.constraint(equalToConstant: 20).isActive = true
btnTop = button.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 10)
btnTop.isActive = true
btnTrailing = button.trailingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: -10)
btnTrailing.isActive = true
请注意,您需要为每个约束编写两行代码!我从来没有弄清楚为什么,但是如果你试图用实际约束添加 isActive
属性 编译器不知道变量的正确类型。
现在,您将所有这些联系在一起 viewDidLayoutSubviews
:
let scaledSize = imageView.scaledSize
var imageFrame = CGRect(origin: CGPoint.zero, size: scaledSize)
if scaledSize.width == imageView.frame.width {
// image fills view along width, calculate Y constant
imageFrame.origin.y = (imageView.frame.height - scaledSize.height) / 2
} else {
// image fills view along height, calculate X constant
imageFrame.origin.x = (imageView.frame.width - scaledSize.width) / 2
}
//btnTop.constant = imageFrame.width - 30
btnTop.constant = imageFrame.origin.y + 10
btnTrailing.constant = ((imageView.frame.width - imageFrame.width - imageFrame.origin.x) * -1) - 10
将按钮放在左上角 简单得多 - 我花了整整 20 分钟才得到正确的计算,使它变成右上角!
在我的测试项目中,我将这段代码封装在 repositionCloseButton()
中,只要应用程序显示新图像就会调用它。这应该适用于纵向和横向,以及纵向和横向图像 - 将 20x20 关闭按钮放置在距离图像右上角 10 点的位置。