Изменение позиции пользовательского UIButton в пользовательском UITableViewCell

Мне нужно динамически менять положение UIButton. Я делаю это в cellForRowAtIndexPath:. Я изменяю рамку кнопки в этом методе. Изменение не отображается, когда таблица изначально отображается. Но когда я просматриваю ячейки и возвращаюсь к ней, она отображается. Точно так же, когда я сначала просматриваю ячейки, которые не видны изначально, изменений нет. Изменение происходит, когда я прокручиваю его во второй раз.

Я попробовал setNeedsDisplay: как на пользовательской кнопке, так и на представлении таблицы. Я сделал это даже в willDisplayCell:forRowAtIndexPath:. Как это решить?

EDIT: Я забыл упомянуть, что загружаю UITableViewCell из файла nib. Вот код для изменения размера кадра.

label1.text  = //text from some source
label1.text = [label1.text stringByAppendingString:@"  |"];
[label1 sizeToFit];
CGRect frameAfterResize=label1.frame;
float x=frameAfterResize.origin.x+frameAfterResize.size.width;
button.frame=CGRectMake(x+2, button.frame.origin.y, button.frame.size.width,button.frame.size.height);

Ответ 1

Создайте свой собственный подкласс UITableViewCell. Создайте и добавьте кнопку в ячейку contentView в свой метод init или создайте и добавьте ее лениво через свойство accessor. Переопределите layoutSubviews и разместите кнопку по желанию.

Что-то вроде этого:

@implementation MyCustomCell

- (void) init
{
    self = [super initWithStyle: UITableViewCellStyleDefault reuseIdentifier: nil];
    if ( self != nil )  
    {
         _myButton = [[UIButton buttonWithType: UIButtonTypeRoundedRect] retain];
         [self.contentView addSubview: _myButton];
    }

    return self;
}

- (void) layoutSubviews
{
    [super layoutSubviews];

    // dynamic layout logic:
    if ( ... )
    {

         _myButton.frame = CGRectMake( 10, 10, 100, 30 );
    }
    else 
   {
         _myButton.frame = CGRectMake( 20, 10, 50, 30 );

   }
}

В качестве альтернативы вы можете попытаться выполнить компоновку ячеек в - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

Ответ 2

У меня была та же проблема, в которой я загружал ячейку из наконечника, но ни одно из вышеперечисленных решений не работало для меня. Они решили проблему для нескольких сценариев, но не для всех.

Вот решение, которое работало для всех сценариев.

@implementation MyChannelCell
-(void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    //Calling from here fixed issue for first time cell load
    [self alignCellViews];
}
-(void)layoutSubviews
{
    [super layoutSubviews];
    //Calling from here fixed issue for coming back to the tableview from other ViewConroller
    [self alignCellViews];

}
/**
Method to change the layout and positions of sub-views
*/
-(void)alignCellViews
{
    //Code to position sub-views
    //self.lblSubscribers is an outlet from nib of type UILabel
    [self.lblSubscribers setFrame:CGRectMake(140, 26, 36, 26)];

    [self setNeedsDisplay];
}

@end

Ответ 3

Вы пытались перезагрузить таблицу после изменения фрейма ячейки с помощью

[self.tableView reloadData]

Я думаю, он должен решить вашу проблему.

Ответ 4

  • Создайте собственный подкласс UITableViewCell
  • Подключите все выходы (кнопка также) от вашего xib к этому классу
  • Создайте собственный метод в этом подклассе UITableViewCell, например, см. ниже, не можете его форматировать.
  • in cellForRowAtIndexPath: используйте этот метод для изменения фрейма и перерисовки ячейки

    [ячейка setNewFrame:....];

он отлично работает для меня

 -(void)setNewFrame:(CGRect)newFrame
    {
        myButton.frame=newFrame;
        [self setNeedsDisplay];
    }

если вы хотите настроить кнопку на текст

-(void)setNewCaption:(NSString)newCaption
{
  label1.text  = newCaption
  label1.text = [label1.text stringByAppendingString:@"  |"];
  // calculate new frame
  myButton.frame=//new frame
  [self setNeedsDiplay];
}

Ответ 5

Вызовите setNeedsDisplay с помощью объекта UITableViewCell.

[cell setNeedsDisplay];

в cellForRowAtIndexPath:

Ответ 6

Если он не отображается по требованию первоначально, но после прокрутки, я предполагаю, что вы изменяете позицию метки только тогда, когда ячейка выгружена, а не когда она изначально загружена из ниба.

Вы не указали эту часть своего метода cellForRowAtIndexPath, поэтому я не могу дать более конкретные рекомендации на данный момент, но либо код выше не выполняется, либо label1 равен нулю, когда создается новая ячейка (т.е. когда метод dequeue возвращает nil, и вы загружаете из nib).

Ответ 7

При рисовании UITableViews ячейки таблицы повторно используются, поэтому есть только один экземпляр UITableViewCell, идентифицированный строкой, переданной в dequeueReusableCellWithIdentifier:.

Если вы обновите ячейку в методе cellForRowAtIndexPath: она не будет иметь ожидаемого эффекта - каждый раз, когда вы будете ссылаться на одну и ту же ячейку (так что каждая ячейка будет иметь кнопку в той же позиции). Следовательно, проблема, которую вы видите, что прокрутка делает положение изменения кнопки.

Самый простой способ исправить вашу проблему - это изменить код, чтобы остановить повторное использование ячеек, создавая новую ячейку каждый раз в cellForRowAtIndexPath. Обновите код следующим образом:

// comment out this line
// cell = [tableView dequeueReusableCellWithIdentifier:identifier];

NSArray *nib = [[NSBundle mainBundle] loadNibNamed:nibName];
cell = [nib objectAtIndex:0];

Обратите внимание, что для повышения эффективности используются ячейки повторного использования (для экономии памяти и сокращения выделения памяти).

Ваше идеальное решение - создать собственный подкласс класса UITableViewCell и обновить положение UIButton в методе layoutSubviews.