UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

An UIView subclass behaving like UILabel auto-layout wise

Forums > Swift

Hey everyone. As generally known, when we use UILabel with auto-layouts correctly they are self sizing based on textwe set. I am just looking for a way to create UIView subclass which should have exactly same behaviour when I set var view: UIView of it.

I have tried intrinsicContentSize, autoresizingMask and auto-layout however could not manage to it.

And I also want you tell why I am seeking such solution. I have a UITableViewCell and I want it to have a subview which I can change the content of it based on data. Exactly the flow like UILabel UILabel.text and UITableView.automaticDimension.

3      

Hi, the intrinsicContentSize is the way to go here. But you need to pair it with AutoLayout to fix this view inside the cell.

What kind of content your view displays? You could potentially use the subviews intrinsic sizes to calculate this new one.

I wrote about intrinsicContentSize on my blog recently if you are interested.

3      

Well I think I messed up pairing you mentioned. The view would include labels, buttons etc. which all added using autolayout. I will look into your blog and let you know if I still struggle.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Hmm maybe you don't need intrinsicContentSize after all? If you setup constraints for the subviews, then the parent view will have defined its size based on the subviews and their constraints.

3      

Yeah that was what I thought. I created a variable to hold the related view in it. Lets call related status view as statusView and holder as containerView. When I say containerView = statusView it does not work. I tried it containerView.addSubview(statusView) it just adds the subview as tableView reuses UITableViewCells. I tried to remove every subview before adding new one but it did not work as well. Do you have any suggestion/code piece ti solve this?

3      

I am trying to understand what you want to achieve.. You can your TableView cell to display the statusView and nothing else? If so, then you can create custom cell subclass, in the init call something like:

contentView.addSubview(statusView)

And configure constraints between contentView and statusView. This is most likely pinning leading, trailing, top and bottom edges without any constants.

I think with this setup the automatic table view dimensions should work.

3      

I thought talk is cheap and

class Cell: UITableViewCell {

    // the view which will change based on state.
    // if type changed to one of subclasses of UIView from inside didSet below, it works. But I can not change it afterwards.
    private lazy var containerView: UIView = {
        let view = UIView()
        return view
    }()

    var data: SomeCodable? {
        didSet {
            switch data.state {
            case .something:
                // how do I assign relevant view to the containerView
            case .someotherthing:
                // how to?
            }
        }
    }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        // setup of other irrelevant views

        containerView.topAnchor.constraint(equalTo: somethingIrrelevant.bottomAnchor).isActive = true
        containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true

    }

    required init?(coder: NSCoder) {
        fatalError()
    }

}

3      

I am sorry, I sometimes cant express myself in english. The thing is, in the above cell I have a containerView which:

  1. will contain different UI depending on the data. those UI designs -UIView subclasses- will have their own autolayout cared about inside themselves.
  2. should be able to do number 1 during initialization (cellForRowAt) and afterwards.
  3. should not break UITableView.automaticDimension.

3      

And this produces what result? Seems like it should work, although I think the preferred solution here is to have multiple types of cells and handle this in the view controller.

Meaning if the data is A, then use one cell, if B then use another cell. I think this is better for separation and can be extended without touching the existing stuff.

3      

I had that as a solution but the cell those cells above are going to be mostly the same UI wise. Just small part at the bottom may vary. I am not allowed to share any design captures. So I quickly made a simple one.

https://ibb.co/d0kSLcM

As you see above there are 3 different for the same cell. Pinkish area is completely same for all of them. And it is kind of a complex view. Green, blue and nil areas are which depend on the state. I could do write subclass for all those separately but it does not make sense to me because of the pinkish part. Yes, it is an option but I think it will be ugly.

Lastly, there is a button in the green view and when user taps it the cell will either become the second or the third one. I dont know how to achieve this if I write them separately.

I could not add the image here so added the link

3      

Oh I see now, thanks for the details.

I think in this case you will have a bit of issue with resizing the cell dynamically.

I would personally create new cells just for the green and blue parts and you can then use table view methods like insertRows and deleteRows to add/remove these cells. If you can support just iOS 13 and above, I would look into Diffable data sources which make this functionality way easier to implement.

3      

Yeah that is where I am struggling. Your suggestion, again though, wont work I think. Because the gray part is the cell itself. It is a chat ui and depends on card based design.

On second thought it will do but will also be very painful to handle frames to match and maintain.

3      

Oh I see. We did something similar in one project where we had to support iOS 12 and wanted to use the inset card style available since iOS 13.

So we had to do it by hand. Each cell would be configurable so it could appear is "top", "middle" or "bottom" type. You would then have to manually set the rounded corners.

But maybe you can have each "red" cell as a section and if it should show either the blue or green part, then the section will return 2 in numberOfRowsInSection and table view will create the card design automatically?

3      

I deeply appreciate your interest to help me. However I will say this, already using sections for date labels. I am about to explode

3      

I see. I guess this depends also on your time budget. Changing content of particular cell and resizing it is doable. But it will take some trial and error. I think you need to call the UITableView.beginUpdates, change the content view, and call UITableView.endUpdates if I remember correctly.

Another approach would be to introduce model for your section, that would have like an array of enums which would tell you the number of rows and based on the enum you would then dequeue and configure correct cell.

This would allow you to have the date labels + other cells as part of a one section and possibly let you call reloadSections just for the one you change.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.