0

我在 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 符号生成的图像时,我在自动布局中设置的框架在运行时保持不变?

4

1 回答 1

3

对图像视图使用SF Symbolswith 配置是非常古怪的。

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

像这样设置.imagea 的属性UIImageView

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 Symbols 时,最好不要使用UIImage.SymbolConfiguration(除非您无法获得所需的外观,在这种情况下,您可能需要跳过一些步骤才能正确调整大小/对齐方式)。

于 2021-02-20T16:29:41.993 回答