在表格视图单元格中动态调整子视图的大小

Posted

技术标签:

【中文标题】在表格视图单元格中动态调整子视图的大小【英文标题】:Resizing a subview dynamically in tableview cell 【发布时间】:2015-04-07 05:35:58 【问题描述】:

我有一个关于在 tableView Cell 中添加子视图的小问题。

我的单元格背景从百分比计数来看是动态的..

我得到正确的百分比,我可以完美地设置背景,但是当我添加一个新条目时......一切都搞砸了

我得到的新条目是完美的,但即使在我调整大小之后,之前的单元格仍然保持不变。

神奇的事情是当我停下来并按照自己的方式构建它时..

请帮帮我..

我使用下面的代码来实现这个...

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
// Dequeue the cell.
speedoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"speedoCell" forIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

CGRect rect = cell.frame;

NSLog(@"Cell width = %f",rect.size.width);
float cell_width=rect.size.width;
float per;
float viewSize=0.0;


if (self.recent_calls.count == 0) 
    cell.title.text =@"No records";
    cell.desc.text =@"";


else
    NSInteger indexOfFirstname = [self.dbManager.arrColumnNames indexOfObject:@"ex_category"];
    NSInteger indexOfSecondname = [self.dbManager.arrColumnNames indexOfObject:@"totle"];

    NSString *totle_cat=[NSString stringWithFormat:@"%@", [[self.recent_calls objectAtIndex:indexPath.row] objectAtIndex:indexOfSecondname]];

    int x=[totle_cat intValue];
    NSLog(@"%d--yoyoyoyoyoyoyoyoyoyo--%d",x,amount_totle);

    float result=0;

    result=((float)x/(float)amount_totle)*100;

// cell_width is static = 343.0 ..... result is percentage we found
viewSize=(cell_width*result)/100;

     NSLog(@"%f----------",viewSize);

    UIView *view,*view1;


    view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
    view1=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];


    view1.frame=CGRectMake(5, 5, cell.frame.size.width-10, cell.frame.size.height-3);

    [view1.layer setCornerRadius:8.0f];
    [view1.layer setMasksToBounds:YES];
    [view1.layer setBorderWidth:0.5f ];


    CGRect frame = view.frame;
    frame.size.width = viewSize;
    frame.size.height=cell.frame.size.height-3;
    view.frame = frame;


    NSLog(@"%f",view.frame.size.width);

    [view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"road_panorama1.jpg"]]];


    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

    UIVisualEffectView *visualEffectView;
    visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];

    visualEffectView.frame = CGRectMake(0, 0, viewSize, cell.frame.size.height-3);
    [view addSubview:visualEffectView];

    [view1 setBackgroundColor:[UIColor whiteColor]];

    [view1 insertSubview:view atIndex:0];

    [cell.contentView insertSubview:view1 atIndex:0];
UIImage *image;
    if ([category isEqualToString:@"Travel"]) 
        image=[UIImage imageNamed:@"taxi13.png"];

    
    else if ([category isEqualToString:@"Food"]) 

        image=[UIImage imageNamed:@"fastfood6.png"];
    
    else if ([category isEqualToString:@"Medical"]) 

        image=[UIImage imageNamed:@"stethoscope11.png"];
    
    else if ([category isEqualToString:@"Shopping"]) 

        image=[UIImage imageNamed:@"shopping-cart13.png"];
    
    else


        image=[UIImage imageNamed:@"question-mark2.png"];
    


    [cell.img setImage:image];





return cell;

从第二个视图控制器添加条目

 NSString *query= [NSString stringWithFormat:@"insert into ex_man_last (ex_title,ex_amount,ex_description,ex_date,ex_category,ex_upload_date,ex_image,ex_my) values ('%@','%@','%@','%@','%@','%@','%@','%@')",_ex_title.text,_ex_amount.text,_ex_description.text,_ex_date.text,_ex_category.text,datestring,imageName,my ];

// Execute the query.
[self.dbManager executeQuery:query];

并调用该方法从视图中的数据库获取更新的条目将出现方法..

 NSString *query =[NSString stringWithFormat:@"SELECT *,sum(ex_amount) as totle FROM ex_man_last where ex_my='%@' GROUP BY ex_category ",query_date];


if (self.recent_calls != nil ) 
    self.recent_calls = nil;


self.recent_calls = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
NSLog(@"--->%@",_ex_main);
NSLog(@"%lu",(unsigned long)[self.recent_calls count]);

NSInteger indexOfSecondname = [self.dbManager.arrColumnNames indexOfObject:@"totle"];

