前面小編介紹了已經介紹了 UIView 與 UIButton (前篇: [入門] BEAR實驗室: XCODE製作互動元件 – UIBUTTON)

有沒有讀者發現其實兩者很相似,除了按鈕可以點擊之外,兩者幾乎一模一樣

今天小編就要教大家自己製作屬於自己的 UIView 做出類似 UIButton 的效果

首先我們在要新增一個屬於我們自己的 UIView 從左上角的工具列找出 File -> New -> File…

接著選擇 iOS 中 Cocoa Touch 裡面的 Objective- C class 檔案

然後我們就可以幫自己的 UIView 命名了

這裡 Tako 幫自己的 UIView 取名為 “TakoView”

繼承(Subclass)的部分我們選擇 UIView

表示我們的 TakoView 尚未編輯時跟 UIView 一模一樣,只有名字不同而已

建立成功後我們得到一個 TakoView.h 及一個 TakoView.m

TakoView 暫且先不要動

現在我們回到熟悉的 ViewController.m 裡面

在圖中藍色框框我們引用剛剛建立的 TakoView

#import “TakoView.h”

這樣我們才可以在本視圖控制器(ViewController)中建立 TakoView

在 viewDidLoad 中寫下建立UIView的程式碼   

TakoView *takoview = [[TakoView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
takoview.backgroundColor = [UIColor redColor];
[self.view addSubview:takoview];

只是這次我們將 UIView 換成了 TakoView

Command + R 執行後

如意料之中的,我們在指定的區域得到一個紅色的方塊

讀者看到這會不會覺得小編吃飽太閒了

有 UIView 不用,偏偏要弄個這麼麻煩的 TakoView 別急,現在我們開始要來客製化我們的 TakoView 了

首先打開我們的 TakoView.h

我們在裡面宣告一個等會拿來計數的全域整數變數 

int count

接著跟著小編在 TakoView.m 中寫入這些程式碼

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self) { 
        //self 就是 TakoView 本身,條件爲 TakoView 存在時為真,即可執行 if 內容
        //與 viewDidLoad 相同,只要 TakoView 一建立首先就會執行這塊程式碼

        count = 0; //幫等下的計數起始為0
        UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
        //這裡的坐標是已TakoView本身為坐標軸計算

        label.text = [NSString stringWithFormat:@"%d",count];
        label.textColor = [UIColor blackColor];
        label.textAlignment  = NSTextAlignmentCenter;
        label.tag = 101;
        [self addSubview:label];
    }
    return self;
}

接著我們在下面加上一個 UIView 本身就有的實例方法

當 TakoView 本身被觸碰到時會執行

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    count++;
    UILabel *label = (UILabel *)[self viewWithTag:101];
    label.text = [NSString stringWithFormat:@"%d",count];
}

Command + R 試一下結果吧!

連續觸碰的情況下,數字也跟著增加

