尝试在捏合顶部添加 UITextfield 以缩放图像。我能够通过捏合来缩放图像,但添加 UITextField 是我遇到困难的地方。我试图让 UITextField 在放大/缩小图像时保留在图像的特定部分。我以为我已经接近了,但 Xcode 似乎不喜欢我添加到 UITextfield 的约束。谢谢您的帮助。
当前代码:
import UIKit
import Foundation
class ZoomImage: UIViewController, UITextFieldDelegate {
private var textField: UITextField {
let ut = UITextField()
ut.backgroundColor = .black
return ut
}
// create scrollView
private let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.backgroundColor = .red
return sv
}()
// create imageView
private var imageView: UIImageView = {
let v = UIImageView()
v.backgroundColor = .blue
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() {
// Allows us to have this view be the delegate of the textfield
self.textField.delegate = self
// Allows us to have this view be the delegate of the scrollview
scrollView.delegate = self
// add Scrollview to view
self.view.addSubview(scrollView)
// Defining imageView
let image = UIImage(named: "test.png")!
imageView = UIImageView(image: image)
imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: image.preferredPresentationSizeForItemProvider)
imageView.contentMode = .scaleAspectFit
imageView.addSubview(textField)
//Defining Textfield
textField.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: image.preferredPresentationSizeForItemProvider)
textField.placeholder = "TEsting"
// add UIImageView to scroll view
scrollView.addSubview(imageView)
scrollView.addSubview(textField)
imageView.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
// respect safe-area
let safeG = view.safeAreaLayoutGuide
// Zoom range
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 10.0
// constraints
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: 0),
scrollView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 0),
imageView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor, constant: 0),
imageView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor, constant: 0),
imageView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor, constant: 0),
imageView.topAnchor.constraint(equalTo: self.scrollView.topAnchor, constant: 0),
imageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
imageView.heightAnchor.constraint(equalTo: scrollView.heightAnchor),
textField.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 0),
textField.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: 0),
textField.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0),
textField.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0)
])
}
}
extension ZoomImage: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}
首先我们需要修复代码中的一些严重错误。
更改
textField
,使其只创建一个实例。每次引用 UITextField
属性时,您的代码都会创建一个新的 textField
实例。使其像其他视图属性一样:
private let textField: UITextField = {
let ut = UITextField()
ut.backgroundColor = .gray
return ut
}()
不要尝试将文本字段添加到两个不同的超级视图。删除该行:
imageView.addSubview(textField)
下一步是更新滚动视图约束以利用
frameLayoutGuide
和 contentLayoutGuide
。然后将文本字段锚定到内容的顶部/尾部角。
NSLayoutConstraint.activate([
scrollView.frameLayoutGuide.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 0),
scrollView.frameLayoutGuide.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: 0),
scrollView.frameLayoutGuide.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: 0),
scrollView.frameLayoutGuide.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 0),
imageView.leadingAnchor.constraint(equalTo: self.scrollView.contentLayoutGuide.leadingAnchor, constant: 0),
imageView.trailingAnchor.constraint(equalTo: self.scrollView.contentLayoutGuide.trailingAnchor, constant: 0),
imageView.bottomAnchor.constraint(equalTo: self.scrollView.contentLayoutGuide.bottomAnchor, constant: 0),
imageView.topAnchor.constraint(equalTo: self.scrollView.contentLayoutGuide.topAnchor, constant: 0),
imageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
imageView.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
textField.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor, constant: 0),
textField.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: 0),
])
完成所有这些后,您最初可以看到完整的图像,文本字段位于右上角。但当您缩放图像时,文本字段仍位于顶部,但不会按预期移动到右侧。如果一直向左滚动,则文本字段会出现在屏幕的右边缘,但不会出现在图像视图的右边缘。
可以通过在滚动视图的缩放级别发生变化时更新文本字段的约束来解决此问题。
添加以下附加滚动视图委托方法:
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
textField.removeFromSuperview()
scrollView.addSubview(textField)
let xC = NSLayoutConstraint(item: self.textField, attribute: .trailing, relatedBy: .equal, toItem: scrollView.contentLayoutGuide, attribute: .trailing, multiplier: scale, constant: 0)
let yC = NSLayoutConstraint(item: self.textField, attribute: .top, relatedBy: .equal, toItem: scrollView.contentLayoutGuide, attribute: .top, multiplier: scale, constant: 0)
NSLayoutConstraint.activate([
xC,
yC,
])
}
这可确保文本字段在每次缩放(放大或缩小)结束时正确定位。
对我来说这似乎是一个 UIKit bug。当内容缩放时,
contentLayoutGuide
似乎没有更新。无需手动将 scale
应用于约束的 multiplier
。
我尝试了另一种方法,将文本字段直接添加到图像视图并设置文本字段相对于图像视图的约束。除了文本字段的大小也随着图像视图的变化而变化之外,无需任何额外的代码即可工作。由于目标是保持文本字段的原始大小,因此这是行不通的。对文本字段应用“缩放”变换可以很容易地使其达到所需的大小,但这会导致其位置发生一些变化。我放弃了尝试在对视图应用各种变换时使约束起作用。