GeneralMike
GeneralMike

Reputation: 3001

Dynamic Columns in a UITableView with Auto Layout

In my iPad app, I will have a UITableView that is being displayed in a popover. I have multiple values that I want to display, so I made a custom UITableViewCell with several labels, to simulate many "columns" in the table. What I want to do is make sure all of my "columns" will be lined up.

The catch is, I can't hardcode the widths of my columns, because I am dynamically populating the data from an XML webservice - so I don't know how wide they need to be until I've made that call and received the data.

My thoughts are to loop through the data (once I get it), and use the sizeWithAttributs: method of NSString to get the maximum width for each of my columns. I will then send that width to my custom cell, so the cell can use it in its layoutSubviews method. The problem is, I'm trying to do all this with NSLayoutConstraints, and in all the examples I've seen, the any sizes in constraintsWithVisualFormat: are always hardcoded - I won't know what my sizes are until runtime. My idea is to do something like

NSDictionary *myDictionary = NSDictionaryOfVariableBindings(myLabel1,myLabel2)
NSArray *myConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[myLabel1(%d)]-[myLabel2(%d)]",myWidth1,myWidth2 options:NSLayoutFormatAlignAllBaseline metrics:nil views:myDictionary];

But this causes a build error. Is it possible to dynamically provide a size to constraintsWithVisualFormat at runtime, instead of hardcoding it?

Upvotes: 1

Views: 800

Answers (2)

matehat
matehat

Reputation: 5374

The recommended way of doing this is to use the metrics parameter:

NSDictionary *myDictionary = NSDictionaryOfVariableBindings(myLabel1,myLabel2)
NSArray *myConstraints = [NSLayoutConstraint 
          constraintsWithVisualFormat:@"H:|-[myLabel1(lbl1w)]-[myLabel2(lbl2w)]" 
                              options:NSLayoutFormatAlignAllBaseline 
                              metrics:@{@"lbl1w": @(myWidth1),
                                        @"lbl2w": @(myWidth2) } 
                                views:myDictionary];

This basically allows you to provided a dictionary mapping names to numeric values for use anywhere in the visual format string. The values need to be NSNumber instances, which can be easily constructed from C numeric variables using the @(aVariable) construct introduced last year.

Upvotes: 3

GeneralMike
GeneralMike

Reputation: 3001

As I was writing this up, I had a flash of non-stupidity that motivated me to look at what you are actually supposed to pass as the first argument to constraintsWithVisualFormat, and sure enough, it's just looking for an NSString. So the solution is to simply break the string out in front:

NSString *formattedString = [NSString stringWithFormat:@"H:|-[myLabel1(%d)]-[myLabel2(%d)]",myWidth1,myWidth2];

and then pass it in:

NSArray *myConstraints = [NSLayoutConstraint constraintsWithVisualFormat:formattedString options:NSLayoutFormatAlignAllBaseline metrics:nil views:myDictionary];

I haven't tested this yet (there's still a lot of stuff I have to code for doing the looping through the data and all that), but it should work. As I said, all the examples I saw hardcoded the sizes, so I figured I'd post this in case anyone else comes looking for how to do it, or in case I forget later =).

Upvotes: 0

Related Questions