Как обновить динамически изменяющееся количество строк в разделе в UITable корреляте (и его ячейках)? - PullRequest
3 голосов
/ 02 февраля 2011

Я пытаюсь сделать подкласс UITableViewController, предоставляя мне UITableView с настройками моего приложения. У меня проблема при перезагрузке данных об изменении состояния UISwtitch.

Таблица состоит из 3 разделов:

секция 1 - один ряд постоянно

раздел 2 - UISwitch в первом ряду сделать этот раздел состоит из 1 или 3 ряды (в зависимости от состояния UISwitch)

раздел 3 - UISwitch в первом ряду сделать этот раздел состоит из 1 или 3 ряды (в зависимости от состояния UISwitch), но с другим UISwitch и дополнительные строки данных.

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

    switch ( section )
    {
        case 0:
            return 1;
            break;
        case 1:
            if ( limit_password_attempts )
                return 3;
            else 
                return 1;
            break;
        case 2:
            if ( lock_when_inactive )
                return 3;
            else 
                return 1;
            break;
        default:
            return 1;
            break;
    }  
}

Эти два UISwitch-ов в первых рядах второго и третьего разделов меняют BOOL соответственно

BOOL limit_password_attempts;
BOOL lock_when_inactive;

Моя проблема - когда я переключаю UISwitch (для exmpl) во втором разделе, тогда я ожидаю, что мой второй раздел расширится еще на 2 строки и будет заполнен новыми данными. Это расширяется, но новые клетки выглядят не так, как я хочу. Вторая строка становится копией первой строки в следующем разделе (строка с UISwitch для третьего раздела), а третьи строки возвращаются корректно в случае, если третий раздел не был расширен ранее, и если это было так, то эта строка становится копия второго ряда из третьего раздела.

Так что моя настройка ячейки выглядит следующим образом, я думаю, ошибка где-то здесь.

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

    UITableViewCell *cell = nil;
    static NSString *EnabledCellIdentifier = @"Enabled";
    cell = [tableView dequeueReusableCellWithIdentifier:EnabledCellIdentifier];

    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] 
                   initWithStyle: UITableViewCellStyleDefault 
                 reuseIdentifier: EnabledCellIdentifier]
                    autorelease];

        cell.detailTextLabel.enabled = YES;

        switch ( indexPath.section )
        {
            case 0: // section 1
                cell.textLabel.text = @"Banks settings";
                break;
            case 1: // section 2
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Limit passwords attempts";
                        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: actSwitch];

                        [actSwitch setTag: indexPath.section];
                        [actSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];

                        [self.view addSubview:actSwitch];
                        [actSwitch setOn:YES animated:NO];
                        [actSwitch setOn:NO animated:NO];

                        actSwitch.on = NO;
                        [cell addSubview: actSwitch];
                        cell.accessoryView = actSwitch;
                        [actSwitch release];
                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock after 3 atempts";
                        break;
                    case 2:
                        cell.textLabel.text = @"Lock for 30 min";
                        break;
                    default:
                        break;
                }
                break;
            }

            case 2: // section 3
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Lock when inactive";
                        UISwitch* pactSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: pactSwitch];

                        [pactSwitch setTag: indexPath.section];
                        [pactSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];

                        [self.view addSubview:pactSwitch];
                        [pactSwitch setOn:YES animated:NO];
                        [pactSwitch setOn:NO animated:NO];

                        pactSwitch.on = NO;
                        [cell addSubview: pactSwitch];
                        cell.accessoryView = pactSwitch;
                        [pactSwitch release];


                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock when inactive for 20 min";
                        break;
                    case 2:
                        cell.textLabel.text = @"Unlock key";
                        break;
                    default:
                        break;
                }
                break;
            }
            default:
                NSLog(@"%d", indexPath.section );
                break;
        }
    }
    return cell;
}

