【问题标题】:UIImageView in UICollectionViewCell randomly changing frame when using SF Symbol as image source使用SF Symbol作为图像源时,UICollectionViewCell中的UIImageView随机改变帧
【发布时间】:2021-02-16 12:28:43
【问题描述】:

我在 UICollectionViewCell 中有一个 UIImageView。我正在使用自动布局将其设置为具有固定宽度和高度的单元格的左上角。

当我在图像视图上设置图像时,从资产目录中的图像,一切都很好。

当我使用 SF Symbols 在图像视图上设置图像时,UIImageView 的框架会随机变化。

Autolayout 将 UIImageView 的框架设置为单元格的左上角,并将宽度和高度设置为 24。使用 Asset Catalog UIImage(named:... 中的图像时会遵守这一点

当我这样做时,框架会随机变化:

let conf = UIImage.SymbolConfiguration(pointSize: 10, weight: .medium, scale: .large)
let image = UIImage(systemName: "doc.fill", withConfiguration: conf)
imageView.image = image

有时单元格会显示如下图像:

其他时间是这样的:

如果我将 UIImageView 的框架打印到控制台,我会看到更改,如下所示:

testImageView: (8.0, 6.666666666666668, 24.0, 27.0)

或者像这样:

testImageView: (8.0, 7.0, 24.0, 26.666666666666664)

所有其他帧在记录时看起来是恒定的,单元格框架是恒定的等等......从 SF Symbol 生成的图像会强制 UIImageView 的框架发生变化。

为什么会发生这种情况,如何正确使用 SF 符号,以便在将 ImageView 的图像设置为从 SF 符号生成的图像时,我在自动布局中设置的框架在运行时保持不变?

【问题讨论】:

    标签: swift uiimageview uiimage uicollectionviewcell sf-symbols


    【解决方案1】:

    SF Symbols 与图像视图配置一起使用非常很古怪。

    我不知道我是否将其称为“错误”或只是未记录(或非常模糊记录)的行为。

    像这样设置UIImageView.image 属性:

    let conf = UIImage.SymbolConfiguration(pointSize: 10, weight: .medium, scale: .large)
    let image = UIImage(systemName: "doc.fill", withConfiguration: conf)
    imageView.image = image
    

    将改变图像视图的框架! ...无论约束如何。

    这是一个明显的例子......

    我们从 4 个图像视图开始,限制为 Width:80,Height:equalTo Width。红线被限制在每个图像视图的顶部和底部:

    现在,我们设置每个 imageView 的图像,使用符号配置 pointSize(从 10.0 开始)、weight: .mediumscale: 小、中、大,加上底部使用 NO 配置 --img = UIImage(systemName: "doc.fill") .

    在 10.0 pointSize 时,我们已经可以看到图像视图帧的变化:

    当我们达到 50.0 的点大小时,“奇怪的帧大小”非常明显:

    这是一个像素精确的捕获:

    这是此示例的代码,以便您可以更详细地检查所有内容:

    class SFSymbolsViewController: UIViewController {
        
        var imgViews: [UIImageView] = []
        var labels: [[UILabel]] = []
        
        // this will be incremented with each tap
        var ptSize: CGFloat = 5.0
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let g = view.safeAreaLayoutGuide
            
            let infoLabel = UILabel()
            infoLabel.translatesAutoresizingMaskIntoConstraints = false
            infoLabel.numberOfLines = 0
            infoLabel.textAlignment = .center
            infoLabel.font = .systemFont(ofSize: 14.0)
            infoLabel.text = "Tap to add images.\nPointSize will start at 10, and each Tap will increment the Point Size by 5.0 and re-generate the images."
    
            view.addSubview(infoLabel)
            NSLayoutConstraint.activate([
                infoLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
                infoLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
                infoLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
            ])
            
            var y: CGFloat = 140
            let yInc: CGFloat = 100
    
            for _ in 1...4 {
                let imageView = UIImageView()
                imageView.backgroundColor = .systemYellow
                imageView.contentMode = .scaleAspectFit
                imageView.translatesAutoresizingMaskIntoConstraints = false
                imgViews.append(imageView)
                
                view.addSubview(imageView)
                
                // horizontal "line" views
                let h1 = UIView()
                let h2 = UIView()
                [h1, h2].forEach { v in
                    v.translatesAutoresizingMaskIntoConstraints = false
                    v.backgroundColor = .red
                    view.addSubview(v)
                    NSLayoutConstraint.activate([
                        v.heightAnchor.constraint(equalToConstant: 1.0),
                        v.widthAnchor.constraint(equalTo: g.widthAnchor),
                        v.centerXAnchor.constraint(equalTo: g.centerXAnchor),
                    ])
                }
                
                // info labels
                var imgLabels: [UILabel] = []
                for _ in 1...3 {
                    let label = UILabel()
                    label.font = .systemFont(ofSize: 12.0)
                    label.translatesAutoresizingMaskIntoConstraints = false
                    view.addSubview(label)
                    // add label to right of imageView
                    NSLayoutConstraint.activate([
                        label.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 12.0),
                        label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -12.0),
                    ])
                    imgLabels.append(label)
                }
                imgLabels[1].text = "cfg:"
                labels.append(imgLabels)
                
                NSLayoutConstraint.activate([
                    // image view Top = y, Leading = 20
                    //  width = 80, height = width (1:1 ratio)
                    imageView.topAnchor.constraint(equalTo: g.topAnchor, constant: y),
                    imageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                    imageView.widthAnchor.constraint(equalToConstant: 80.0),
                    imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
                    
                    // put a "line" on top and bottom of imageView
                    h1.bottomAnchor.constraint(equalTo: imageView.topAnchor),
                    h2.topAnchor.constraint(equalTo: imageView.bottomAnchor),
                    
                    // label y positions
                    imgLabels[0].topAnchor.constraint(equalTo: h1.bottomAnchor, constant: 4.0),
                    imgLabels[1].centerYAnchor.constraint(equalTo: imageView.centerYAnchor),
                    imgLabels[2].bottomAnchor.constraint(equalTo: h2.topAnchor, constant: -4.0),
                ])
                y += yInc
            }
            
            let t = UITapGestureRecognizer(target: self, action: #selector(self.setImages(_:)))
            view.addGestureRecognizer(t)
            
        }
        
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            updateSizeLabels(true)
        }
        
        func updateSizeLabels(_ orig: Bool) -> Void {
            for (l, v) in zip(labels, imgViews) {
                if orig {
                    l[0].text = "Orig Frame: \(v.frame)"
                }
                l[2].text = "New Frame: \(v.frame)"
            }
        }
        
        @objc func setImages(_ g: UITapGestureRecognizer) -> Void {
            
            ptSize += 5.0
            
            var cfg: UIImage.SymbolConfiguration!
            var img: UIImage!
            var i: Int = 0
            
            labels[i][1].text = "cfg: \(ptSize) / medium / small"
            cfg = UIImage.SymbolConfiguration(pointSize: ptSize, weight: .medium, scale: .small)
            img = UIImage(systemName: "doc.fill", withConfiguration: cfg)
            
            imgViews[i].image = img
            
            i += 1
            
            labels[i][1].text = "cfg: \(ptSize) / medium / medium"
            cfg = UIImage.SymbolConfiguration(pointSize: ptSize, weight: .medium, scale: .medium)
            img = UIImage(systemName: "doc.fill", withConfiguration: cfg)
            
            imgViews[i].image = img
            
            i += 1
            
            labels[i][1].text = "cfg: \(ptSize) / medium / large"
            cfg = UIImage.SymbolConfiguration(pointSize: ptSize, weight: .medium, scale: .large)
            img = UIImage(systemName: "doc.fill", withConfiguration: cfg)
            
            imgViews[i].image = img
            
            i += 1
            
            labels[i][1].text = "cfg: NO SymbolConfiguration"
            img = UIImage(systemName: "doc.fill")
            
            imgViews[i].image = img
    
            // update the size labels after UI updates
            DispatchQueue.main.async {
                self.updateSizeLabels(false)
            }
        }
        
    }
    

    底线:我相信配置选项与字体的配合更直接相关。以这种方式使用 SF 符号时,使用UIImage.SymbolConfiguration 可能会更好(除非您无法获得所需的外观,在这种情况下,您可能需要跳过一些障碍才能获得尺寸/对齐正确)。

    【讨论】:

      猜你喜欢
      • 2020-05-17
      • 1970-01-01
      • 2017-05-23
      • 2021-06-24
      • 2020-02-03
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 1970-01-01
      相关资源
      最近更新 更多