3

I have table view cell like this.

enter image description here

After image is downloaded, I update the height of image view so that aspect ratio is correct (width is fixed).

[self.imgMain removeConstraint:self.aspectConstraint];
self.aspectConstraint = [NSLayoutConstraint constraintWithItem:self.imgMain
                                                     attribute:NSLayoutAttributeWidth
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self.imgMain
                                                     attribute:NSLayoutAttributeHeight
                                                    multiplier:aspectRatioMult
                                                      constant:0];
self.aspectConstraint.priority = 999;//the reason is that if it is 1000, it violate with my label height constraints and it broke label constraint.So I set to 999
[self.imgMain addConstraint:self.aspectConstraint];
[self setNeedsUpdateConstraints];
[self updateConstraints];

Problem is that although I update constraints, tableviewcell never change and it reuse cell in every 3 cell for the first time. If I scroll up and down, height is updated. How shall I update my constraints successfully?

Edit

I set cell data like this.

- (void)setData:(NSDictionary *)dict
{
    if (!dict)
        return;

    self.cellData = [NSDictionary dictionaryWithDictionary:dict];
    [self.imgMain setImageWithURL:[NSURL URLWithString:self.cellData[SERVER_IMG]] placeholderImage:[UIImage new] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL){

        if (image) {
            [self putImage:image];
            return ;
        }
        [self putImage:[UIImage imageNamed:@"placeholder.png"]];


    } usingActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

    NSString *name = [NSString stringWithFormat:@"%@%@",SERVER_NAME, [LocalizationHelper getExtForLocale]];

    if([self.cellData[SERVER_INTEGRATION_ID]intValue]==SERVER_ISHOPCHANGI_ID) {

        [self.lblShopName setText:self.cellData[SERVER_DESCRIPTION]];
        [self.btnMap setHidden:YES];
        self.imgWidthMapBtnConstraint.constant = 0;
    } else {
        [self.lblShopName setText:self.cellData[SERVER_LOCATIONS][0][SERVER_SHOP]];
        [self.btnMap setHidden:[Helper isPointZero:dict[SERVER_LOCATIONS][0]]];
        self.imgWidthMapBtnConstraint.constant = 33;
    }
    [self.lblOfferTitle setText:self.cellData[name]];
}
Khant Thu Linn
  • 5,905
  • 7
  • 52
  • 120

3 Answers3

3

LITTLE OVERVIEW TO MAKE THINGS CLEAR:

While using Autolayout, for calculating the height of cell, iOS only calculates the height first time the cell is loaded for a indexPath and caches it, and reuse it next time, cell gets visible again.

TO resolve - >

Either Use,

tableView.beginUpdates()
tableView.endUpdates()

OR

tableView.reloadRowsAtIndexPath

REFERENCE LINKS

ANSWER TO YOUR QUESTION

You can use tableView.beginUpdates()/endUpdates() in set Data like

BELOW WON'T CAUSE INDEFINITE LOOP

-(void)setData{
  /*YOUR CODE UPDATING THE CONSTRAINTS*/
  tableView.beginUpdates()
  tableView.endUpdates()
}

OR

for using reloadRows CHECK if CONSTRAINTS are already SET, to break the loop, if yes, then don't call the reloadRows*

    -(void)setData{
       CGFloat requiredValue = 0;

if([self.cellData[SERVER_INTEGRATION_ID]intValue]==SERVER_ISHOPCHANGI_ID) {
       
requiredValue  = 0;

        } else {
    
       requiredValue  = 33;

      }
          /*CHECK IF CONSTRAINT ALREADY SET*/
         if(self.imgWidthMapBtnConstraint.constant != requiredValue){

          self.imgWidthMapBtnConstraint.constant = requiredValue;
           /**RELOAD ROW*/
        }
        }
Community
  • 1
  • 1
gunjot singh
  • 2,578
  • 20
  • 28
  • I am changing constraint in my tableviewcell. Do I need to send back with delegate to reload table? – Khant Thu Linn May 27 '16 at 06:29
  • yes, you will have to get your tableview reference using delegate. – gunjot singh May 27 '16 at 07:59
  • Thanks. I have set data as in my question. When shall I call reloadRows? I try to call in setdata. Then, when I scroll cell, I set data, i reload again and it cause to setdata again and so on. – Khant Thu Linn May 27 '16 at 08:37
  • hmm...I think it still infinite. I still got error like this. http://imgur.com/8zlcxm2 I am using dynamic height though. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) return UITableViewAutomaticDimension; – Khant Thu Linn May 27 '16 at 09:29
  • Have you tried tableView.beginUpdates()/endUpdates() ?? – gunjot singh May 27 '16 at 11:50
  • Only include tableView.beginUpdates()/endUpdates() and don't call reload rows like in first example i mentioned. Please give it a try and let me know. – gunjot singh May 27 '16 at 14:07
  • Thanks. I got idea from you. My constraints must be sth wrong. it is still not okay but I now roughly know how to change height only without setting data again. – Khant Thu Linn May 29 '16 at 13:37
1

Swift

Yes changing the constraints will not do anything because the height was already computed when calling heightForRowAtIndexPath and this is only called when reloading the tableView or reloading a cell.

You either call tableView.reloadData() but this is not efficient if you have changes in only one cell.

If you know the indexPath of the cell that changed just call tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)

ELKA
  • 735
  • 6
  • 17
0

imagine UITableViewCell only have one label and it's height is AutomaticDimension, sometime I want margin depend on data

at first I set constraints like this

[_label mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(@(0));
    make.right.equalTo(@(0));
    make.top.equalTo(@(self.margin));
    make.height.equalTo(@30)
    make.bottom.equalTo(@(-self.margin));
}];

and I want change margin when cell data change

- (void)setMargin:(CGFloat)margin {
        _margin = margin;
        [self.label mas_updateConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(@(self.margin));
            make.bottom.equalTo(@(-self.margin));
        }];
}

scroll UITableview , xcode warning when I change margin of this cell (reuse)

Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
"<MASLayoutConstraint:0x1c42b9e60 UILabel:0x13fec3bb0.top == UITableViewCellContentView:0x13fe9ef60.top + 10>",
"<MASLayoutConstraint:0x1c42b9d40 UILabel:0x13fec3bb0.height == 30>",
"<MASLayoutConstraint:0x1c42b9e00 UILabel:0x13fec3bb0.bottom == UITableViewCellContentView:0x13fe9ef60.bottom - 10>",
"<NSAutoresizingMaskLayoutConstraint:0x1c0291710 UITableViewCellContentView:0x13fe9ef60.height == 80>"
)

Will attempt to recover by breaking constraint 
<MASLayoutConstraint:0x1c42b9d40 UILabel:0x13fec3bb0.height == 30>

to avoid this warning is set priority:

[_label mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(@(0));
    make.right.equalTo(@(0));
    make.top.equalTo(@(self.margin));
    make.height.equalTo(@30).priority(MASLayoutPriorityDefaultMedium);
    make.bottom.equalTo(@(-self.margin));
}];
wlixcc
  • 1,132
  • 10
  • 14