Class 11
iOS 應⽤用軟體設計
內容⼤大綱
•   UISplitViewController
    •   QV116:UISplitViewController 基本原理
    •   QV118: UISplitViewController 結合 Navigation, TableView及資
        料顯⽰示等綜合應⽤用
    •   Samples:MultipleDetailViews
    •   Samples:Websites
•   UIPopoverController
    •   QV117:UIPopoverController 基本原理
    •   Samples:Popovers

    •   QV120:UIPopoverController使⽤用 Protocol 之 delegate

•   UIPageViewController
    •   QV113:UIPageViewController 基本原理 (多⾴頁⾯面翻書程式)
UISplitViewController
UIPopoverController
UIPageViewController
for iPad
UISplitViewController
Split View Controllers (iPad)
範例:

            QV116
UISplitViewController 基本原理
Project QV116


 UISplitViewController
 於 iPad 上使⽤用
兩組畫⾯面
                          ViewController



       AppDelegate.h

#import <UIKit/UIKit.h>

@class ViewController;
@class DetailViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) ViewController *viewController;
@property (strong, nonatomic) DetailViewController *detailController;
@property (strong, nonatomic) UISplitViewController *splitViewController;

@end

                                   另建⼀一個 UISplitViewController
AppDelegate.m
#import "ViewController.h"
#import "DetailViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.
    self.viewController = [[ViewController alloc]
                        initWithNibName:@"ViewController" bundle:nil];
    self.detailController = [[DetailViewController alloc]
                          initWithNibName:@"DetailViewController" bundle:nil];

    splitViewController = [[UISplitViewController alloc] init];
    splitViewController.viewControllers = [NSArray arrayWithObjects:
                           self.viewController, self.detailController, nil];

    [self.window addSubview:splitViewController.view];

    //self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];
    return YES;
}                                         ⽤用陣列指定內容並加⼊入 window
直向時只看到⼀一個畫⾯面
               橫向時會顯⽰示分割畫⾯面
問題討論



其實什麼內容都沒有,然後呢?
範例:
          QV118

  UISplitViewController 結合
     Navigation, TableView
   及資料顯⽰示等綜合應⽤用
Project QV118

由新增專案 Master-Detail
App 開始
(使⽤用 Storyboard 及 iPad)
增加 Master View 的清單
增加 Detail View 的連結 
執⾏行,測試結果
(注意:包含直向及橫向)
檢查 Storyboard
SplitViewController 指定了兩個畫⾯面
準備以程式進⾏行    MasterViewController
           內部的 Table View 需指定
MasterViewController.h




#import <UIKit/UIKit.h>

@class DetailViewController;

@interface MasterViewController : UITableViewController
{
    NSArray *bookArray;
}
                                         資料陣列,給           TableView ⽤用

@property (strong, nonatomic) DetailViewController *detailViewController;

@end
MasterViewController.m
- (void)viewDidLoad
{
    [super viewDidLoad];

   // 定義要呈現的項⺫⽬目清單
   bookArray = [[NSArray alloc] initWithObjects:@"書劍恩仇錄", @"碧⾎血劍",
@"射鵰英雄傳", @"雪⼭山飛狐", @"神鵰俠侶", @"飛狐外傳", @"⽩白⾺馬嘯⻄西⾵風", @"鴛鴦⼑刀",
@"倚天屠⻯⿓龍記", @"連城訣", @"天⻯⿓龍⼋八部", @"俠客⾏行", @"笑傲江湖", @"⿅鹿⿍鼎記", nil];

    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self
action:@selector(insertNewObject:)];
    self.navigationItem.rightBarButtonItem = addButton;    要顯⽰示的清單
    self.detailViewController = (DetailViewController *)
