Как программно увеличить высоту ячейки UITableView в iPhone?
У меня есть отдельный пользовательский UITableViewCell
для отображения данных (эти данные поступают из ответа сервера JSON). В каждом UITableViewCell
у меня есть кнопка, как прочитанная далее. Если пользователь нажимает кнопку "Читать дальше", я хочу программно добавить UILabel
для отображения дополнительной информации с сервера. Но сначала я установил высоту UITableViewCell
, поэтому после нажатия кнопки "читать больше" я не могу видеть дополнительную информацию UILabel
..
Это снимок экрана:
![enter image description here]()
Это мой обязательный экран:
![enter image description here]()
Это следующее кодирование, которое я использовал:
-(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];
}
Ответы
Ответ 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;
}
Надеюсь, что это сработает для вас.
Ответ 2
Возьмите int readMoreAtIndex;
в качестве переменной класса. Инициализируйте его с отрицательным значением, например -1 в init method
и/или viewDidLoad/viewWillAppear
. Некоторая базовая логика будет такой:
- (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");
}
РЕДАКТИРОВАТЬ: Ссылки для учебных пособий для реализации расширяемого/сбрасываемого табличного представления.
Ответ 3
Я нашел другое решение на основе self-sizing элементов таблицы. Вместо того, чтобы обновлять высоту ячеек (hardcoded), мы можем обновить приоритет ограничений.
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)
}
}
}
Вот пример, показывающий, как он выглядит: Моя пользовательская ячейка MyCell
Ответ 4
Вам нужно поставить какой-то механизм флага и управлять высотой в
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Лучшим и идеальным способом является вычисление высоты в соответствии с текстом, а затем возврат высоты
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(readMore){
return 500;
}else{
return 100;
}
}
Если вы используете автозапуск, вы можете рассчитать размер каждой метки вручную в соответствии с содержимым с помощью метода sizeToFit
Ответ 5
Я отправляю образец кода, который будет расширять ячейку на основе нажатия кнопки и размер текста работает как для 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
in viewController
#import "ViewController.h"
#import "CustomCell.h"
@interface ViewController ( <UITableViewDataSource,UITableViewDelegate,ButtonClickDelegate>//confirm 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
EDIT: ADDED ButtonClickedForExpand
для первого щелчка
EDIT: 2 изменен if(self.previousIndexPath.row == nil)
в методе просмотра "whenReadMoreButtonClicked" контроллера просмотра
Комментарий, если u не получает
Ответ 6
Я предлагаю вам выполнить следующие действия:
В пользовательской ячейке содержимое, которое будет доступно вам, поместите его в скрытый контейнер UIView. По умолчанию он не отображается.
-
Когда вы читаете больше нажатий кнопок, обрабатывайте свой триггер события внутри класса, который рисует tableView, когда вы выполняете его funReadmore
.
-
Возьмите индекс ячейки и выполните управление/добавьте его в объект NSMutableArray
.
-
Перезагрузите данные TableView, используя:
[yourTableViewInstance reloadData];
- В функции
heightForRowAtIndexPath
delegate, напишите его следующим образом:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(arrayOfExpandedCellIndexes.contains(indexPath.row))
return EXTENDED_CELL_HEIGHT; // Macro : #define EXTENDED_CELL_HEIGHT 230.0f
else
return NORMAL_CELL_HEIGHT; // Macro : #define NORMAL_CELL_HEIGHT 100.0f
}
Используя этот способ, вы можете обрабатывать более одной ячейки с нажатой кнопкой "Читать дальше". Если по вашему требованию только одна ячейка может быть расширена, очистите свой arrayOfExpandedCellIndexes
, используя:
[arrayOfExpandedCellIndexes removeAllObjects];
ПРИМЕЧАНИЕ. Как только высота настроена для ячейки, не забудьте сделать скрытый вид видимым.
Надеюсь, что это поможет!