使用SF Symbol作为图像源时,UICollectionViewCell中的UIImageView随机改变帧
Posted
技术标签:
【中文标题】使用SF Symbol作为图像源时,UICollectionViewCell中的UIImageView随机改变帧【英文标题】:UIImageView in UICollectionViewCell randomly changing frame when using SF Symbol as image source 【发布时间】: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 符号生成的图像时,我在自动布局中设置的框架在运行时保持不变?
【问题讨论】:
【参考方案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: .medium
和 scale:
小、中、大,加上底部使用 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
可能会更好(除非您无法获得所需的外观,在这种情况下,您可能需要跳过一些障碍才能获得尺寸/对齐正确)。
【讨论】:
以上是关于使用SF Symbol作为图像源时,UICollectionViewCell中的UIImageView随机改变帧的主要内容,如果未能解决你的问题,请参考以下文章
SF Symbol imageView 不符合pointSize?
尝试使用 Attunity 连接到 Teradata 作为源时出错