Похоже, есть какой-то скрытый от меня массив с данными строк, который заполняется onec, и контроллер таблицы каким-то образом обновляет таблицу в зависимости от того, какая строка появилась, обновляя только их. Почему он делает копии, при добавлении строки в раздел. Это как вставка узла в массив. Я думал, что это должно продвигать клетки вперед, а не просто копировать. Должен ли я удалить строки, чтобы сделать такой вид обновления таблицы? Я полагаю, что мне здесь не хватает некоторых базовых вещей. Какая-то концепция MVC? Но действительно ли здесь необходимо иметь модель данных или нет? Зачем? Если да, то как я могу это сделать?

Спасибо за любые ответы. Хорошего дня.


Это было в моем коде. Я просто не записал это в своем вопросе. Метод reloadData вызывается после переключения UISwtitch:

[pactSwitch setTag: indexPath.section];
[actSwitch addTarget: self
              action: @selector(actSwitchChanged:) 
    forControlEvents: UIControlEventValueChanged];

В методе actSwitchChanged:

-(void) actSwitchChanged: (UISwitch*) pSwitch {

    if ( [pSwitch tag] == 1 ) //section 2
        limit_password_attempts = !limit_password_attempts ;
    else if ( [pSwitch tag] == 2 ) //section 3
        lock_when_inactive = !lock_when_inactive;
    [self.tableView reloadData];

}

Таким образом, reloadData изменяет содержимое viewTable, но делает это не так, как я ожидаю.

Есть идеи?

Ответы [ 3 ]

4 голосов
/ 02 февраля 2011

Модель данных всегда существует ... даже если это просто набор операторов if, которые вызывает ваш UITableView. Я думаю, что это различие вызывает проблему.

Ваши логические значения представляют вашу базовую модель данных. Как и все изменения в моделях данных, вы должны сообщить табличному представлению, когда ваши базовые данные были изменены.

Попробуйте добавить следующий вызов при изменении одного из ваших логических значений.

[myTableViewController.tableView reloadData];
3 голосов
/ 04 февраля 2011

Вы правы, вы допустили ошибку - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.Если вы ищете простой способ реализации ячеек с разным расположением без подклассов UITableViewCell, то вам, например, нужно:

0) прочитать this для глубокого понимания программирования UITableView

1) метод, который возвращает тип ячейки для каждого макета

- (NSString*)typeOfCellForIndexPath:(NSIndexPath*)indexPath {
    NSString *ret = @"CellWithoutSwitch";
    if(indexPath.section != 0 && idextPath.row == 0) {
        ret = @"CellWithSwitch";
    }
    return ret;
}

2) метод, который возвращает ячейку для каждого типа

- (UITableViewCell*)cellForType:(NSString*)aType {
    UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: aType] autorelease];
    cell.detailTextLabel.enabled = YES;
    if ([aType isEqualToString:@"CellWithSwitch"]) {
        // just copy of your code
        // this does not need here
        cell.textLabel.text = @"Limit passwords attempts";
        // this needs but with CGRectMake(...) insted of CGRectZero
        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];
        // this does not need
        [cell setEditingAccessoryView: actSwitch];
        // this needs but for switch tag you should use #define SWITCH_TAG 777
        [actSwitch setTag: indexPath.section];
        // this does not need here
        [actSwitch addTarget: self
                      action: @selector(actSwitchChanged:) 
            forControlEvents: UIControlEventValueChanged];

        // wrong part of code
        [self.view addSubview:actSwitch];
        // this does not need here
        [actSwitch setOn:YES animated:NO];
        // wrong part of code
        [actSwitch setOn:NO animated:NO];

        actSwitch.on = NO;
        // ok
        [cell addSubview: actSwitch];
        // wrong part of code
        cell.accessoryView = actSwitch;
        // ok
        [actSwitch release];
    }
}