[[self.splitViewController.viewControllers lastObject] topViewController];

    // 初始即選擇到某區某列 (注意:不會觸發 UITableViewDelegate 的 method)
    [self.tableView selectRowAtIndexPath:
                             [NSIndexPath indexPathForRow:0 inSection:0]
                    animated:NO
                    scrollPosition:UITableViewScrollPositionMiddle];
}
MasterViewController.m



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
    //return _objects.count;
    return [bookArray count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:cellIdentifier];

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

    cell.textLabel.text = [bookArray objectAtIndex:indexPath.row];

    return cell;
}
⼀一些畫⾯面顯⽰示⽂文字,需注意會在何處...
#pragma mark - Split view

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:
(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)popoverController
{
    barButtonItem.title = NSLocalizedString(@"顯⽰示作品清單", @"Master");
    [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
    self.masterPopoverController = popoverController;
}
MasterViewController.m
- (void)viewDidLoad
{
    [super viewDidLoad];

   // 定義要呈現的項⺫⽬目清單
   bookArray = [[NSArray alloc] initWithObjects:@"書劍恩仇錄", @"碧⾎血劍",
@"射鵰英雄傳", @"雪⼭山飛狐", @"神鵰俠侶", @"飛狐外傳", @"⽩白⾺馬嘯⻄西⾵風", @"鴛鴦⼑刀",
@"倚天屠⻯⿓龍記", @"連城訣", @"天⻯⿓龍⼋八部", @"俠客⾏行", @"笑傲江湖", @"⿅鹿⿍鼎記", nil];

    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self
action:@selector(insertNewObject:)];
    self.navigationItem.rightBarButtonItem = addButton;

    self.detailViewController = (DetailViewController *)
[[self.splitViewController.viewControllers lastObject]     detail 的內容
topViewController];

    // 初始即選擇到某區某列 (注意:不會觸發 UITableViewDelegate 的 method)
    [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0
inSection:0] animated:NO
scrollPosition:UITableViewScrollPositionMiddle];

    self.detailViewController.detailItem = @"陳家洛、霍⻘青桐、⾹香⾹香公主";
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
    //NSDate *object = [_objects objectAtIndex:indexPath.row];
    //self.detailViewController.detailItem = object;

! switch (indexPath.row)
    {
! !   case 0:
! !   ! self.detailViewController.detailItem   = @"陳家洛,霍⻘青桐,⾹香⾹香公主";
! !   ! break;
! !   case 1:
! !   ! self.detailViewController.detailItem   = @"袁崇煥,⾦金蛇郎君";
! !   ! break;
! !   case 2:
! !   ! self.detailViewController.detailItem   = @"郭靖,⻩黄蓉,⿈黃藥師,歐陽鋒";
! !   ! break;
! !   case 3:
! !   ! self.detailViewController.detailItem   = @"胡斐";
! !   ! break;
! !
           *** 省略部分程式 ***

! !   default:
! !   ! break;
! }
}
執⾏行測試...
問題討論


往前邁進⼀一⼤大步!
但道路還很遠......
範例觀摩:
MultipleDetailViews
範例觀摩:WebView




    Source: (書附範例) iPad 應⽤用開發實戰 (李晨)
for iPad
UIPopoverController
Project QV117



 UIPopoverController
內容畫⾯面置於⼀一個
ViewController 內
ViewController.h




#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIPopoverControllerDelegate>
{
    UIPopoverController *popController;
}

- (IBAction) showPopover:(id)sender;                     使⽤用協定
@end
#import "ViewController.h"
#import "PopoverContentViewController.h"          ViewController.m
@implementation ViewController

- (IBAction) showPopover:(id)sender
{
    PopoverContentViewController *content =
                         [[PopoverContentViewController alloc] init];
!
    // 取得按鈕
    UIButton *tappedButton = (UIButton *)sender;             設置內容
    // 設置 popover
    popController = [[UIPopoverController alloc]
                      initWithContentViewController:content];

    // 設定 popover 內容尺⼨寸,若空間不夠放,會⾃自動縮⼩小
!   popController.popoverContentSize = CGSizeMake(256, 256);    指定位置
!    popController.delegate = self;

    [popController presentPopoverFromRect:tappedButton.frame
                                   inView:self.view
    彈出顯⽰示        permittedArrowDirections:UIPopoverArrowDirectionAny
                                 animated:YES];
}
補充說明

