将按钮限制为 UIImageView 内的图像
Posted
技术标签:
【中文标题】将按钮限制为 UIImageView 内的图像【英文标题】:Constrain button to image inside UIImageView 【发布时间】:2020-04-12 18:12:41 【问题描述】:我有一个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
?
【问题讨论】:
这个 UIImageView 的大小是固定的吗? @DilanAnuruddha 是的 @DilanAnuruddha 但里面的图片可以改变 你的 UIImageView contentMode 是什么? @DilanAnuruddha 离开 【参考方案1】:我整理了一个示例项目,repo 是here。
基本上你需要做几件事:
计算两者您的UIImageView
帧大小以及UIMage
的帧在scaledAspectFit
中显示。
创建两个命名约束,并在获得按钮框架后动态重新定位按钮。
首先,您需要记住,直到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
类型的变量。为此,我改编了两年前的my answer:
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 个点的位置。
【讨论】:
【参考方案2】:使用您的图像宽度来定位按钮。粗略构思并平滑 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)
])
【讨论】:
感谢您的回答,可能也是正确的,但我同意@dfd 的想法以上是关于将按钮限制为 UIImageView 内的图像的主要内容,如果未能解决你的问题,请参考以下文章
UIButton 内的 UIImageView 具有默认填充 - 如何删除?
在 Swift 中使用 AlamofireImage 将 GIF 图像转换为 UIImageView
在 UITableView 内的 UIImageView 中从 Web 加载图像