Thursday, December 27, 2012

Monday, December 24, 2012

Делегирование, часть 2: UITableView / UITableViewDelegate http://karonator.ru/cources/ios/1556

http://karonator.ru/cources/ios/1556

Делегирование, часть 2: UITableView / UITableViewDelegate

Здравствуйте товарищи.

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

Ближе к делу. Стоящая перед нами задача проста: надо оживить UITableView. Для примера сделаем простую табличку, в которой перечислим выдающихся физиков, математиков и программистов. Нам необходимо будет описать класс-контроллер, который будет отвечать за поведение нашей таблички, а так же заполнять её информацией. Для того, чтобы наш класс мог «подружиться» со стандартным элементом интерфейса UITableView, его нужно будет сделать удовлетворяющим протоколамUITableViewDelegate и UITableViewDataSource.

ПОДГОТОВКА ПРОЕКТА

Для начала создадим пустой проект (Simple View Application), я назвал его XSample — не очень логично, зато названия файлов будут покороче. XCode создал нам 5 файлов:

  • XSampleAppDelegate.h / XSampleAppDelegate.m — класс-делегат нашего приложения, в нём описываются функции, которые будут вызваться если наше приложение закроют, свернут и т.п. В нём ничего трогать не надо.
  • XSampleViewController.h / XSampleViewController.m — это класс отвечает за окошко нашего приложения, точнее за его UIView, к нему мы вернёмся позже.
  • XSampleViewController.xib — файл Interface Builder'а, описывающий наш интерфейс.

Самоконтроль:

Теперь нужно добавить в проект класс, который будет отвечать за нашу таблицу (то есть фактически её делегировать). Сделаем этот класс наследником UIViewController, хотя это совершенно не обязательно (его можно спокойно унаследовать от NSObject), и назовём его XTableController. Итак, добавление класса-контроллера:

Вот, проект мы подготовили, давайте теперь опишем класс-контроллер таблицы: XTableController.

КОНТРОЛЛЕР

Итак, сейчас нам нужно подготовить класс, который будет управлять нашей таблицей.
Изначально файл XTableController.h должен выглядеть как-то так:

  1  2  3  4  5  
  @interface XTableController : UIViewController  {  }     @end

Нам нужно сделать две вещи:

1. Объявить о том, что наш класс поддерживает протоколы UITableViewDelegate и UITableViewDataSource. После того как об этом будет заявлено, нам нужно будет в файле XTableController.m описать соответствующие этим протоколам методы. Об этом чуть позже.

2. Подготовить структуры данных для нашей таблицы. С точки зрения данных, таблица это куча ячеек, которые могут быть разделены на разделы. В нашем случае у нас будет 3 раздела (физики, математики и программисты), и ячейки в разделах.

Вообще говоря, хранить данные вы можете как хотите. В нашем примере будет использоваться NSMutableArray. Между прочим, если переименовать файлы *.h и *.m в *.hpp и *.mm, то вы сможете использовать c++, что даст вам возможность использовать std::map и std::vector.

В свете вышесказанного, заголовочный файл нашего класса-контроллера преобразуется:

  1  2  3  4  5  6  7  8  9  10  11  
  @interface XTableController : UIViewController <UITableViewDelegate, UITableViewDataSource>  {    NSMutableArray * group_1;    NSMutableArray * group_2;    NSMutableArray * group_3;    NSMutableArray * group_names;  }     - (void) InitData;     @end

Теперь перейдём к файлу XTableController.m, в котором нам нужно описать ряд методов.
Итак, для начала инициализация структур с данными:

  1  2  3  4  5  6  7  8  
  - (void) InitData  {    group_names = [[NSMutableArray alloc] initWithObjects: @"Физики", @"Maтематики", @"Программисты", nil];       group_1 = [[NSMutableArray alloc] initWithObjects: @"В. Рентген", @"И. Ньютон", @"М. Склодовская-Кюри", @"H. Тесла", nil];    group_2 = [[NSMutableArray alloc] initWithObjects: @"О. Коши", @"К. Вейерштрасс", @"А. Колмогоров", nil];    group_3 = [[NSMutableArray alloc] initWithObjects: @"Д. Ричи", @"Д. Кнут", @"Б. Гейтс", nil];  }

Теперь нам нужно описать некоторые методы, чтобы наш класс мог удовлетворять протоколам, о которых я писал выше. Начинаем с количества секций в таблице (совет — читайте названия методов, они говорящие):

  1  2  3  4  
  - (NSInteger) numberOfSectionsInTableView: (UITableView*) tableView  {    return [group_names count];  }

Далее говорим, сколько ячеек в каждой секции:

  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  
  - (NSInteger) tableView: (UITableView*) tableView numberOfRowsInSection: (NSInteger) section  {    switch (section)     {      case 0:        return [group_1 count];        break;      case 1:        return [group_2 count];        break;      default:        return [group_3 count];        break;	    }  }