for (int i=0; i<[self.recent_calls count]; i++) 
    NSString *amount=[[self.recent_calls objectAtIndex:i] objectAtIndex:indexOfSecondname] ;
    amount_totle=amount_totle+[amount intValue];

整个代码在索引路径方法的行的单元格中......

请帮帮我...提前谢谢...

【问题讨论】:

对于您的重新启动,它工作正常,因为单元格中的代码是正确的,您如何向表格视图添加新条目是您确保重新加载表格视图。跨度> 你没有考虑单元格的重复使用。当您滚动并重用一个单元格时,您会将 view1 添加到一个已经有 view1 的单元格中。 您能否发布您对 cellForRowAtIndexPath: 的完整实现以及添加新条目和重新加载表格的方式? 我确实在 viewDidAppear 方法中重新加载了表格,好的,我将其发布完成 您的问题解决了吗? 【参考方案1】:

好的,让我们试试这个,

为什么你在 cellForRowAtIndexPath 方法中做所有事情,它的工作是返回单元格以供 tableview 处理,而不是处理单元格内的所有子视图

Cell 是负责处理其中所有内容的单元。它包含包含您的视图组件的内容视图,所以我们不允许单元格处理其视图组件。为此,我们需要将一些信息传递给它,例如您的案例百分比和标签文本以及您正在显示和休息的图像将其留给单元格。如果您根据 (MVC) 模式修改某些内容或添加新组件,这也将使用完整的功能。

我不会只关注您的问题,在您的cellForRowAtIndexPath 中,您每次都会继续添加新视图,即使对于重复使用的单元格也是如此。只需删除所有视图处理代码(这将在自定义单元格中使用)

如果您只想创建一个新项目并尝试一下,真的,我在这里尝试了您的代码,它工作正常,所以让我们尝试一个新项目,以便您清楚地理解,最后我也会添加 gif 文件以显示结果。

首先使用UITableViewCell 的子类创建一个新文件,并给它一个名称,我将其命名为CustomCell

CustomCell.h 文件中

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface CustomCell : UITableViewCell

 //creating the properties for all view components and also for percentage value that we need for calculating of width
 //i took your code hear 
@property (nonatomic, assign) CGFloat percentage;
@property (nonatomic, assign) CGFloat viewWidth;

@property (nonatomic, strong) UIView *view;
@property (nonatomic, strong) UIView *view1;

@property (nonatomic, strong)  UIBlurEffect *blurEffect ;

@property (nonatomic, strong) UIVisualEffectView *visualEffectView;
@property (nonatomic, strong)  UILabel *percentageLabel ;
@end

CustomCell.m 文件中

#import "CustomCell.h"

@implementation CustomCell

//we are using this to create new cell just override it and call super
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
  
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self)
    
       [self initiliseViewComponents]; //hear we are adding views to cell
    
    return self;
 

 - (void)setPercentage:(CGFloat)percentage
 
    float result=0;
    result=((float)percentage/(float)100)*100;
    _percentage = result;
   _viewWidth = result*343 / 100;
   _percentageLabel.text = [NSString stringWithFormat:@"%d",(int)_percentage]; //to show the percentage 


//at this point we don't no the size of cell, 
//same what u are doing in your project just initialising and add it to cell's content view 
- (void)initiliseViewComponents

  _view             = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];
  _view1            = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];

 _blurEffect       = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
 _visualEffectView = [[UIVisualEffectView alloc] initWithEffect:_blurEffect];

 _percentageLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];


 [_view addSubview:_visualEffectView];
 [_view1 setBackgroundColor:[UIColor whiteColor]];

 [_view1 insertSubview:_view atIndex:0];
 [self.contentView insertSubview:_view1 atIndex:0];
 [self.contentView addSubview:_percentageLabel];


- (void)awakeFromNib 
 // Initialization code
 

- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
   [super setSelected:selected animated:animated];
   // Configure the view for the selected state
 

 //in this method just set frames for your subviews this method will be called automatically 
