0

What I want to achive is something like list view in Files App. Document will display a little thumbnail if has one. Otherwise a SF Symbol with textStyle .callout will show up. All the rows’ labels should be left aligned. But currently the thumbnails are much bigger than the SF Symbols so that they push the labels away.

I emphasize textStyle because my app supports dynamic type, which means the imageView's frame calculation should base on SF Symbol.

I try to override layoutSubviews. But can't figure out how to do the calculation.

Files App

Files App

My App

My App

marc-medley
  • 8,931
  • 5
  • 60
  • 66
francisfeng
  • 704
  • 1
  • 8
  • 22
  • If you are using SF Symbols, you're already requiring iOS 13+. Have you checked out the new features in UICollectionView for iOS 14? IIRC, one of the "list" features align things like this. Use the Apple Developer app - I think - check out Modern cell configuration. –  Sep 24 '20 at 16:56
  • Not quite clear what you're going for... In your "My App" image, do you want the 4 images to be the same size as the `doc.text` symbol on the first row? – DonMag Sep 24 '20 at 17:56
  • @DonMag I should be more clear. The texts of each row should be aligned. The first row is an example how all rows should look like. – francisfeng Sep 24 '20 at 18:06
  • @dfd I just watched a section of WWDC 20 and it seemed promising. But I am a little reluctant to adopt since it looks like more work to do. – francisfeng Sep 24 '20 at 18:09
  • @francisfeng You have to give fixed width and height to make them align. – Rob Sep 24 '20 at 18:19
  • @francisfeng - still need some detail... Do you want it to look like this, with the images scaled to proportionally to 60x60 (that is, maintaining aspect ratio)? https://i.stack.imgur.com/IA30X.png Here's the same output, but with a border around the image view for clarity: https://i.stack.imgur.com/ypKSp.png – DonMag Sep 24 '20 at 19:23
  • @DonMag Yes. This is exactly what I want. How do you acheive it? – francisfeng Sep 25 '20 at 02:43

1 Answers1

0

For maximum control of your cell appearance, you should create a custom cell. But, if you want use a standard Subtitle cell, you can resize your images when setting them.

There are some excellent image scaling functions in this Stack Overflow answer: how to resize a bitmap on iOS

Add the extensions from that answer to your project. Specifically, for your needs, we'll use scaledAspectFit().

So, assuming you have a Subtitle cell prototype, with identifier of "cell", your cellForRowAt will look something like this:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    
    // however you have your data stored
    let title = "IMG_0001.JPG"
    let subtitle = "Today at 10:15 AM, 2.5 MB"
    let imgName = "IMG_0001"
    
    cell.textLabel?.text = title
    cell.detailTextLabel?.text = subtitle
    
    if let img = UIImage(named: imgName) {
        // default cell image size is 56x56 (points)
        //  so we'll proportionally scale the image,
        //  using screen scale to get the best resolution
        let widthHeight = UIScreen.main.scale * 56
        let scaledImg = img.scaledAspectFit(to: CGSize(width: widthHeight, height: widthHeight))
        cell.imageView?.image = scaledImg
    }
    return cell

}

Edit

Takes only a little research to implement the use fo SF Symbols...

Add this func to your table view controller - it will return a UIImage of an SF Symbol at specified point size, centered in specified size:

private func drawSystemImage(_ sysName: String, at pointSize: CGFloat, centeredIn size: CGSize) -> UIImage? {
    let cfg = UIImage.SymbolConfiguration(pointSize: pointSize)
    guard let img = UIImage(systemName: sysName, withConfiguration: cfg) else { return nil }
    let x = (size.width - img.size.width) * 0.5
    let y = (size.height - img.size.height) * 0.5
    let renderer = UIGraphicsImageRenderer(size: size)
    return renderer.image { context in
        img.draw(in: CGRect(origin: CGPoint(x: x, y: y), size: img.size))
    }
}

Then change your cellForRowAt func as needed:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    
    // however you have your data stored
    let title = "IMG_0001.JPG"
    let subtitle = "Today at 10:15 AM, 2.5 MB"
    let imgName = "IMG_0001"
    
    cell.textLabel?.text = title
    cell.detailTextLabel?.text = subtitle

    // defalt image view size
    let wh = UIScreen.main.scale * 56
    let targetSize = CGSize(width: wh, height: wh)

    // for this example, if it's the first row, generate an image from SF Symbol
    if indexPath.row == 0 {
        if let img = drawSystemImage("doc.text", at: UIScreen.main.scale * 24, centeredIn: targetSize) {
            cell.imageView?.image = img
        }
    } else {
        if let img = UIImage(named: imgName) {
            // default cell image size is 56x56 (points)
            //  so we'll proportionally scale the image,
            //  using screen scale to get the best resolution
            let scaledImg = img.scaledAspectFit(to: targetSize)
            cell.imageView?.image = scaledImg
        }
    }
    return cell
    
}

I'll leave it up to you to tweak the point size as desired (and configure any other properties of your SF Symbol image such as weight, scale, color, etc).

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • I know how to resize images. But this answer didn't involve SF symbols, which in my case it's crucial to align them with images. – francisfeng Sep 25 '20 at 15:38
  • @francisfeng - rather easy to do... see my edited answer. (With a little searching, you could probably have made the changes yourself in the time it took me to post the edit). – DonMag Sep 25 '20 at 16:12