代码之家  ›  专栏  ›  技术社区  ›  BSR

UIKit:如何在缩放图像的顶部添加UITextfield

  •  1
  • BSR  · 技术社区  · 1 年前

    试图在缩放图像的顶部添加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
        }
    }
    
    1 回复  |  直到 1 年前
        1
  •  1
  •   HangarRash    1 年前

    首先,我们需要修复代码中的一些严重错误。

    1. 改变 textField 所以它只创建一个实例。您的代码正在创建一个新的 UITextField 实例,每次 text字段 属性被引用。使其与其他视图属性类似:

      private let textField: UITextField = {
          let ut = UITextField()
          ut.backgroundColor = .gray
          return ut
      }()
      
    2. 不要试图将文本字段添加到两个不同的超级视图中。拆下线路:

      imageView.addSubview(textField)
      
    3. 不创建新的 UIImageView 例子更换线路:

      imageView = UIImageView(image: image)
      

      具有

      imageView.image = image
      
    4. 您正在使用约束。不要麻烦设置图幅。删除设置的所有行 frame 任何视图的属性。

    接下来是更新滚动视图约束以利用 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错误 内容布局指南 似乎不会随着内容的缩放而更新。应该不需要手动应用 scale 到约束的 multiplier .


    我尝试了另一种方法,将文本字段直接添加到图像视图中,并设置文本字段相对于图像视图的约束。这在没有任何额外代码的情况下工作,只是文本字段的大小也随着图像视图的变化而变化。由于目标是保持文本字段的原始大小,这是行不通的。对文本字段应用“缩放”变换可以很容易地使其达到所需的大小,但这会导致其位置发生一些变化。我放弃了在对视图应用各种变换的同时使约束生效的尝试。