Теперь опишем метод, отвечающий за название каждой секции:

  1  2  3  4  
  - (NSString*) tableView: (UITableView*) tableView titleForHeaderInSection: (NSInteger) section   {      return [group_names objectAtIndex: section];  }

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

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

Следует обратить внимание на связку dequeueReusableCellWithIdentifier / reuseIdentifier — это стандартный способ создания ячеек, позволяющий оптимизировать работу таблицы.

Итак, наш метод:

  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  
  - (UITableViewCell*) tableView: (UITableView*) tableView cellForRowAtIndexPath: (NSIndexPath*) index_path  {    static NSString * CellIdentifier = @"Cell";	    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];       if (cell == nil)     {      // существует несколько предопределённых стилей для ячеек таблицы      // UITableViewCellStyleDefault - самый простой из них      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];    }       switch (index_path.section)     {      case 0:        cell.textLabel.text = [group_1 objectAtIndex: index_path.row];			        break;      case 1:        cell.textLabel.text = [group_2 objectAtIndex: index_path.row];        break;      default:        cell.textLabel.text = [group_3 objectAtIndex: index_path.row];			        break;    }    return cell;  }

На этом описание нашего класса контроллера окончено. Это далеко не все методы, которые можно переопределить, есть много других. Описывая из вы можете добавить в вашу таблицу возможность поиска, удаления ячеек или из сортировки. Нам это пока не нужно. Теперь нужно добавить таблицу на нашу вьюшку (UIView), и связать с контроллером.

ДОБАВЛЕНИЕ ТАБЛИЦЫ

Для того, чтобы добавить таблицу в наше окошко, нужно открыть XSampleViewController.xib и перетащить на нашу UIView элемент UITableView. Вас не должно смущать, что в таблице уже есть секции и текст — это сделано просто для того, чтобы вы знали как примерно она будет выглядеть, если запустить программу то таблица будет пустой. Ну ничего, это не надолго =)
Заодно давайте переключим внешний вид таблицы на grouped.
На всякий случай скриншоты:

Итак у нас есть написанный класс-контроллер (XTableController), и таблица. Нужно их связать. Для этого нам нужно создать объект класса XTableController, и «сказать» нашей таблице, что ею будет управлять этот объект.

НАСТРОЙКА ДЕЛЕГИРОВАНИЯ

Сейчас мы будет работать с классом, отвечающим за нашу основную вьюшку (XSampleViewController). В нём мы свяжем таблицу и контроллер в единое целое.

Дла начала откроем файл XSampleViewController.h и модифицируем его, чтобы он выглядел так:

  1  2  3  4  5  6  7  8  9  10  
  #import <UIKit/UIKit.h>  #import "XTableController.h"     @interface XSampleViewController : UIViewController  {    IBOutlet UITableView * my_table;    XTableController * xcontroller;  }     @end

Мы добавили две строчки. Со второй всё понятно, а вот что такое IBOutlet может быть не вполне ясно. Как вы видите, после IBOutlet идёт обычное объявление указателя на таблицу. Так вот, поставив перед объявлением IBOutlet мы получим возможность связать нашу таблицу в Interface Builder с этим указателем. Фактически, поставленная запись IBOutlet просто говорит XCode, что этот указатель мы определим вручную, связав с каким-то элементом интерфейса. После этого my_table будет указывать на нашу таблицу.

Итак, давайте их таки свяжем. Для этого нужно открыть файл XSampleViewController.xib и кликнуть правой кнопкой мышки по нашей табличке. Далее на плюсик в разделе Reference Outlets, и протянуть линию к File's Owner. XCode предложит вам выбор, выбираем my_table. Теперь my_table указывает на реально существующую таблицу.
Читается это наверное страшновато, на самом деле это очень просто и удобно, посмотрите скриншоты — станет понятнее:

Теперь переменная my_table указывает на реальную таблицу. Нам остался последний шаг — проинициализировать контроллер и указать таблице, кто ею будет управлять. Для этого откроем файл XSampleViewController.m, и внесём изменения в метод ViewDidLoad. Этот метод будет вызван при загрузке нашей вьюшки.
Итак, смотрим:

  1  2  3  4  5  6  7  8  9  10  
  - (void)viewDidLoad  {    xcontroller = [[XTableController alloc] init];    [xcontroller InitData];       [my_table setDelegate: xcontroller];    [my_table setDataSource: xcontroller];       [super viewDidLoad];  }

Вот и всё. Перед тем как любоваться результат, давайте ещё раз вспомним основные шаги:
1. Описали класс для управления таблицей XTableController, удовлетворяющий протоколам UITableViewDelegate и UITableViewDataSource.
2. Добавили таблицу на нашу UIView, через IBOutlet связали её с кодом.
3. Создали объект нашего класса, настроили таблицу, чтобы ею управлял наш объект.