如何決定彈出⽅方框的位置,以及箭頭的
⽅方向?
彈出⽅方框內為獨⽴立的 UIViewController,
此內部若有事件,該如何做?
( 有難度)
範例觀摩:Popovers
範例:
           QV120

      UIPopoverController
使⽤用 Protocol 之 delegate 程式寫法
Project QV120

 延伸 QV117
 UIPopoverController
 delegate / protocol 的
 程式寫法
彈出之內容畫⾯面
(2)設定遵循協定
                                    (4) 開啟彈出畫⾯面
                   主要畫⾯面
 (3)實作代理⽅方法
                ViewController



                  彈出控制器
              UIPopoverController


                                        (5) 執⾏行傳回資料
(1)在此定義出協定
                彈出之內容畫⾯面                (呼叫代理⽅方法)
          PopoverContentViewCotroller
PopoverContentViewController.h



#import <UIKit/UIKit.h>

@protocol DismissPopoverDelegate <NSObject>            定義出協定
     - (void) dismissWithData:(NSString *)data;
@end
                                                                1
@interface PopoverContentViewController : UIViewController
{
    __unsafe_unretained id <DismissPopoverDelegate> delegate;
}
@property (nonatomic, assign) __unsafe_unretained
id<DismissPopoverDelegate> delegate;

- (IBAction) sendBack:(id)sender;
- (IBAction) sendBack2:(id)sender;                 定義出協定
- (IBAction) sendBack3:(id)sender;

@end
ViewController.h




#import <UIKit/UIKit.h>
#import "PopoverContentViewController.h"

@interface ViewController : UIViewController
<UIPopoverControllerDelegate, DismissPopoverDelegate>
{
    UIPopoverController *popController;
                                                            2
    IBOutlet UILabel *display;
}                                                          使⽤用協定
- (IBAction) showPopover:(id)sender;

@end
ViewController.m




- (void) dismissWithData:(NSString *)data
{
    display.text = [NSString stringWithFormat:@"收到資料 %@", data];

    [popController dismissPopoverAnimated:YES];
}



                                           3
                                                  實作協定
#import "ViewController.h"
#import "PopoverContentViewController.h"
                                                   ViewController.m
@implementation ViewController
                                     4
- (IBAction) showPopover:(id)sender
{
    PopoverContentViewController *content =
[[PopoverContentViewController alloc] init];
    content.delegate = self;                           在此指定
                                                     "內容畫⾯面物件"
    // 取得按鈕
    UIButton *tappedButton = (UIButton *)sender;       的代理⼈人

    // 設置 popover
    popController = [[UIPopoverController alloc]
initWithContentViewController:content];

    // 設定 popover 內容尺⼨寸,若空間不夠放,會⾃自動縮⼩小
    //popController.popoverContentSize = CGSizeMake(256, 256);
    popController.delegate = self;

    [popController presentPopoverFromRect:tappedButton.frame
                                   inView:self.view
                 permittedArrowDirections:UIPopoverArrowDirectionAny
                                 animated:YES];
}
PopoverContentViewController.m


#import "PopoverContentViewController.h"


@implementation PopoverContentViewController
@synthesize delegate;

- (IBAction) sendBack:(id)sender
{                                               5
    [self.delegate dismissWithData:@"1"];
}
                                                 透過代理⼈人
- (IBAction) sendBack2:(id)sender
{                                                 傳遞資料
    [self.delegate dismissWithData:@"2"];
}

- (IBAction) sendBack3:(id)sender
{
    [self.delegate dismissWithData:@"3"];
}
UIPageViewController
Delegate method
•   UIPageViewControllerDelegate




•   UIPageViewControllerDataSource
範例:
         QV113

