【问题标题】:How to programmatically increase UITableView cell's height in iPhone?如何以编程方式增加 iPhone 中的 TableView 单元格高度?
【发布时间】:2014-02-19 05:43:54
【问题描述】:

我有单独的自定义 UITableViewCell 用于显示数据(这些数据来自服务器 JSON 响应)。在每个 UITableViewCell 中,我都有阅读更多按钮。如果用户单击阅读更多按钮,我想以编程方式添加UILabel 用于显示来自服务器的附加信息。但最初我设置了UITableViewCell 高度,所以在单击阅读更多按钮后我无法看到附加信息UILabel..

这是屏幕截图:

这是我需要的屏幕:

这是我使用的以下编码:

-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

   int height1;
    if(readMore){
        height1=200;
        NSLog(@"Clicked");
    }
    else{
        height1=100;
        NSLog(@"Not clicked");
    }
    return height1; // Normal height
}


-(NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
    return [TitleArr  count];
}


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

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        static NSString *simpleTableIdentifier = @"SimpleTableCell_iPad";

        cell = (TableCell_Leads *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    }
    else{
        static NSString *simpleTableIdentifier = @"TableCell_Leads";

        cell = (TableCell_Leads *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    }
    if (cell == nil)
    {
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        {
            NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell_iPad" owner:self options:nil];
            cell = [nib objectAtIndex:0];

        }
        else{
            NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"TableCell_Leads" owner:self options:nil];
            cell = [nib objectAtIndex:0];
        }
    }




    cell.labTitle.text = [TitleArr objectAtIndex:indexPath.row];

    cell.labCategory.text=[CategoryArr objectAtIndex:indexPath.row];

    [cell.btnReadmore addTarget:self
                         action:@selector(funReadmore:)
               forControlEvents:UIControlEventTouchUpInside];


    return cell;
}



 - (IBAction)funReadmore:(id)sender
    {
        [self.tableView beginUpdates];
        readMore=TRUE;



        NSLog(@"READ MORE");
        [self.tableView endUpdates];
}

【问题讨论】:

  • 请给我建议..这是一个非常迫切的需求..
  • 查看我的示例项目..

标签: ios objective-c iphone uitableview


【解决方案1】:

首先取一个bool & int 变量。

BOOL isReadMoreButtonTouched = NO;
int indexOfReadMoreButton = -1;

然后用你的代码在下面实现

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    [[cell btnReadmore] setTag:[indexPath row]];

    if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton)
    {
       // design your read more label here
    }
}

现在实施 IBAction

-(IBAction) funReadmore:(id)sender
{
    UIButton *readMoreButton = (UIButton *)sender;
    indexOfReadMoreButton=[readMoreButton tag];
    isReadMoreButtonTouched=YES;

    [[self tableView] beginUpdates];
    [[self tableView] reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForItem: indexOfReadMoreButton inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
    [[self tableView] endUpdates];
}

现在就来heightForRowAtIndexPath

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton) return 200.0f;
    else return 100.0f;
}

希望它对你有用。

【讨论】:

  • 是的,感谢您的建议,我修改了我的编码(就像您发布的一样),但 uitableview 单元格高度没有改变
  • 你的heightForRowAtIndexPath 是否在点击阅读更多按钮后被调用?
  • No heightForRowAtIndexPath 方法在我触摸阅读更多按钮时未调用。
  • 我想知道当我按下按钮时没有被调用 heightForRowAtIndexPath 方法的原因是什么???
  • 好的,你可以reload 你的表格视图代替reloadRowsAtIndexPaths 一次吗?然后检查你的heightForRowAtIndexPath 是否被调用
【解决方案2】:

int readMoreAtIndex; 作为您的类变量。在init method 和/或viewDidLoad/viewWillAppear 中使用负值(如-1)对其进行初始化。一些基本逻辑是这样的:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    if(readMoreAtIndex == indexPath.row) {
        return 400; //return as per your requirement
    }
    return 100;
}

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

    //same lines as currently you are doing to setup cell.     

    //important line
    [cell.btnReadmore setTag:indexPath.row];

    [cell.btnReadmore addTarget:self
                         action:@selector(funReadmore:)
               forControlEvents:UIControlEventTouchUpInside];

    if(indexPath.row == readMoreAtIndex) {
        //setup your cell according to your logic to show expanded view
    }
    else {
        //you are reusing cells, so provide logic to disappear shown expanded view if you want
    }

    return cell;
}

- (IBAction)funReadmore:(id)sender
{     
    UIButton *button = (UIButton *)sender;
    readMoreAtIndex = button.tag;
    [yourTableView reloadData];
    NSLog(@"READ MORE");
}

编辑:实现可展开/可折叠表格视图的教程链接。

  1. Expanding/Collapsing TableView Sections
  2. Collapsable Table View for iOS

【讨论】:

  • 很抱歉给您带来不便。我正在使用您的编码。但它没有为我的要求提供任何解决方案.. :(
  • 编辑您的问题并发布您如何显示扩展视图??
  • 你能提供一些关于我需要的示例或教程吗??
  • 我在我的一个项目中使用相同类型的代码。顺便说一句,工作正常。我正在编辑答案以添加指向教程和有用材料的链接。
  • 感谢您的教程链接...:)
【解决方案3】:

我找到了另一个基于self-sizing 表格视图单元格的解决方案。我们可以更新约束优先级,而不是更新单元格的高度(硬编码)。

fileprivate extension Int {
   static let rowHeight = 175
}

class CellArticleData {
  var article: Article
  var isExpanded: Bool

  init(article: Article, isExpanded: Bool) {
    self.article = article
    self.isExpanded = isExpanded
  }
}

 enum Article: String {
    case medicine, sport
    static let allArticles: [Article] = [.medicine, .sport]
    var title: String { return self.rawValue.capitalized }
    var description: String {
        switch self {
          case .medicine:
            return "Lorem Ipsum is simply dummy text of the printing and 
            typesetting industry"
          case .sport:
            return "Contrary to popular belief, Lorem Ipsum is not simply 
            random text. It has roots in a piece of classical Latin 
            literature from 45 BC, making it over 2000 years old. Richard 
            McClintock, a Latin professor at Hampden-Sydney College in 
            Virginia."
      }
   }
}

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
var articles: [CellArticleData] = Article.allArticles.map { CellArticleData(article: $0, isExpanded: false) }

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self
    tableView.delegate = self
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = CGFloat(.rowHeight)
}

 extension ViewController: UITableViewDataSource {

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
    let articleData = articles[indexPath.row]
    cell.setup(articleData: articleData)
    cell.delegate = self
    return cell
  }
}

extension ViewController: MyCellDelegate {

  func handleReadMore() {
      tableView.reloadData()
   }
}

我有一个自定义类,代表处理协议和约束更新的单元格“MyCell”:

protocol MyCellDelegate {
    func handleReadMore()
}

class MyCell: UITableViewCell {

   @IBOutlet weak var topConstraint: NSLayoutConstraint!
   @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
   @IBOutlet weak var heightConstraint: NSLayoutConstraint!

  func setup(articleData: CellArticleData) {
    self.articleData = articleData

    titleLabel.text = articleData.article.title
    descriptionLabel.text = articleData.article.description
    readMoreLabel.isUserInteractionEnabled = true

    let readMoreTap = UITapGestureRecognizer(target: self, action: #selector(handleReadMore))
    readMoreTap.cancelsTouchesInView = false
    readMoreLabel.addGestureRecognizer(readMoreTap)
    updateCellConstraints()
}

fileprivate func updateCellConstraints() {
    if let articleData = self.articleData {
        if !articleData.isExpanded {
            heightConstraint.priority = 999
            topConstraint.priority = 250
            bottomConstraint.priority = 250
        }else {
            heightConstraint.priority = 250
            topConstraint.priority = 999
            bottomConstraint.priority = 999
        }

    }
  }

   func handleReadMore() {
      if let articleData = self.articleData {
         articleData.isExpanded = !articleData.isExpanded
         delegate?.handleReadMore(articleData: articleData)
     }
   }
}

下面是一个例子,展示了它的样子: My custom cell MyCell

【讨论】:

    【解决方案4】:

    你需要放置某种标志机制并管理高度

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

    最好最理想的方式是根据文字计算高度,然后返回高度

     - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {       
        if(readMore){
          return 500;
         }else{
          return 100;
         }
    }
    

    如果您使用自动布局,则可以使用sizeToFit方法根据内容手动计算每个标签的大小

    【讨论】:

    • 我把这些代码放在哪里了?
    • if(readMore) 最初被调用。但是当我按下阅读更多按钮时,高度不会改变:(
    • 这是一个非常迫切的需求..请给我一些简单的解决方案
    • 是的,我编辑了我的问题..你能提供一些关于我需要的示例或教程吗?
    【解决方案5】:

    我建议您按照以下步骤操作:

    在自定义单元格中,您可以使用的内容,将其放在隐藏的 UIView 容器中。所以默认是不可见的。

    1. 当读取更多按钮按下时,在绘制 tableView 的类中处理它的事件触发器,就像你正在做的那样funReadmore 处理程序。

    2. 获取单元格的索引并在NSMutableArray对象中管理/添加。

    3. 使用以下方法重新加载 TableView 数据:

    [yourTableViewInstance reloadData];
    1. heightForRowAtIndexPath委托函数中,这样写:
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if(arrayOfExpandedCellIndexes.contains(indexPath.row)) 返回 EXTENDED_CELL_HEIGHT; // 宏:#define EXTENDED_CELL_HEIGHT 230.0f 别的 返回 NORMAL_CELL_HEIGHT; // 宏 : #define NORMAL_CELL_HEIGHT 100.0f }

    使用这种方式,您可以在按下“阅读更多”按钮的情况下处理多个单元格。如果您的要求只能扩展一个单元格,请使用以下命令清除您的arrayOfExpandedCellIndexes

    [arrayOfExpandedCellIndexes removeAllObjects];
    

    注意:一旦调整了单元格的高度,不要忘记让隐藏的视图可见。

    希望对你有帮助!

    【讨论】:

    • 这种方法在尝试扩大单元格大小时对我不起作用
    • @NSNoob,你能告诉你当时得到了什么吗?我用过这种方法,效果很好。
    • 我这样做是为了增加包含章节/书籍标题的单元格大小。 pastebin.com/HRfEpseg 在第一个单元格(第一本书的标题)上工作得很好。其余的,并没有按计划进行
    • 几个问题:1) 当单元格应该展开时,您是否处理了 UIView 可见性? 2) 你确定你在heightForRowAtIndex 函数中引用了正确的数据源吗? 3)你如何在数据源中存储价值?在您使用NSString 时,我直接存储了indexPath.row(整数)。你能澄清一下这些吗?
    • 我没有像“扩展点击”那样做。创建表格时,我正在增加特定单元格的单元格大小。例如章节标题和书名比普通单元格大。是的,数据源是正确的,它们包含存在章节名称和书名的主数组的索引。这就是我使用字符串的原因,因为索引存储为字符串。
    【解决方案6】:

    我发布的示例代码将根据按钮单击展开单元格,并且文本大小适用于 iOS6 和 iOS 7,这只是示例代码,请仔细阅读,这可能会对您有所帮助 ... :)

    这只是一个你可以尝试的示例项目


         in customCell.h
         #import <UIKit/UIKit.h>
         @class CustomCell;
         @protocol ButtonClickDelegate <NSObject> //custom delegate
         - (void)whenReadMoreButtonClicked:(CustomCell *)cell;//i am passing the cell itself
         @end
    
         @interface CustomCell : UITableViewCell
         @property (nonatomic,assign)id<ButtonClickDelegate>delegate;
        @property (nonatomic,retain)UILabel *mesageLabel;
        @property (nonatomic,retain)NSString *message;
        @property (nonatomic,assign)BOOL expand;
    
        @end
    


    在 customCell.m 中


        #import "CustomCell.h"
    
        @implementation CustomCell
        @synthesize delegate;//synthesize it
        @synthesize mesageLabel;
        @synthesize message;
        @synthesize expand;
    
    
        - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
       {
          self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
          if (self) {
         // Initialization code
          UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(5,2, 100, 35)];
          [button addTarget:self action:@selector(whenButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
          [button setTitle:@"Read More" forState:UIControlStateNormal];
           button.backgroundColor = [UIColor greenColor];
    
          self.mesageLabel = [[UILabel alloc]initWithFrame:CGRectMake(0 , 40,0 ,0)];
           self.mesageLabel.backgroundColor = [UIColor redColor];
          self.mesageLabel.numberOfLines = 100;
          [self addSubview:self.mesageLabel];
           [self addSubview:button];
        }
         return self;
       }
    
      - (void)setSelected:(BOOL)selected animated:(BOOL)animated
      {
           [super setSelected:selected animated:animated];
    
          // Configure the view for the selected state
      }
    
       - (void)whenButtonClicked:(id)sender
       {
           if([self.delegate respondsToSelector:@selector(whenReadMoreButtonClicked:)])
           {
              [self.delegate whenReadMoreButtonClicked:self];//delegate to controller
           }
    
      }
    
      - (void)layoutSubviews
      {
           [super layoutSubviews];
          self.mesageLabel.text = self.message;
          if(self.expand)
          {
              CGSize size = [self findMessgeStringHeight];
              self.mesageLabel.frame = CGRectMake(0, 40, size.width, size.height);
          }
          else
          {
              self.mesageLabel.frame = CGRectMake(0, 40, self.bounds.size.width, 100);
          }
    
      }
    
    
       //helper method to find height
        - (CGSize)findMessgeStringHeight
         {  
             NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.message attributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:17.0f] }];
            CGRect rect = [attributedText boundingRectWithSize:(CGSize){225, MAXFLOAT}
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                               context:nil];
            CGSize requiredSize = rect.size;
    
             return requiredSize; //finally u return your height
         } 
    
         @end
    


    在视图控制器中

          #import "ViewController.h"
          #import "CustomCell.h"
    
          @interface ViewController ( <UITableViewDataSource,UITableViewDelegate,ButtonClickDelegate>//confirm's to delegate
          {
    
            BOOL ButtonClickedForExpand;
            NSMutableArray *array;
    
         }
    
         @property (nonatomic,retain)NSIndexPath *previousIndexPath;
          @property (nonatomic,retain)NSIndexPath *currentIndexPath;
    
         @end
    
        @implementation ViewController
         @synthesize previousIndexPath;
        @synthesize currentIndexPath;
    
        - (void)viewDidLoad
         {
             [super viewDidLoad];
            ButtonClickedForExpand = NO;
    // Do any additional setup after loading the view, typically from a nib.
          array = [[NSMutableArray alloc]initWithObjects:@"hello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext",@"some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext",@"ello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext ello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext ello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext ello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext ello happy coding some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtext some longtextsome longtext some longtext", nil];
          }
    
        - (void)didReceiveMemoryWarning
        {
           [super didReceiveMemoryWarning];
          // Dispose of any resources that can be recreated. 
        }
    
        - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
       {
           return 1;
       }
    
        - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
       {
          return array.count;
       }
         - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
      { 
          CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL"];
         if(cell == nil)
          {
            cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CELL"];
          }
    
         if(ButtonClickedForExpand)
         {
            if(indexPath.row == currentIndexPath.row)
            {
               cell.expand = YES;
            }
            else
           {
              cell.expand = NO;
           }
        }
        else
       {
           cell.expand = NO;
       }
    
        cell.message = [array objectAtIndex:indexPath.row];
        cell.delegate = self;//u need to set delegate to self
        return cell;
      }
    
       - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
      {
          CGSize size = [self findMessgeStringHeight:[array objectAtIndex:indexPath.row]];
         if(ButtonClickedForExpand)
          {
             if(indexPath.row == currentIndexPath.row)
             {
                 return size.height + 30;
             }
            else
            {
               return 100;//by default
            }
        }
        else
         {
             return 100;
         }
    
      } 
    
        //helper function to return the correct height for your label
      - (CGSize)findMessgeStringHeight:(NSString *)str
      {
    
         NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:str attributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:17.0f] }];
         CGRect rect = [attributedText boundingRectWithSize:(CGSize){225, MAXFLOAT}
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                               context:nil];
         CGSize requiredSize = rect.size;
    
         return requiredSize; //finally u return your height
      }
    
    
    
      - (void)whenReadMoreButtonClicked:(CustomCell *)cell
     {
           ButtonClickedForExpand = YES;
           self.previousIndexPath = self.currentIndexPath;
          self.currentIndexPath = [self.tableView indexPathForCell:cell];
    
    
           [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:self.currentIndexPath] withRowAnimation:UITableViewRowAnimationFade];
    
        if(self.previousIndexPath.row == nil)
         { 
          return;
         }
         else
         {
           [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:self.previousIndexPath] withRowAnimation:UITableViewRowAnimationFade];
          }
    
       }
    
    
       @end
    


    编辑:添加ButtonClickedForExpand 以进行首次点击

    EDIT:2 在视图控制器的“whenReadMoreButtonClicked”方法中更改了if(self.previousIndexPath.row == nil)

    如果你没有得到,请评论

    【讨论】:

      猜你喜欢
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 2020-05-31
      • 2013-01-09
      • 1970-01-01
      • 2017-01-10
      相关资源
      最近更新 更多