在WWDC SF Symbols视频中,Apple说在显示SF Symbols时更喜欢水平和垂直对齐。据推测,这意味着每个UIImageView.center.x
应该包含相同的值,以便它们在列中对齐。我的问题是如何确定x值应该是多少,因为它们都是不同的宽度。这是一个示例屏幕截图:
此屏幕快照使用UITableViewCellStyleDefault
和cell.imageView
和cell.textLabel
。但是,我想知道如何使用自定义UITableViewCell
实现相同的效果。基于UIImageSymbolConfiguration.pointSize
来确定一定宽度的正确方法是正确的吗?确定宽度后,所有符号都会根据该中心显示吗?
关于如何布局/对齐SF符号的任何指导,特别是在不使用自动布局的情况下,都将非常有用:)
这是一个非常简单的示例。
它遍历数据以确定将用于设置imageView的宽度约束常量的最宽符号。
class MySymbolCell: UITableViewCell {
let symbolImageView: UIImageView = {
let v = UIImageView()
v.contentMode = .center
return v
}()
let theLabel: UILabel = {
let v = UILabel()
return v
}()
var imageWidthConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
symbolImageView.translatesAutoresizingMaskIntoConstraints = false
theLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(symbolImageView)
contentView.addSubview(theLabel)
// this way we can change imageView width at run-time if needed
imageWidthConstraint = symbolImageView.widthAnchor.constraint(equalToConstant: 40.0)
imageWidthConstraint.priority = UILayoutPriority(rawValue: 999)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain imageView top / bottom / leading
symbolImageView.topAnchor.constraint(equalTo: g.topAnchor),
symbolImageView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
symbolImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
// constrain width
imageWidthConstraint,
// constrain height equal to width
symbolImageView.heightAnchor.constraint(equalTo: symbolImageView.widthAnchor),
// constrain label leading 8-pts from image view
theLabel.leadingAnchor.constraint(equalTo: symbolImageView.trailingAnchor, constant: 8.0),
// constrain label centerY to image view centerY
theLabel.centerYAnchor.constraint(equalTo: symbolImageView.centerYAnchor),
// constrain label trailing to content view trailing
theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
])
}
}
class MySymbolTableViewController: UITableViewController {
var myData: [String] = [
"arrow.up",
"arrow.down",
"person.badge.plus",
"eye.slash",
"line.horizontal.3",
"textformat.123",
]
var symbolImageViewWidth: CGFloat = 40.0
// configure as desired
let imageConfig = UIImage.SymbolConfiguration(pointSize: 20, weight: .light, scale: .default)
override func viewDidLoad() {
super.viewDidLoad()
// calculate how wide you need your cell's symbol image view to be
// either run a loop to get the widest symbol your data is using,
// or
// just make sure you can fit the widest of the symbols ("bold.italic.underline")
let testLoop = true
if testLoop {
var maxW: CGFloat = 0.0
myData.forEach {
if let img = UIImage(systemName: $0, withConfiguration: imageConfig) {
maxW = max(img.size.width, maxW)
}
}
symbolImageViewWidth = maxW
} else {
if let img = UIImage(systemName: "bold.italic.underline", withConfiguration: imageConfig) {
symbolImageViewWidth = img.size.width
}
}
tableView.register(MySymbolCell.self, forCellReuseIdentifier: "MySymbolCell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MySymbolCell", for: indexPath) as! MySymbolCell
let img = UIImage(systemName: myData[indexPath.row], withConfiguration: imageConfig)
cell.symbolImageView.image = img
cell.theLabel.text = myData[indexPath.row]
cell.imageWidthConstraint.constant = symbolImageViewWidth
return cell
}
}
结果: