简体   繁体   中英

How do you align SF Symbols with one another in a UITableView?

In the WWDC SF Symbols video, Apple says to prefer horizontal and vertical alignment when displaying SF Symbols. Presumably, that means that each UIImageView.center.x should contain the same value so that they line up in a column. My question is how to determine what that x value should be since they are all different widths. Here is an example screenshot:

截屏

This screenshot is using UITableViewCellStyleDefault with cell.imageView and cell.textLabel . However, I want to know how to achieve the same effect using a custom UITableViewCell . Is the correct way to just determine a certain amount of width based off the UIImageSymbolConfiguration.pointSize ? Once you have that width, all symbols will be displayed according to that center?

Any guidance on how to layout/align SF Symbols especially without the use of auto layout would be super helpful:)

Here is a very simple example.

It loops through the data to determine the widest symbol that will be used to set the imageView's width constraint constant.

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
    }

}

Result:

在此处输入图像描述

It might be easier to adjust cell.separatorInset

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.separatorInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 0)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM