web-dev-qa-db-fra.com

Comment augmenter par programme la hauteur des cellules UITableView dans l'iPhone?

J'ai la coutume séparée UITableViewCell pour afficher les données (ces données proviennent de la réponse JSON du serveur). Dans chaque UITableViewCell j'ai le bouton comme lire plus. Si l'utilisateur clique sur le bouton lire plus je veux pour ajouter par programme UILabel pour afficher des informations supplémentaires à partir du serveur. Mais initialement, j'ai défini la hauteur de UITableViewCell donc après avoir cliqué sur le bouton lire plus, je ne peux pas voir les informations supplémentaires UILabel ..

Voici la capture d'écran:

enter image description here

Ceci est mon écran requis:

enter image description here

C'est le codage suivant que j'ai utilisé:

-(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];
}
20
Kalai

Tout d'abord, prenez une variable bool & int.

BOOL isReadMoreButtonTouched = NO;
int indexOfReadMoreButton = -1;

Implémentez ensuite ci-dessous avec votre code

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

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

Maintenant implémentez 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];
}

Maintenant, venez à heightForRowAtIndexPath

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

J'espère que cela fonctionnera pour vous.

25
Tapas Pal

Prenez un int readMoreAtIndex; comme variable de classe. Initialisez-le avec une valeur négative comme -1 dans init method et/ou viewDidLoad/viewWillAppear. Une logique de base serait comme ceci:

- (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");
}

EDIT: Liens pour les tutoriels pour implémenter la table extensible/pliable.

  1. développer/réduire les sections TableView
  2. Vue de tableau pliable pour iOS
4
Salman Zaidi

J'ai trouvé une autre solution basée sur auto-dimensionnement cellules de vue de table. Au lieu de mettre à jour la hauteur de cellule (codé en dur), nous pouvons mettre à jour la priorité des contraintes.

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()
   }
}

J'ai une classe personnalisée qui représente une cellule "MyCell" qui gère les mises à jour du protocole et des contraintes:

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)
     }
   }
}

Voici un exemple montrant à quoi il ressemble: Ma cellule personnalisée MyCell

2
Martin Deandreis

Vous devez mettre une sorte de mécanisme de drapeau et gérer la hauteur

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

Le meilleur et le meilleur moyen est de calculer la hauteur en fonction du texte, puis de renvoyer la hauteur

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

Si vous utilisez la mise en page automatique, vous pouvez calculer la taille de chaque étiquette manuellement en fonction du contenu en utilisant la méthode sizeToFit

1
Jay Gajjar

Je vous suggère de suivre ces étapes:

Dans une cellule personnalisée, le contenu qui sera à votre disposition, placez-le dans un conteneur UIView caché. Il n'est donc pas visible par défaut.

  1. Lorsque vous lisez plus de boutons, gérez son déclencheur d'événement à l'intérieur de la classe qui dessine tableView comme vous le faites funReadmore handler.

  2. Prenez l'index de la cellule et gérez/ajoutez-le dans l'objet NSMutableArray.

  3. Recharger les données TableView en utilisant:

[yourTableViewInstance reloadData];
  1. Dans la fonction déléguée heightForRowAtIndexPath, écrivez-la comme ceci:
 - (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath 
 {
 If (arrayOfExpandedCellIndexes.contains (indexPath.row)) 
 retourne EXTENDED_CELL_HEIGHT; // Macro: #define EXTENDED_CELL_HEIGHT 230.0f 
 Else 
 Return NORMAL_CELL_HEIGHT; // Macro: #define NORMAL_CELL_HEIGHT 100.0f 
} 

De cette façon, vous pouvez gérer plusieurs cellules en appuyant sur le bouton Lire la suite. Si dans votre besoin une seule cellule peut être développée, effacez votre arrayOfExpandedCellIndexes en utilisant:

[arrayOfExpandedCellIndexes removeAllObjects];

REMARQUE: Une fois la hauteur ajustée pour une cellule, n'oubliez pas de rendre visible la vue cachée.

J'espère que ça aide!

1
NeverHopeless

Je publie l'exemple de code qui développera la cellule en fonction du clic sur le bouton et la taille du texte fonctionne pour iOS6 et iOS 7, ce n'est qu'un exemple de code, passez par ceci, cela peut vous aider ... :)

ce n'est qu'un exemple de projet que vous pouvez essayer


     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


dans 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


en vueContrôleur

      #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


MODIFIER: AJOUTÉ ButtonClickedForExpand au premier clic

EDIT: 2 ont changé if(self.previousIndexPath.row == nil) dans la méthode "whenReadMoreButtonClicked" du contrôleur de vue

Commente si tu n'obtiens pas

1
Shankar BS