是不是跟我們之前建立的UIButton效果一樣呢! (參考: [[入門] BEAR實驗室: XCODE製作互動元件 – UIBUTTON][iOS Button]

PS:綠色坐標軸為TakoView中建立元件參考的坐標軸

接下來我們要做的內容更簡單

卻是真正要開始介紹 Protocol 與 Delegate 的觀念!!!!!

協定與委派代理的觀念是 xcode 的精華,但對新手而言卻是難以理解

市面上的書用寫的也很難交代清楚

小編以下將直接用實作介紹 Protocol 與 Delegate 的數種常見用法

現在我們先來訂立目標

我們將要在 ViewController 內輸入參數去控制 TakoView 的 Frame 與 backgroundColor 屬性

咦?!

我們之前不是用 initWithFrame 跟 TakoView.backgroundColor 就可以了嗎?

沒錯,小編要藉由這次的機會教大家蘋果本身是如何設計這些方法的

首先在 TakoView.h 內加入如下程式碼:

@class TakoView;    //本TakoView就是一個類別

@protocol TakoViewDelegate <NSObject>
    //protocol就是協定,名稱為 "TakoViewDelegate" 可以自己取名
    //蘋果本身都是命名為Delegate與DataSource
    - (UIColor *)setTakoViewColor:(TakoView *)TakoView;

    - (CGRect)setTakoViewFrame:(TakoView *)TakoView;
    //協定內的方法在委派的類別(我們的ViewController)內必須具備,某種程度算是防呆裝置
@end


@interface TakoView : UIView //我們當初創建時 TakoView 就是選擇繼承自 UIView

@property(nonatomic) id<TakoViewDelegate> DataSource;
//ViewController 可藉由 TakoViewDelegate 將自身傳值至 DataSource 然後給 TakoView

-(void)setTakoViewDataSource;
//TakoView 內用到的實例方法,宣告後可在 ViewController 內呼叫

@end

接著我們看 TakoView.m

initWithFrame 的部分為初始化執行的內容,在此我們不執行任何動作

在下面加入如下程式碼:

-(void)setTakoViewDataSource
{
    self.backgroundColor = [_DataSource setTakoViewColor:self];
    self.frame = [_DataSource setTakoViewFrame:self];
}

self 是自己的意思,就是 TakoView 的意思

_DateSource 就是 ViewController 這等下再更詳細介紹

setTakoViewColor 及 Frame 就是剛剛協定 ViewController 必須實作的方法

- (UIColor *)setTakoViewColor:(TakoView *)TakoView;
- (CGRect)setTakoViewFrame:(TakoView *)TakoView;

所以這裡就是呼叫 ViewController 中的兩個方法,並給值 TakoView

在我們的範例給的 TakoView 值不會使用到,但有些時候還滿好用的,小編之後再介紹

這兩個方法分別會回傳 UIColor 及 CGRect 兩個屬性給 TakoView 使用

於是我們就得到

self.backgroundColor
self.frame

用以來設定我們 TakoView 的顏色及大小位置

最後該是設定我們的 ViewController.m 檔囉

記得一定要 #import "TakoView.h" 要用它就要引用它!!

然後在 @interface ViewController ()  後要加上

<TakoViewDelegate>

表示我們本類別(ViewController)遵守 TakoViewDelegate 這個 protocol 協定

所以我們就必須在下面加上兩個規定的實例方法了

- (UIColor *)setTakoViewColor:(TakoView *)TakoView
{
    return [UIColor redColor];  //回傳一個 UIColor
}

- (CGRect)setTakoViewFrame:(TakoView *)TakoView;
{
    return CGRectMake(100, 100, 100, 100);  //回傳一個 CGRect
}

兩方法被 TakoView 呼叫到的話就會回傳屬性

題外話,-(void) 表示回傳空值,換而言之就是不需回傳

然後在 ViewDidLoad 內加入如下程式碼:

TakoView *takoview = [[TakoView alloc]init];
//建立一個takoview 並不給予任何屬性

takoview.DataSource = self;

//將本身(ViewContoller)傳給 DataSource,讓 TakoView 使用
//但在 TakoView 中會以 _DataSource 使用
//這是因為synthesize 的關係,現在的xcode會幫我們處理好,小編就不再多談

[takoview setTakoViewDataSource];

//呼叫 takoview 內的實例方法,因此 takoview 才會設定本身的顏色及範圍大小

[self.view addSubview:takoview];

//最後不要忘記將 takoview 加到畫面上囉

[cjtoolbox name=’google_ad’]

這邊的邏輯如下:

  1. ViewController 建立了一個毫無屬性的 TakoView 名字為 takoview
  2. 把 ViewController 的值傳給 takoview內的DataSource
  3. 呼叫 takoview 裡面的 setTakoViewDataSource方法
  4. 該方法呼叫 ViewController 內的 setTakoViewColor 及 setTakoViewFrame 方法並藉由兩方法回傳的數值設定takoview本身的屬性
  5. 將 takoview 加到畫面上

到這裡讀者們不知道有沒有對 Protocol 及 Delegate 有一點點感覺了呢?

其實這就是 openSource 的概念,別人做好的程式碼,我們可以藉由 Delegate 去設定數值或執行 protocol 規定的方法來使用

最常使用到委派與協定的設計不外乎這兩點

  1. 傳值
  2. 做成可以 re-use 的 library

當然我們的 TakoView 也可以重複使用

ViewController.m

宣告全域變數

@interface ViewController ()<TakoViewDelegate>
{
    TakoView *takoviewRed;
    TakoView *takoviewYellow;
    //宣告兩個TakoView
}
@end

ViewDidLoad 中建立兩個 TakoView

記得兩個是獨立的,皆需給予 DataSource

- (void)viewDidLoad
{
    [super viewDidLoad];
    takoviewRed = [[TakoView alloc]init];
    takoviewRed.DataSource = self;
    [takoviewRed setTakoViewDataSource];
    [self.view addSubview:takoviewRed];

    takoviewYellow = [[TakoView alloc]init];
    takoviewYellow.DataSource = self;
    [takoviewYellow setTakoViewDataSource];
    [self.view addSubview:takoviewYellow];
}

當初建立的(TakoView *)TakoView 有用武之地的

藉由 if 判斷式我們可以知道哪個 takoview 要回傳哪個數值

雖然我們只要兩個 if 就可以成立,但是程式碼並不知 道

所以 if 之外記得也要設立一個值回傳,compile 才能成功

- (UIColor *)setTakoViewColor:(TakoView *)TakoView
{
    if (TakoView == takoviewRed) {
        return [UIColor redColor];
    }
    else if (TakoView == takoviewYellow) {
        return [UIColor yellowColor];
    }
    return nil;
}

- (CGRect)setTakoViewFrame:(TakoView *)TakoView;
{
    if (TakoView == takoviewRed) {
        return CGRectMake(100, 100, 100, 100);
    }
    return nil;
}

大功告成!!我們得到一上一下,一紅一黃的 TakoView 了!!

這是個簡單的範例,小編也介紹不需要Delegate的簡單傳值方法

TakoView.h檔內改寫為

@interface TakoView : UIView
    -(void)setTakoView:(TakoView*)TakoView BackgroundColor:(UIColor*)color;
    -(void)setTakoView:(TakoView *)TakoView Frame:(CGRect)rect;
@end

其他都不需要,包含 protocol 也拿掉

TakoView.m內 initWithFrame 我們一樣不寫任何東西

下面兩個方法改寫為

-(void)setTakoView:(TakoView*)TakoView BackgroundColor:(UIColor*)color
{
    self.backgroundColor = color;
}

-(void)setTakoView:(TakoView *)TakoView Frame:(CGRect)rect
{
    self.frame = rect;
}

ViewController 內依然要 #import "TakoView" 但不需要 DelegateViewDidLoad 內程式碼:

TakoView* takoview = [[TakoView alloc]init];
[takoview setTakoView:takoview BackgroundColor:[UIColor yellowColor]];
[takoview setTakoView:takoview Frame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:takoview];

是不是又更了解xcode內的程式碼是如何運作的了呢!

喜歡這篇文章嗎? 加入Takobear粉絲團吧!