//dont change the cell's frame just the subviews frame 

 - (void)layoutSubviews
 
   _percentageLabel.frame = CGRectMake(self.contentView.bounds.size.width - 50, self.contentView.bounds.origin.y + 10, 50, 50);

  CGRect cellFrame = self.contentView.frame;
  cellFrame.origin.x += 5;
  cellFrame.origin.y += 5;
  cellFrame.size.width -= 10;
  cellFrame.size.height -= 3;
  _view1.frame=cellFrame;

  [_view1.layer setCornerRadius:8.0f];
  [_view1.layer setMasksToBounds:YES];
  [_view1.layer setBorderWidth:0.5f ];

  // [_view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"images2.jpg"]]];
  [_view setBackgroundColor:[UIColor redColor]];
  self.backgroundColor = [UIColor clearColor];

  CGRect frame      = _view.frame;
  frame.size.width  = _viewWidth;
  frame.size.height = self.frame.size.height-3;
  _view.frame = frame;
  _visualEffectView.frame = CGRectMake(0, 0, _viewWidth, frame.size.height);
  NSLog(@"%f",_view.frame.size.width);

  [super layoutSubviews]; //finally call super


@end

然后来到主控制器 在主视图控制器中, 添加一个 tableview 并为它刮匙一个出口

//in ViewController.h
@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *aTableView;
@property (strong,nonatomic) NSMutableArray *aMutableArray; //to holde percentages

ViewController.m实现数据源和委托

- (void)viewDidLoad

  [super viewDidLoad]; 
  _aMutableArray = [[NSMutableArray alloc]initWithObjects:@(20),@(30),@(50), nil]; //initially it has 3 values we will add some more dynamically


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

   return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

   return _aMutableArray.count;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

   CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL"];
   if(cell == nil)
   
      cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CELL"];
   
   cell.percentage = [[_aMutableArray objectAtIndex:indexPath.row] floatValue];
   return cell;


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

   return 60.0f;


//this action method to add new cell dynamically at the top of the tableview
- (IBAction)addButtonAction:(id)sender

   CGFloat nextPerent = arc4random_uniform(80) % 100; //i took some random percentage values 
   [_aMutableArray insertObject:[NSNumber numberWithFloat:nextPerent] atIndex:0];
   [_aTableView reloadData];

所以点击运行按钮,结果将如下所示

对不起,我不得不压缩它的 gif 图像质量有点低蓝色按钮是添加新单元格到 tableview 和它不需要的标签

希望对你有帮助

【讨论】:

【参考方案2】:

当您使用 speedoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"speedoCell" forIndexPath:indexPath]; 使用可重复使用的单元格时

因此,一旦分配了单元格,它将一次又一次地重复使用。

考虑一个案例,您第一次创建包含两个单元格的表格,如屏幕截图 1 所示,Medical 和 Travel 分别具有 80% 和 20%,因此您创建了模糊视图并将其添加到白色视图上,最后您插入了 view1 (包含模糊效果的白色背景视图)在单元格 contentView 的第 0 个索引上。

上述案例完美运行。

再次,您插入新条目(单元格)食物,所有事情都搞砸了!!! 这里的问题是,由于之前为索引 0 和 1 创建了两个单元格,因此它们被重复使用,这次数据被更改,因此您计算了模糊和白色区域,创建了视图并再次插入到索引 0 处的单元格的 contentView 上,这就是问题所在。

已经在索引处插入的视图将可见,而与在父视图的同一索引处添加的其他视图无关。

要解决这个问题,如果单元格被重用,你必须检查重用单元格是否包含具有模糊效果的白色背景视图,然后你必须先将其删除,重新计算模糊和白色区域并再次在单元格内容视图的索引 0 处插入 view1。

这就是单元格被重用的时间,所以首先我们从单元格的内容视图中删除索引 0 处已经插入的视图,再次创建白色+模糊视图并将新创建的视图插入到单元格内容的第 0 个索引处视图,并且总是会显示新创建的(因为有时会存在一个,而之前的会被删除)。

【讨论】:

只需将标签分配给 view1,然后将其作为 [view1 setTag:VIEW_TAG] 插入到单元格的内容视图中; 然后像你一样添加它 [cell.contentView insertSubview:view1 atIndex:0]; 当您访问单元格时,speedoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"speedoCell" forIndexPath:indexPath];,然后检查单元格的内容视图是否包含标记视图 UIView *view1 = [cell.contentView viewWithTag:VIEW_TAG]; if(view1) [view1 removeFromSuperview];

以上是关于在表格视图单元格中动态调整子视图的大小的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式动态调整多行 UILabel 和随附的表格视图单元格

如何使用自动布局来调整表格视图单元格中的视图大小?

为啥自调整大小的表格视图单元格中的 UIImageView 具有内容模式 AspectFit 的原始高度?

使用自动布局进行编辑时在表格视图中调整子视图的大小

动画在具有动态单元格高度的单元格中添加子视图

ios在表格视图单元格中视觉调整图像大小