3) метод, которыйнастроить ячейку с путем

    - (void)cofigureCell:(UITableViewCell*)cell forIndexPath:(NSIndexPath*)indexPath {
        // just copy of your code
        switch ( indexPath.section )
        {
            case 0: // section 1
                cell.textLabel.text = @"Banks settings";
                break;
            case 1: // section 2
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Limit passwords attempts";
                        /* this part of code replace with UISwitch* actSwitch = (UISwitch*)[cell viewWithTag:SWITCH_TAG];
                        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: actSwitch];

                        [actSwitch setTag: indexPath.section];*/

                        [actSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];
                        /* all what you need now that cofigure an state of switch with limit_password_attempts variable - [actSwitch setOn:limit_password_attempts animated:NO];
// this is junk
                        [self.view addSubview:actSwitch];
                        [actSwitch setOn:YES animated:NO];
                        [actSwitch setOn:NO animated:NO];

                        actSwitch.on = NO;
                        [cell addSubview: actSwitch];
                        cell.accessoryView = actSwitch;
                        [actSwitch release];*/
                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock after 3 atempts";
                        break;
                    case 2:
                        cell.textLabel.text = @"Lock for 30 min";
                        break;
                    default:
                        break;
                }
                break;
            }

            case 2: // section 3
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        // look at previous configuration of switch
                        cell.textLabel.text = @"Lock when inactive";
                        UISwitch* pactSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: pactSwitch];

                        [pactSwitch setTag: indexPath.section];
                        [pactSwitch addTarget: self
                                       action: @selector(actSwitchChanged:) 
                             forControlEvents: UIControlEventValueChanged];

                        [self.view addSubview:pactSwitch];
                        [pactSwitch setOn:YES animated:NO];
                        [pactSwitch setOn:NO animated:NO];

                        pactSwitch.on = NO;
                        [cell addSubview: pactSwitch];
                        cell.accessoryView = pactSwitch;
                        [pactSwitch release];


                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock when inactive for 20 min";
                        break;
                    case 2:
                        cell.textLabel.text = @"Unlock key";
                        break;
                    default:
                        break;
                }
                break;
            }
            default:
                NSLog(@"%d", indexPath.section );
                break;
        }
    }

4) реализация последнего метода

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

    UITableViewCell *cell = nil;
    // get type for indexPath
    static NSString *EnabledCellIdentifier = [self typeOfCellForIndexPath:idextPath];
    cell = [tableView dequeueReusableCellWithIdentifier:EnabledCellIdentifier];

    if (cell == nil) 
    {
        // create a cell with needed type
        cell = [self cellForType:EnabledCellIdentifier];
    }

    // cofigure the cell
    [self cofigureCell:cell forIndexPath:indexPath];

    return cell;
}
0 голосов
/ 04 февраля 2011

Гай, спасибо за ответ.Это помогло мне, теперь таблица перезагружается правильно, когда я меняю условие UISwitch.Но мне пришлось изменить тэг для uiswitch, потому что мне нужно различать, с каким UISwitch я имею дело в методе actSwitchChanged, чтобы понять, является ли он limit_password_attempts или lock_when_inactive

Я предполагаю, что это не вызовет проблемы в будущем?Я имею в виду, что SWITCH_TAG здесь перезаписывается.А также, зачем мне #define SWITCH_TAG 777 нет лучшего способа пометить его?И почему 777?

                 cell.textLabel.text = @"Limit passwords attempts";
                 UISwitch* actSwitch = (UISwitch*)[cell viewWithTag: SWITCH_TAG];
                 [actSwitch setTag: indexPath.section];
                 [actSwitch addTarget: self
                               action: @selector(actSwitchChanged:) 
                     forControlEvents: UIControlEventValueChanged];
                 [actSwitch setOn:limit_password_attempts animated:YES];

И у меня есть еще вопрос: моя программа теперь работает хорошо, но я не понимаю, что изменилось.Я добавил еще несколько методов: cellForType: и cofigureCell:forIndexPath:, но все, что они делали, было сделано практически так же, как и в предыдущей версии cellForRowAtIndexPath:.

Итак ... что изменилось здесь, чтобы заставить его работать правильно?:)

...