重用 tableviewcell 中的约束和高度未更新

Posted

技术标签:

【中文标题】重用 tableviewcell 中的约束和高度未更新【英文标题】:Reusing constraints in tableviewcell and height is not updated 【发布时间】:2016-05-27 04:48:43 【问题描述】:

我有这样的表格视图单元格。

图像下载后,我更新图像视图的高度,使纵横比正确(宽度固定)。

[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];

问题是,虽然我更新了约束,但 tableviewcell 永远不会改变,它第一次在每 3 个单元格中重用单元格。如果我上下滚动,高度会更新。我该如何成功更新我的约束?

编辑

我这样设置单元格数据。

- (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]];

【问题讨论】:

[self layoutIfNeeded] 丢失 如果我放 layoutIfNeeded 则它不起作用。 @PKT 【参考方案1】:

让事情变得清晰的小概述:

在使用 Autolayout 时,为了计算单元格的高度,ios 仅在第一次为 indexPath 加载单元格时计算高度并缓存它,并在下次重用时,单元格再次可见。

解决 - >

任意使用,

tableView.beginUpdates()
tableView.endUpdates()

OR

tableView.reloadRowsAtIndexPath

参考链接

How to animate UITableViewCell height using auto-layout?

https://blog.pivotal.io/labs/labs/expandable-uitableviewcells

回答您的问题

您可以在 set Data like 中使用 tableView.beginUpdates()/endUpdates()

以下不会导致无限循环

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

使用 reloadRows CHECK 如果 CONSTRAINTS 已经设置,则中断循环,如果是,则不要调用 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*/
        
        

【讨论】:

我正在更改我的 tableviewcell 中的约束。我是否需要与代表一起发回重新加载表? 是的,您必须使用委托获取您的 tableview 参考。 谢谢。我已经在我的问题中设置了数据。我什么时候应该调用 reloadRows?我尝试调用 setdata。然后,当我滚动单元格时,我设置数据,我再次重新加载并导致再次设置数据等等。 嗯...我认为它仍然是无限的。我仍然有这样的错误。 imgur.com/8zlcxm2 不过我使用的是动态高度。 if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) return UITableViewAutomaticDimension; 你试过 tableView.beginUpdates()/endUpdates() 吗??【参考方案2】:

斯威夫特

是的,更改约束不会做任何事情,因为在调用 heightForRowAtIndexPath 时已经计算了高度,并且仅在重新加载 tableView 或重新加载 cell 时才会调用。

您可以调用 tableView.reloadData() 但如果您只在一个单元格中进行更改,则效率不高。

如果您知道更改的单元格的 indexPath,只需调用 tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)

【讨论】:

我应该在哪里/何时调用/放置 reloadRowsAtIndexPaths? 你应该先获取对应单元格的indexPath。然后,在 setImageWithURL 的完成块中调用 reloadRowsAtIndexPath。【参考方案3】:

想象 UITableViewCell 只有一个标签,它的高度是 AutomaticDimension, 有时我希望保证金取决于数据

一开始我是这样设置约束的

[_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));
];

我想在单元格数据更改时更改边距

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

滚动 UITableview ,当我更改此单元格的边距时 xcode 警告(重用)

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>

为避免此警告设置了优先级:

[_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));
];

【讨论】:

以上是关于重用 tableviewcell 中的约束和高度未更新的主要内容,如果未能解决你的问题,请参考以下文章

UIImageView 不是 StackView 和 TableViewCell 中的自动高度

tableViewCell自动计算高度

动态增加 UILabel & TableView Cell 的高度?

关于单元重用的自定义 UITableViewCell 约束问题

设置 tableviewcell 高度以显示具有动态高度单元格的完整内部/嵌套 uitableview

UITableView 自定义单元格高度未正确管理 swift 中的动态约束