четверг, 15 октября 2015 г.

31. UITableView Part 1

В этом уроке рассматривается создание UITableView контроллера из пустого проекта без использования сторибоард - все делается в "коде".
Урок находится по здесь.
Если нельзя создать пустой проект (в новой версии Xcode) удаляем лишние файлы (ViewController.h, ViewController.m).
И создаем новый класс (новый файл) контроллера наследника от UIViewControl. 
Можно наследовать сразу от класса UITableView, но если потребуется добавить простой View в сабьвью, то с этим могут возникнуть проблемы.

Для того, чтобы наш контроллер отобразился на экране в функции класса AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

мы создаем наш контроллер и добавляем его на окно как главный контроллер (roмtviewcontroller):
    TAViewController *controller=[[TAViewController alloc] init];
    self.window.rootViewController=controller;

Все контроллер создан и работает - виден на экране.

Добавим на наш контроллер - таблицу UITableView.

Добавим функцию LoadView - которая вызывается перед загрузкой view и вызываем этот метод для родителя  (для корректной работы).

- (void) loadView{
    [super loadView];
    

}

Определяем frame для новой таблицы. Прямоугольник берем из bounds и загуляем origin он обычно и так 0,0 , но так рекомендуется делать.

    CGRect frame=self.view.bounds;
    frame.origin=CGPointZero;

Создаем таблицу  используя initWithFrame в качестве параметра наш прямоугольник frame и стиль для таблицы :UITableViewStyleGrouped.
    UITableView *tableView=[[UITableView alloc] initWithFrame:frame style:UITableViewStyleGrouped];

Добавляем автоматическое растягивание по длине и высоте

    tableView.autoresizingMask=UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;

Делаем наш класс delegate и datasource этой таблицы

    tableView.delegate=self;
    tableView.dataSource=self;

Для того, чтобы наш класс был делегатом и датасорсом, нужно указать, что он поддерживает протоколы UITableViewDataSource и UITableViewDelegate.

@interface TAViewController () <UITableViewDataSource,UITableViewDelegate>

В протоколе  UITableViewDataSource есть обязательные два метода для реализации:

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

Определяет сколько будет строк в каждой секции

И еще обязательной реализации требует функция 

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

Она возвращает ячейку в каждой строке.

Пока мы их формально создадим:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 2;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    static NSString *Identifier=@"cell";
    UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:Identifier];
    if (!cell) {
        cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:Identifier];
    }
    cell.textLabel.textColor=[UIColor redColor];
    cell.textLabel.text=[NSString stringWithFormat:@"Cell Section:%@",@(indexPath.section)];
    cell.detailTextLabel.textColor=[UIColor greenColor];
    cell.detailTextLabel.text=[NSString stringWithFormat:@"Cell Row:%@",@(indexPath.row)];
    return cell;

}

Конструкция с Identifier рассмотрена в прошлом уроке 30 используется для экономии ресурсов (повторное использование ячеек).

Так как выбран стиль ячейки с дополнительным полем detailTextLabel  туда выведена номер строки в секции и применены выделение цветом.

Добавляем нашу таблицу в subview главной view

    [self.view addSubview:tableView];

Теперь наша таблица отображается на экране эмулятора - 1 секция и 2 строки в ней.

Реализуем еще несколько функций из протокола UITableViewDataSource

Для определения количества секций используется эта функция 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 3;

}

Для определения заголовков Header секций используется эта функция 

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    return [NSString stringWithFormat:@"Section %@",@(section)];
}

Для определения концовок Footer  секций используется эта функция 

- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
    return [NSString stringWithFormat:@"Footer %@",@(section)];

}

Для наполнения контента - данных для таблицы создаются два класса (наследники NSObject):
TAStudent и TAGroup.

Данными занимаемся в методе viewDidLoad - создаем рандомное количество групп студентов и рандомное количество студентов в каждой группе.
После изменения данных, перезагружаем данные в таблицу

[self.tableView reloadData];

Вышеописанные функции, которые выводят конкретные данные выглядят уже так

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

    TAGroup *group=self.groupsArray[section];
    return [ group.students count ];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    static NSString *Identifier=@"cell";
    UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:Identifier];
    if (!cell) {
        cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:Identifier];
    };
    TAGroup *group=self.groupsArray[indexPath.section];
    TAStudent *student=group.students[indexPath.row];
    cell.textLabel.text=[NSString stringWithFormat:@"%@ %@",student.lastName,student.firstName];
    cell.detailTextLabel.text=[NSString stringWithFormat:@"%@",@(student.averageGrade)];

    if (student.averageGrade>=4.0) {
        cell.detailTextLabel.textColor=[UIColor greenColor];
     }
    else if (student.averageGrade>=3.0) {
        cell.detailTextLabel.textColor=[UIColor orangeColor];
    }
    else {
        cell.detailTextLabel.textColor=[UIColor redColor];
    }

    return cell;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return self.groupsArray.count;
}

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    TAGroup *group=self.groupsArray[section];
    return [NSString stringWithFormat:@"%@",group.name];
}

- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
    TAGroup *group=self.groupsArray[section];
    return [NSString stringWithFormat:@"%@ student in %@",@(group.students.count),group.name];
}

Для изменения порядка строк в таблице  реализуем метод, который спрашивает возможно ли передвижение элемента таблицы передаваемого в indexPath

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
    TAGroup *group=self.groupsArray[indexPath.section];
    TAStudent *student=group.students[indexPath.row];
    return student.averageGrade<4;

}

В данном случае мы разрешаем передвижение только у кого оценка меньше 4.

Так же для передвижения строк нужно реализовать следующий метод

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
    TAGroup *sourceGroup=self.groupsArray[sourceIndexPath.section];
    TAStudent* student=sourceGroup.students[sourceIndexPath.row];
    NSMutableArray *tempArray=[NSMutableArray arrayWithArray:sourceGroup.students];

    if (sourceIndexPath.section==destinationIndexPath.section){
        [tempArray exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];
        sourceGroup.students=tempArray;
    }
    else{
    
    [tempArray removeObject:student];
    sourceGroup.students=tempArray;
    
    
    TAGroup *destinationGroup=self.groupsArray[destinationIndexPath.section];
    tempArray=[NSMutableArray arrayWithArray:destinationGroup.students];
    [tempArray insertObject:student atIndex:destinationIndexPath.row];
    destinationGroup.students=tempArray;
    }


}
В этом методе производится перемещение данных в массивах и группах в соответствии с перемещением в таблице представления данных.

Чтобы перевести таблицу в режим редактирования необходимо добавить например в  loadView
    tableView.editing=YES;

Чтобы изменить стиль ячейки - например убрать/добавить кнопку удаления или добавления элемента необходимо реализовать этот метод

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleNone;

}

Исходный текст этого проекта находится здесь.

Продолжение этой темы в следующем уроке - два урока объединенные.
Домашнее задание соответственно тоже в следующем уроке.

Комментариев нет:

Отправить комментарий