РЕЗУЛЬТАТ

Запускаем приложение, наслаждаемся результатом:

По доброй традиции прикладываю проект и исходный код. В следующей статье будем учиться делать таблицы офигенно красивыми. Успехов вам!

PROJECT & CODE

P.S. Если у вас что-то не получается, падает, зависает, или вам что-то не понятно — пишите вопросы в комментарии, я постараюсь вам помочь.

P.P.S. Если вам помогла эта статья, поставьте лайк, или напишите комментарий — мне будет приятно. Спасибо.

Sunday, December 23, 2012

Примеры по UITableView http://idev.by/tag/uitableview/

http://idev.by/tag/uitableview/

  1. Удобный способ создания/повторного использования ячеек таблицы

    +2
    АВТОР  
    / 10.06.2012 / КОММЕНТАРИИ (17)
    Так выглядит стандартный способ создания/реиспользования ячейки (без custom XIB-интерфейса):
      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {      UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];      if (cell == nil)      cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];      // Add elements to the cell      return cell;  }
    В БЛОГЕ IOS
    ОБСУЖДАЮТ LIMEJELLYYOOORIIIDLEBEDEV И ЕЩЕ ОДИН
  2. Идея и UITableView

    +3
    АВТОР  
    / 21.05.2012 / КОММЕНТАРИИ (8)
    Хочу поделиться с сообществом одной мыслью. Суть в следующем: иногда нужно создать простой UITableView с однотипными ячейками, который будет отображать в себе какую-либо коллекцию. Можно использовать стандартный подход с UITableViewDelegate и UITableViewDataSource. Но всегда хочется чтобы было быстрее и удобнее.
    Исходя из выше сказанного мне захотелось упростить эту процедуру. Я решил заменить вызовы методов UITableViewDataSource на блоки. Например:
      -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    Я заменил на вот такой блок:
      ^(UITableViewCell* cell, NSIndexPath* indexPath, id item){      // код обработки ячейки  }
    В БЛОГЕ IOS
    ОБСУЖДАЮТ ГРЕБУБЛЯLIMEJELLYDLEBEDEV И ЕЩЕ ОДИН
  3. Анонс TableKit — обертка над UITableView

    0
    АВТОР  
    / 29.04.2012 / 1 КОММЕНТАРИЙ
    TableKit — небольшая библиотечка для работы с таблицами под iOS. По сравнению с традиционным подходом требует гораздо меньше кода и намного удобнее.
    Ячейки и секции таблицы организованы иерархически, что очень логично и читабельно.
    Для создания примера таблицы достаточно несколько строчек кода:
      TKStaticCell* staticCell = [TKStaticCell cellWithText:@"Hello World!"];  TKTextFieldCell* textCell = [TKTextFieldCell cellWithText:@"Editing Text"];  TKSection* section = [TKSection sectionWithCells:staticCell, textCell, nil];  TKTableViewController* tvc = [[TKTableViewController alloc] initWithStyle:UITableViewStylePlain];  tvc.sections = [NSArray arrayWithObjects: section, nil];  [self.navigationController pushViewController:tvc animated:YES];
    В БЛОГЕ IOS
    ОБСУЖДАЮТ LIMEJELLY
  4. Взгляд на UITableView изнутри

    0
    АВТОР  
    / 02.01.2012 / КОММЕНТАРИИ (2)
    Продолжаю тему UITableView. В предыдущих статьях вы узнали как работать с UITableView, наполнять данными, создавать кастомные ячейки и какую ошибку не следует допускать. Одна из замечательных возможностей UITableView — это повторное использование ячеек. В этой статье я покажу одну из реализаций такого поведения. В качестве примера мы сделаем «кастомный» UITableView.
    Суть метода — есть два множества ячеек. Первое содержит в себе ячейки, которые в данный момент находятся на экране. Второе множество содержит в себе ячейки которых нет на экране и которые могут быть использованы снова. При прокрутке таблицы мы каждый раз пересчитываем индексы ячеек, которые должны быть на экране. Если нужно удаляем ячейки, которые должны «спрятаться» и показываем новые (доставая их из второго множества).
    В БЛОГЕ IOS
  5. Создаем ячейки UITableViewCell в Interface Builder, Скринкаст!

    +1
    АВТОР  
    / 19.12.2011 / КОММЕНТАРИИ (15)
    Ну вот я снял свой первый скринкаст! Предлагаю его на всеобщее обозрение. Приму все замечания и предложения. Хотелось, чтобы вы ответили после просмотра на эти вопросы:
    • Нужна ли музыка в скринкасте?
    • Нужно ли более детально объяснение?
    • Стоит ли вместо голоса сделать субтитры?
    Исходники можно загрузить тут. Приятного просмотра!
    В БЛОГЕ IOS
    ОБСУЖДАЮТ DILIMEJELLYMASTERCORP И ЕЩЕ 7
  6. Важно о UITableView

    +1
    АВТОР  
    / 07.12.2011 / КОММЕНТАРИИ (16)
    Вы еще его увидите
    Вы еще его увидите
    В последнее время все чаще начал замечать ошибку у iPhone-разработчиков (неопытных и даже у тех, кто считает себя опытными) связанную с использованием ячеек в UITableView. Разработчики не понимают, что в UITableView ячейки не создаются каждый раз, а используются уже созданные!
    Начнем по-порядку. Всем нам известен метод tableView:cellForRowAtIndexPath:. Привожу наиболее распространенный код (цифрами отмечены специальные места, о которых речь пойдет ниже):
      -(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {      // 1      static NSString* cellID = @"cellID";      UITableViewCell* cell;      cell = [tableView dequeueReusableCellWithIdentifier:cellID];        if ( !cell ) {          cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];          // 2      }        // 3      return cell;  }
    Мы прекрасно знаем что должен возвращать этот метод. Он должен возвращать ячейку, которая вот-вот появиться на экране.
    В БЛОГЕ IOS
  7. Наполняем UITableView данными из Интернета. Пишем RSS-читалку

    0
    АВТОР  
    / 24.10.2011 / 1 КОММЕНТАРИЙ
    Рассмотрим пример наполнения UITableView данными из Интернета. Данная задача встречается очень часто. Будем рассматривать в контексте написания RSS-читалки. Для того, чтобы полностью понять материал вам нужны знания о UITableView и парсинге XML. Эти обе темы затрагивались на этом сайте:
    В БЛОГЕ IOS
    ТЕГИ 
  8. Все о UITableview: часть 3

    0
    АВТОР  
    / 19.08.2011 / КОММЕНТАРИИ (3)
    Как мы могли убедиться в предыдущих двух статьях, разработка приложений с таблицами в iOS ведется легко и быстро. В третьей статье мы рассмотрим как создать приложение, которое будет иметь уникальный дизайн и выделяться на обшем фоне.
    С помощью стандартного класса UITableViewCell мы можем вывести на экран текст, детальный текст и одну картинку. И расположение этих элементов внутри ячейки может быть не самым подходящим для нашего приложения (из первой статьи мы помним, что задавали стиль отображения при инициализации с помощью метода initWithStyle). Создадим ячейку, которая будет удовлетворять нашим требованиям: три текстовых поля, картинка и кнопка.
    В БЛОГЕ IOS
  9. Все о UITableview: часть 2

    0
    АВТОР  
    / 12.08.2011 / КОММЕНТАРИИ (4)
    Во второй части статьи изучим методы по добавлению и удалению новых элементов в таблице.
    Воспользуемся исходником из первой части статьи. Для простоты предварительно удалим из него все записи касающиеся массива items2, делегатов titleForHeaderInSectionи sectionIndexTitlesForTableView. В navigation bar добавим новую кнопку, нажав на которую мы будем добавлять новую запись в таблицу. Для создания кнопки воспользуемся следующим кодом, который поместим в метод
      - (void)viewDidLoad  {      [super viewDidLoad];        UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNew)];      self.navigationItem.leftBarButtonItem = addButton;      [addButton release];        items = [[NSMutableArray alloc] init];      [items addObject:@"Яблоки"];      [items addObject:@"Апельсины"];      [items addObject:@"Груши"];  }
    В БЛОГЕ IOS
  10. Все о UITableView. Часть 1

    0
    АВТОР  
    / 10.08.2011 / КОММЕНТАРИИ (16)
    Для пользователя очень важно, чтобы данные были представлены в удобном виде. В этой статье мы рассмотрим как создается табличное представление данных в iOS. Во многих ситуациях оно просто незаменимо. Запустите XCode и выберите пункт «Create a new XCode Project». В появившемся меню выберите шаблон «Navigation-based Application». В следующем меню необходимо указать название проекта (Product Name). В данном примере я использую «Table». Далее укажите место куда будет сохранен проект.
    На данном этапе мы получили простое приложение, которое выводит на девайс пустую таблицу. В проекте у нас есть файлы RootViewController.h и RootViewController.m — это заголовочный и имплеметационный файлы для класса, который отвечает за вывод таблицы на экран девайса и обработку событий. Также присутствует файл RootViewController.xib, который отвечает за внешний вид. Открыв его можно увидеть, что вся форма состоит из одного элемента интерфейса «Table view».
    В БЛОГЕ IOS
    ОБСУЖДАЮТ CRAZY_BLUДИМАLIME И ЕЩЕ 2