0

I have a tableview where I add a text string (of three NSStrings).

Because the three text strings are of similar length, I was wondering if there was a simple way to do this with a simple stringWithFormat

[NSString stringWithFormat:@"%@ %@ %@" , hours, days, months];

I've tried \t but that is not the best and wonder how it would work on different platforms. I I have alreay made the font smaller for iPhones.

Want

3       5       1 
12      6       7 
2       30      12
Willeke
  • 14,578
  • 4
  • 19
  • 47
James D
  • 1
  • 2
  • Not sure if I understand correctly, are each set of three numbers in one cell? In that case you could try a horizontal `UIStackView`. – koen Oct 03 '20 at 02:34
  • Table views don't have "columns". That looks like a collection view, not a table view. – matt Oct 03 '20 at 04:28

2 Answers2

1

I'd use a UIStackView inside each cell.

self.data = @[@[@"3", @"5", @"1"], @[@"12", @"6", @"7"], @[@"2", @"30", @"12"]];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"test" forIndexPath:indexPath];
    
    UILabel *label1 = [UILabel new];
    label1.text = self.data[indexPath.row][0];
    label1.textAlignment = NSTextAlignmentCenter;
    
    UILabel *label2 = [UILabel new];
    label2.text = self.data[indexPath.row][1];
    label2.textAlignment = NSTextAlignmentCenter;

    UILabel *label3 = [UILabel new];
    label3.text = self.data[indexPath.row][2];
    label3.textAlignment = NSTextAlignmentCenter;

    UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews: @[label1, label2, label3]];
    stackView.tag = 1;
    
    stackView.axis = UILayoutConstraintAxisHorizontal;
    stackView.distribution = UIStackViewDistributionFillEqually;
    
    UIView *sub = [cell.contentView viewWithTag: 1];
    
    if (sub != nil ) {
        [sub removeFromSuperview];
    }
    
    [cell.contentView addSubview: stackView];
    
    stackView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [stackView.centerYAnchor constraintEqualToAnchor: cell.contentView.centerYAnchor].active = YES;
    [stackView.leadingAnchor constraintEqualToAnchor: cell.contentView.leadingAnchor constant: 10].active = YES;
    [stackView.trailingAnchor constraintEqualToAnchor: cell.contentView.trailingAnchor constant: -10].active = YES;

    return cell;
}

EDIT: Added a tag to the stack view to prevent cells that are reused to have more than one stack view.

result:

enter image description here

koen
  • 5,383
  • 7
  • 50
  • 89
  • This method works well. How do you adjust so that stack view resizes for an iPhone or when you rotate? – cavuco Oct 05 '20 at 17:44
  • I only tested this on a simulator and the stack view automatically adjusted when rotating. – koen Oct 05 '20 at 18:04
  • Did you create a stack view on the XIB or just in code? I added your text verbatim to test and it works without adding a stack view within XIB but it does not resize on rotate simulator. – cavuco Oct 05 '20 at 18:21
  • I had to add constraints to the tableview. Now it resizes. Thanks – cavuco Oct 05 '20 at 18:39
  • @cavuco: Glad it works. In my example, I used a `UITableViewController` in the Storyboard, I guess that has the constraints already added for the tableView. – koen Oct 05 '20 at 19:15
  • My tableview fills from a new array created from a JSON NSURLSession. The array updates correctly, but the cell does not update correctly. Whatever is the first tableview displayed (lets say it shows in row 0, "A B C") as the three labels. When I select a new seach through the JSON, and the labels 1-3 update to "D E F" the tableview returns the cell(s) of the first view ("A B C") and then if there are more rows, those appear normally. If I return to the original search in JSON, the correct tableview appears. – James D Oct 08 '20 at 17:11
  • [Continued] I have to enter cell=nil right after the cell = (UITableViewCell*) tableView dequeueReusableCellWithIdentifier:@"cell"); line inorder to have it work correctly. Right after that, I have a if(cell=nil) function within which is the code you had above. My other tableviews don't require that. What am I doing wrong here? – James D Oct 08 '20 at 17:11
  • @JamesD SO recommends to keep one question per topic, so please post a new question regarding your JSON issue. – koen Oct 09 '20 at 11:44
  • It is the same issue. It doesn't work when you reload the table like normal. You understand the code, so I'm sure its related – cavuco Oct 09 '20 at 22:02
  • I added a reload button to my small project and it still works with a small edit in the code (see above). I don't know what your JSON looks like so can't answer that part. – koen Oct 10 '20 at 13:43
  • And don't use `cell = (UITableViewCell*) tableView dequeueReusableCellWithIdentifier:@"cell");` that's outdated, instead use `cell = [tableView dequeueReusableCellWithIdentifier: @"cell" forIndexPath:indexPath];` as I wrote in my answer. – koen Oct 10 '20 at 17:05
0

Columns don't need to be UI Elements. This can be solved with attributed Strings since iOS 7.0

NSArray *tabs = @[
    [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:72.0 options:@{}],
    [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:144.0 options:@{}]
];
    
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.defaultTabInterval = 72.0;
style.tabStops = tabs;
    
NSDictionary *attr = @{ NSFontAttributeName:[UIFont systemFontOfSize:18.0], NSParagraphStyleAttributeName:style };
    
NSString *hh = @"2";
NSString *dd = @"30";
NSString *mm = @"12";
NSAttributedString *tabbedString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\t%@\t%@", hh, dd, mm] attributes:attr];

but be aware of that tabstops can shift the strings layout when the space between them is not anouth to show the partly string in its fontsize.

Ol Sen
  • 3,163
  • 2
  • 21
  • 30
  • What is the function of style.defaultTabInterval = 72.0 when you are assigning style.tabStops=tabs which assigns the location of each tab stop? How would I make this more device dependent (ie iPhone vs ipad)? Can I assign different fonts or sizes to each entry (mm, hh) independently or do I have to use the same font and size? – James D Oct 03 '20 at 17:55
  • defaultTabInterval will be repeatedly applied after the last expected tabulator is used in case more tabs are used in a string. In the example above meaning a third tabulator would come 144.0+72.0. And yes you can format different size, font, you just expand the attributed String to what you need. read more [here](https://stackoverflow.com/questions/18365631/example-of-nsattributedstring-with-two-different-font-sizes) or lookup what you can do else with NSAttributedString – Ol Sen Oct 03 '20 at 18:52
  • One problem, When I assign the AttributedString to the the cell element '' DataElement *e [[DataElement alloc] initWithLabel: tabbedString]; '' it says its an incompatible pointer. (NSAttributedString to parameter type NSString). – cavuco Oct 05 '20 at 15:48