UIPageViewController 基本原理
Project QV113


 UIPageViewController
 多個⾴頁⾯面的翻書程式
新增每⾴頁內容的畫⾯面
         ContentViewController




ContentViewController.h


#import <UIKit/UIKit.h>
                                                        ⾴頁⾯面內顯⽰示
@interface ContentViewController : UIViewController
{                                                        WebView
}
@property (strong, nonatomic) IBOutlet UIWebView *webView;
@property (strong, nonatomic) id dataObject;

@end
ContentViewController.xib




加⼊入 WebView 以顯⽰示資料
ContentViewController.m

                                               於每次翻⾴頁時,
                                              將 dataObject 內容
                                               指定到 WebView
@implementation ContentViewController
@synthesize webView, dataObject;


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [webView loadHTMLString:dataObject baseURL:[NSURL URLWithString:@""]];
}




                                        寫於 ContentViewController.m
                                          的 viewDidLoad: 也可以
ViewController.h
                                                  Data Model



#import <UIKit/UIKit.h>
#import "ContentViewController.h"

@interface ViewController : UIViewController
<UIPageViewControllerDataSource>
{
    UIPageViewController *pageController;
    NSArray *pageContent;
}
@property (strong, nonatomic) UIPageViewController *pageController;
@property (strong, nonatomic) NSArray *pageContent;

@end
ViewController.m
- (void) createContentPages
{

    NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
    for (int i=1; i<11; i++)
    {
        NSString *contentString = [[NSString alloc]
                                   initWithFormat:
@"<html><head></head><body><h1>Chapter %d</h1><p>This is the page
%d of content displayed using UIPageViewController in iOS 5.</
p></body></html>", i, i];
        [pageStrings addObject:contentString];
    }

    pageContent = [[NSArray alloc] initWithArray:pageStrings];
}


- (void)viewDidLoad
{                                             將 1~10 ⾴頁內容
    [super viewDidLoad];
    [self createContentPages];                儲存於陣列內
    ****** 省略部分程式 ******
}
建⽴立兩個⽅方法,供代理                                      ViewController.m
    程式於切換⾴頁⾯面時呼叫



- (ContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
    // Return the data view controller for the given index.
    if (([self.pageContent count] == 0) ||
        (index >= [self.pageContent count]))
    {                                            指定某⼀一⾴頁,傳回建⽴立好的
        return nil;
    }                                               ContentViewController
    // Create a new view controller and pass suitable data.
    ContentViewController *dataViewController = [[ContentViewController alloc]
                         initWithNibName:@"contentViewController" bundle:nil];
    dataViewController.dataObject = [self.pageContent objectAtIndex:index];
    return dataViewController;
}



- (NSUInteger)indexOfViewController:(ContentViewController *)viewController
{
    return [self.pageContent indexOfObject:viewController.dataObject];
}
ViewController.m
    UIPageViewController 的代理⽅方法
(viewControllerBeforeViewController)


- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerBeforeViewController:
(UIViewController *)viewController
{
    NSUInteger index = [self indexOfViewController:
                        (ContentViewController *)viewController];
    if ((index == 0) || (index == NSNotFound))
    {
        return nil;
    }

    index--;
    return [self viewControllerAtIndex:index];
}
ViewController.m
    UIPageViewController 的代理⽅方法
(viewControllerAfterViewController)


- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:
(UIViewController *)viewController
{
    NSUInteger index = [self indexOfViewController:
                        (ContentViewController *)viewController];
    if (index == NSNotFound)
    {
        return nil;
    }

     index++;
     if (index == [self.pageContent count])
     {
         return nil;
     }
     return [self viewControllerAtIndex:index];
}
- (void)viewDidLoad
                                                           ViewController.m
{
    [super viewDidLoad];
    [self createContentPages];

    NSDictionary *options =
    [NSDictionary dictionaryWithObject:
    [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin]
                         forKey:UIPageViewControllerOptionSpineLocationKey];

    self.pageController = [[UIPageViewController alloc]
         initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
         navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
         options: options];

    pageController.dataSource = self;
    [[pageController view] setFrame:[[self view] bounds]];

    ContentViewController *initialViewController =
    [self viewControllerAtIndex:0];
    NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];

    [pageController setViewControllers:viewControllers
                    direction:UIPageViewControllerNavigationDirectionForward
                    animated:NO
                    completion:nil];

    [self addChildViewController:pageController];
    [[self view] addSubview:[pageController view]];
    [pageController didMoveToParentViewController:self];
}
問題討論


