Pull to refresh

Альтернатива UISplitViewController (отображение MasterView в книжной ориентации устройства)

Reading time 5 min
Views 1.3K
Как было замечено в статье “Всплывающие окна. Работа с UIPopoverController” в iPhone SDK 3.2 были добавлены новые элементы интерфейса: UIPopoverController и UISplitViewController. О первом из них уже довольно подробно рассказано на хабре. Я же хочу поговорить о UISplitViewController, верней о некой альтернативе.

“Зачем же нужна эта альтернатива?”, — спросите Вы, — “какова причина?”. Все дело в особенности поведения SplitView, вот выдержка из SDK: “Both view controllers are displayed in landscape orientations but only the detail view controller is displayed in portrait orientations”. Т.е. при книжной ориентации правая часть (MasterView) попросту прячется(см. рис. 1)


Рисунок 1 — SplitView в альбомной (а) и книжной (б) ориентации

Посмотрев на Основные настройки iPad мы увидим совсем другую картину: и в книжной и в альбомной ориентации левая часть (MasterView) отображается одинаково (не прячется)


Рисунок 2 — Основные настройки iPad

Ну что ж, построим свой SplitView, где бы левая часть не пряталась с блекджеком и шлюхами, хотя к черту SplitView и блэкджек.

Начнем с создания нового проекта в Xcode(View-based Application). Я дал ему название AlternativeSplit (см. Рис 3).


Рисунок 3- Создание нового проекта

Далее добавим в проект два новых класса MasterViewController (subclass of UITableViewController) и DetailViewController (subclass of UIViewController), выбрав в меню File->New file… ->Cocoa Touch Class-> UIViewController subclass.

Откроем AlternativeSplitViewController.xib в InterfaceBuilder и «нарисуем примерно такую картину»:


Рисунок 4 — Редактирование AlternativeSplitViewController.xib

Настроим Autosizing так, что бы наш view не «поплыл» при переключении с одной ориентации на другую. Для левой части Master (NavigationBar и TableView) укажем такие же параметры как и на рисунке 5.а, а для правой Detail (NavigationBar и View) —как на рис. 5.б


Рисунок 5 — параметры Autosizing

Добавим в класс AlternativeSplitViewControlle.h новую IBOutlet переменную, отредактировав файл
AlternativeSplitViewController.h следующим образом

  1. //
  2. // AlternativeSplitViewController.h
  3. // AlternativeSplit
  4. //
  5. #import <UIKit/UIKit.h>
  6. @class MasterViewController;
  7. @interface AlternativeSplitViewController : UIViewController {
  8.   IBOutlet MasterViewController* masterViewController;
  9. }
  10. @end
* This source code was highlighted with Source Code Highlighter.


Класс MasterViewController будет отвечать у нас за таблицу, содержащую пункты меню. Перепишем его следующим образом (если кратко: ниже в коде мы заполняем таблицу и при выборе пользователем ячейки таблицы (didSelectRowAtIndexPath) посылаем сообщение DetailView):

  1. //
  2. // MasterViewController.h
  3. // AlternativeSplit
  4. //
  5. #import <UIKit/UIKit.h>
  6. @class DetailViewController;
  7.  
  8. @interface MasterViewController : UITableViewController {
  9.   IBOutlet DetailViewController* detailViewController;
  10. }
  11.  
  12. @end
* This source code was highlighted with Source Code Highlighter.


  1.  
  2. //
  3. // MasterViewController.m
  4. // AlternativeSplit
  5. //
  6. #import "MasterViewController.h"
  7. #import "DetailViewController.h"
  8.  
  9. @implementation MasterViewController
  10.  
  11. #pragma mark -
  12. #pragma mark View lifecycle
  13.  
  14. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  15.   // Override to allow orientations other than the default portrait orientation.
  16.   return YES;
  17. }
  18. #pragma mark -
  19. #pragma mark Table view data source
  20. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  21.   // Return the number of sections.
  22.   return 1;
  23. }
  24. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  25.   // Return the number of rows in the section.
  26.   return 5;
  27. }
  28. // Customize the appearance of table view cells.
  29. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  30.   
  31.   static NSString *CellIdentifier = @"Cell";
  32.   
  33.   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  34.   if (cell == nil) {
  35.     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
  36.   }
  37.   // Configure the cell...
  38.   cell.textLabel.text= [NSString stringWithFormat:@"Row %i",indexPath.row];
  39.   return cell;
  40. }
  41. #pragma mark -
  42. #pragma mark Table view delegate
  43.  
  44. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  45.   
  46.   [detailViewController setNewText:[NSString stringWithFormat:@"Row %i", indexPath.row]];
  47. }
  48.  
  49.  
  50. #pragma mark -
  51. #pragma mark Memory management
  52.  
  53. - (void)didReceiveMemoryWarning {
  54.   // Releases the view if it doesn't have a superview.
  55.   [super didReceiveMemoryWarning];
  56.   
  57.   // Relinquish ownership any cached data, images, etc that aren't in use.
  58. }
  59.  
  60. - (void)dealloc {
  61.   [super dealloc];
  62. }
  63. @end
* This source code was highlighted with Source Code Highlighter.


DetailViewController будет отвечаеть у нас за правую часть. Отредактируем класс DetailViewController (добавим новую IBOutlet переменную UILabel *lbl и новый метод setNewText, который будет изменять текст нашей lbl )

  1. //
  2. // DetailViewController.h
  3. // AlternativeSplit
  4. //
  5. #import <UIKit/UIKit.h>
  6.  
  7. @interface DetailViewController : UIViewController {
  8.   IBOutlet UILabel* lbl;
  9. }
  10. -(void) setNewText:(NSString*) text;
  11. @end
* This source code was highlighted with Source Code Highlighter.


  1. //
  2. // DetailViewController.m
  3. // AlternativeSplit
  4. //
  5.  
  6. #import "DetailViewController.h"
  7. @implementation DetailViewController
  8. -(void) setNewText:(NSString*) text{
  9.   lbl.text=text;
  10. }
  11. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  12.   // Overriden to allow any orientation.
  13.   return YES;
  14. }
  15. - (void)didReceiveMemoryWarning {
  16.   // Releases the view if it doesn't have a superview.
  17.   [super didReceiveMemoryWarning];
  18.   
  19.   // Release any cached data, images, etc that aren't in use.
  20. }
  21. - (void)viewDidUnload {
  22.   [super viewDidUnload];
  23.   // Release any retained subviews of the main view.
  24.   // e.g. self.myOutlet = nil;
  25. }
  26. - (void)dealloc {
  27.   [super dealloc];
  28. }
  29. @end
* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx">Source Code Highlighter.


Все что осталось нам сделать — это связать в interfaceBuildere наши IBOutlet переменные (см рис. 6). И дело в шляпе.


Рисунок 6 — Связывание IBOutlet переменных

Результат:


Рисунок 7 — Альтернативный SplitView

Исходный код можно скачать здесь или здесь.

Спасибо за внимание.
P.S. Есть некое продолжение этой статьи: «Легким движением руки брюки UITabBar превращается, брюки UITabBar превращается… в элегантные шорты UISplitView» (эдакий Костыль при портировании iPhone приложения под iPad). Стоит ли писать?
Tags:
Hubs:
+8
Comments 3
Comments Comments 3

Articles