An Example iOS5 iPhone
UIPageViewController Application
(Source: http://www.techotopia.com/index.php/
An_Example_iOS_5_iPhone_UIPageViewController_Application)
............

I os 11

  • 1.
  • 2.
    內容⼤大綱 • UISplitViewController • QV116:UISplitViewController 基本原理 • QV118: UISplitViewController 結合 Navigation, TableView及資 料顯⽰示等綜合應⽤用 • Samples:MultipleDetailViews • Samples:Websites • UIPopoverController • QV117:UIPopoverController 基本原理 • Samples:Popovers • QV120:UIPopoverController使⽤用 Protocol 之 delegate • UIPageViewController • QV113:UIPageViewController 基本原理 (多⾴頁⾯面翻書程式)
  • 3.
  • 4.
  • 5.
  • 6.
    範例: QV116 UISplitViewController 基本原理
  • 7.
  • 8.
    兩組畫⾯面 ViewController AppDelegate.h #import <UIKit/UIKit.h> @class ViewController; @class DetailViewController; @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) ViewController *viewController; @property (strong, nonatomic) DetailViewController *detailController; @property (strong, nonatomic) UISplitViewController *splitViewController; @end 另建⼀一個 UISplitViewController
  • 9.
    AppDelegate.m #import "ViewController.h" #import "DetailViewController.h" @implementationAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.detailController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil]; splitViewController = [[UISplitViewController alloc] init]; splitViewController.viewControllers = [NSArray arrayWithObjects: self.viewController, self.detailController, nil]; [self.window addSubview:splitViewController.view]; //self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } ⽤用陣列指定內容並加⼊入 window
  • 10.
    直向時只看到⼀一個畫⾯面 橫向時會顯⽰示分割畫⾯面
  • 11.
  • 12.
    範例: QV118 UISplitViewController 結合 Navigation, TableView 及資料顯⽰示等綜合應⽤用
  • 13.
    Project QV118 由新增專案 Master-Detail App開始 (使⽤用 Storyboard 及 iPad) 增加 Master View 的清單 增加 Detail View 的連結 
  • 15.
  • 16.
  • 17.
  • 18.
    準備以程式進⾏行 MasterViewController 內部的 Table View 需指定
  • 19.
    MasterViewController.h #import <UIKit/UIKit.h> @class DetailViewController; @interfaceMasterViewController : UITableViewController { NSArray *bookArray; } 資料陣列,給 TableView ⽤用 @property (strong, nonatomic) DetailViewController *detailViewController; @end
  • 20.
    MasterViewController.m - (void)viewDidLoad { [super viewDidLoad]; // 定義要呈現的項⺫⽬目清單 bookArray = [[NSArray alloc] initWithObjects:@"書劍恩仇錄", @"碧⾎血劍", @"射鵰英雄傳", @"雪⼭山飛狐", @"神鵰俠侶", @"飛狐外傳", @"⽩白⾺馬嘯⻄西⾵風", @"鴛鴦⼑刀", @"倚天屠⻯⿓龍記", @"連城訣", @"天⻯⿓龍⼋八部", @"俠客⾏行", @"笑傲江湖", @"⿅鹿⿍鼎記", nil]; self.navigationItem.leftBarButtonItem = self.editButtonItem; UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; self.navigationItem.rightBarButtonItem = addButton; 要顯⽰示的清單 self.detailViewController = (DetailViewController *) [[self.splitViewController.viewControllers lastObject] topViewController]; // 初始即選擇到某區某列 (注意:不會觸發 UITableViewDelegate 的 method) [self.tableView selectRowAtIndexPath: [NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionMiddle]; }
  • 21.
    MasterViewController.m - (NSInteger)tableView:(UITableView *)tableViewnumberOfRowsInSection: (NSInteger)section { //return _objects.count; return [bookArray count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath { static NSString *cellIdentifier = @"CellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if(cell==nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; } cell.textLabel.text = [bookArray objectAtIndex:indexPath.row]; return cell; }
  • 22.
    ⼀一些畫⾯面顯⽰示⽂文字,需注意會在何處... #pragma mark -Split view - (void)splitViewController:(UISplitViewController *)splitController willHideViewController: (UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController { barButtonItem.title = NSLocalizedString(@"顯⽰示作品清單", @"Master"); [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES]; self.masterPopoverController = popoverController; }
  • 23.
    MasterViewController.m - (void)viewDidLoad { [super viewDidLoad]; // 定義要呈現的項⺫⽬目清單 bookArray = [[NSArray alloc] initWithObjects:@"書劍恩仇錄", @"碧⾎血劍", @"射鵰英雄傳", @"雪⼭山飛狐", @"神鵰俠侶", @"飛狐外傳", @"⽩白⾺馬嘯⻄西⾵風", @"鴛鴦⼑刀", @"倚天屠⻯⿓龍記", @"連城訣", @"天⻯⿓龍⼋八部", @"俠客⾏行", @"笑傲江湖", @"⿅鹿⿍鼎記", nil]; self.navigationItem.leftBarButtonItem = self.editButtonItem; UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; self.navigationItem.rightBarButtonItem = addButton; self.detailViewController = (DetailViewController *) [[self.splitViewController.viewControllers lastObject] detail 的內容 topViewController]; // 初始即選擇到某區某列 (注意:不會觸發 UITableViewDelegate 的 method) [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionMiddle]; self.detailViewController.detailItem = @"陳家洛、霍⻘青桐、⾹香⾹香公主"; }
  • 24.
    - (void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath: (NSIndexPath *)indexPath { //NSDate *object = [_objects objectAtIndex:indexPath.row]; //self.detailViewController.detailItem = object; ! switch (indexPath.row) { ! ! case 0: ! ! ! self.detailViewController.detailItem = @"陳家洛,霍⻘青桐,⾹香⾹香公主"; ! ! ! break; ! ! case 1: ! ! ! self.detailViewController.detailItem = @"袁崇煥,⾦金蛇郎君"; ! ! ! break; ! ! case 2: ! ! ! self.detailViewController.detailItem = @"郭靖,⻩黄蓉,⿈黃藥師,歐陽鋒"; ! ! ! break; ! ! case 3: ! ! ! self.detailViewController.detailItem = @"胡斐"; ! ! ! break; ! ! *** 省略部分程式 *** ! ! default: ! ! ! break; ! } }
  • 25.
  • 26.
  • 27.
  • 28.
    範例觀摩:WebView Source: (書附範例) iPad 應⽤用開發實戰 (李晨)
  • 29.
  • 30.
  • 31.
  • 32.
    ViewController.h #import <UIKit/UIKit.h> @interface ViewController: UIViewController <UIPopoverControllerDelegate> { UIPopoverController *popController; } - (IBAction) showPopover:(id)sender; 使⽤用協定 @end
  • 33.
    #import "ViewController.h" #import "PopoverContentViewController.h" ViewController.m @implementation ViewController - (IBAction) showPopover:(id)sender { PopoverContentViewController *content = [[PopoverContentViewController alloc] init]; ! // 取得按鈕 UIButton *tappedButton = (UIButton *)sender; 設置內容 // 設置 popover popController = [[UIPopoverController alloc] initWithContentViewController:content]; // 設定 popover 內容尺⼨寸,若空間不夠放,會⾃自動縮⼩小 ! popController.popoverContentSize = CGSizeMake(256, 256); 指定位置 ! popController.delegate = self; [popController presentPopoverFromRect:tappedButton.frame inView:self.view 彈出顯⽰示 permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; }
  • 34.
  • 35.
  • 36.
    範例: QV120 UIPopoverController 使⽤用 Protocol 之 delegate 程式寫法
  • 37.
    Project QV120 延伸QV117 UIPopoverController delegate / protocol 的 程式寫法
  • 38.
  • 39.
    (2)設定遵循協定 (4) 開啟彈出畫⾯面 主要畫⾯面 (3)實作代理⽅方法 ViewController 彈出控制器 UIPopoverController (5) 執⾏行傳回資料 (1)在此定義出協定 彈出之內容畫⾯面 (呼叫代理⽅方法) PopoverContentViewCotroller
  • 40.
    PopoverContentViewController.h #import <UIKit/UIKit.h> @protocol DismissPopoverDelegate<NSObject> 定義出協定 - (void) dismissWithData:(NSString *)data; @end 1 @interface PopoverContentViewController : UIViewController { __unsafe_unretained id <DismissPopoverDelegate> delegate; } @property (nonatomic, assign) __unsafe_unretained id<DismissPopoverDelegate> delegate; - (IBAction) sendBack:(id)sender; - (IBAction) sendBack2:(id)sender; 定義出協定 - (IBAction) sendBack3:(id)sender; @end
  • 41.
    ViewController.h #import <UIKit/UIKit.h> #import "PopoverContentViewController.h" @interfaceViewController : UIViewController <UIPopoverControllerDelegate, DismissPopoverDelegate> { UIPopoverController *popController; 2 IBOutlet UILabel *display; } 使⽤用協定 - (IBAction) showPopover:(id)sender; @end
  • 42.
    ViewController.m - (void) dismissWithData:(NSString*)data { display.text = [NSString stringWithFormat:@"收到資料 %@", data]; [popController dismissPopoverAnimated:YES]; } 3 實作協定
  • 43.
    #import "ViewController.h" #import "PopoverContentViewController.h" ViewController.m @implementation ViewController 4 - (IBAction) showPopover:(id)sender { PopoverContentViewController *content = [[PopoverContentViewController alloc] init]; content.delegate = self; 在此指定 "內容畫⾯面物件" // 取得按鈕 UIButton *tappedButton = (UIButton *)sender; 的代理⼈人 // 設置 popover popController = [[UIPopoverController alloc] initWithContentViewController:content]; // 設定 popover 內容尺⼨寸,若空間不夠放,會⾃自動縮⼩小 //popController.popoverContentSize = CGSizeMake(256, 256); popController.delegate = self; [popController presentPopoverFromRect:tappedButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; }
  • 44.
    PopoverContentViewController.m #import "PopoverContentViewController.h" @implementation PopoverContentViewController @synthesizedelegate; - (IBAction) sendBack:(id)sender { 5 [self.delegate dismissWithData:@"1"]; } 透過代理⼈人 - (IBAction) sendBack2:(id)sender { 傳遞資料 [self.delegate dismissWithData:@"2"]; } - (IBAction) sendBack3:(id)sender { [self.delegate dismissWithData:@"3"]; }
  • 45.
  • 46.
    Delegate method • UIPageViewControllerDelegate • UIPageViewControllerDataSource
  • 47.
    範例: QV113 UIPageViewController 基本原理
  • 48.
    Project QV113 UIPageViewController 多個⾴頁⾯面的翻書程式
  • 49.
    新增每⾴頁內容的畫⾯面 ContentViewController ContentViewController.h #import <UIKit/UIKit.h> ⾴頁⾯面內顯⽰示 @interface ContentViewController : UIViewController { WebView } @property (strong, nonatomic) IBOutlet UIWebView *webView; @property (strong, nonatomic) id dataObject; @end
  • 50.
  • 51.
    ContentViewController.m 於每次翻⾴頁時, 將 dataObject 內容 指定到 WebView @implementation ContentViewController @synthesize webView, dataObject; - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [webView loadHTMLString:dataObject baseURL:[NSURL URLWithString:@""]]; } 寫於 ContentViewController.m 的 viewDidLoad: 也可以
  • 52.
    ViewController.h Data Model #import <UIKit/UIKit.h> #import "ContentViewController.h" @interface ViewController : UIViewController <UIPageViewControllerDataSource> { UIPageViewController *pageController; NSArray *pageContent; } @property (strong, nonatomic) UIPageViewController *pageController; @property (strong, nonatomic) NSArray *pageContent; @end
  • 53.
    ViewController.m - (void) createContentPages { NSMutableArray *pageStrings = [[NSMutableArray alloc] init]; for (int i=1; i<11; i++) { NSString *contentString = [[NSString alloc] initWithFormat: @"<html><head></head><body><h1>Chapter %d</h1><p>This is the page %d of content displayed using UIPageViewController in iOS 5.</ p></body></html>", i, i]; [pageStrings addObject:contentString]; } pageContent = [[NSArray alloc] initWithArray:pageStrings]; } - (void)viewDidLoad { 將 1~10 ⾴頁內容 [super viewDidLoad]; [self createContentPages]; 儲存於陣列內 ****** 省略部分程式 ****** }
  • 54.
    建⽴立兩個⽅方法,供代理 ViewController.m 程式於切換⾴頁⾯面時呼叫 - (ContentViewController *)viewControllerAtIndex:(NSUInteger)index { // Return the data view controller for the given index. if (([self.pageContent count] == 0) || (index >= [self.pageContent count])) { 指定某⼀一⾴頁,傳回建⽴立好的 return nil; } ContentViewController // Create a new view controller and pass suitable data. ContentViewController *dataViewController = [[ContentViewController alloc] initWithNibName:@"contentViewController" bundle:nil]; dataViewController.dataObject = [self.pageContent objectAtIndex:index]; return dataViewController; } - (NSUInteger)indexOfViewController:(ContentViewController *)viewController { return [self.pageContent indexOfObject:viewController.dataObject]; }
  • 55.
    ViewController.m UIPageViewController 的代理⽅方法 (viewControllerBeforeViewController) - (UIViewController *)pageViewController: (UIPageViewController *)pageViewController viewControllerBeforeViewController: (UIViewController *)viewController { NSUInteger index = [self indexOfViewController: (ContentViewController *)viewController]; if ((index == 0) || (index == NSNotFound)) { return nil; } index--; return [self viewControllerAtIndex:index]; }
  • 56.
    ViewController.m UIPageViewController 的代理⽅方法 (viewControllerAfterViewController) - (UIViewController *)pageViewController: (UIPageViewController *)pageViewController viewControllerAfterViewController: (UIViewController *)viewController { NSUInteger index = [self indexOfViewController: (ContentViewController *)viewController]; if (index == NSNotFound) { return nil; } index++; if (index == [self.pageContent count]) { return nil; } return [self viewControllerAtIndex:index]; }
  • 57.
    - (void)viewDidLoad ViewController.m { [super viewDidLoad]; [self createContentPages]; NSDictionary *options = [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin] forKey:UIPageViewControllerOptionSpineLocationKey]; self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options: options]; pageController.dataSource = self; [[pageController view] setFrame:[[self view] bounds]]; ContentViewController *initialViewController = [self viewControllerAtIndex:0]; NSArray *viewControllers = [NSArray arrayWithObject:initialViewController]; [pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; [self addChildViewController:pageController]; [[self view] addSubview:[pageController view]]; [pageController didMoveToParentViewController:self]; }
  • 58.
    問題討論 An Example iOS5iPhone UIPageViewController Application (Source: http://www.techotopia.com/index.php/ An_Example_iOS_5_iPhone_UIPageViewController_Application)
  • 59.