斯坦福大學(xué)iOS公開課筆記(7)--繪制視圖和手勢


title: 斯坦福大學(xué)iOS公開課筆記(7)--繪制視圖和手勢
date: 2017-05-31 20:57:14
tags:


這節(jié)課主要講了iOS中的輸入(Input)和輸出(Output)糯笙。

輸入是指用戶和應(yīng)用之間進(jìn)行交互的部分仓洼,這節(jié)課中主要是使用手勢UIGestureRecognizer來對應(yīng)用內(nèi)的控件進(jìn)行控制。

輸出是指應(yīng)用展示給用戶的東西,這節(jié)課中主要使用UIView進(jìn)行輸出。

然后在后邊通過一個繪制撲克牌的Demo來進(jìn)一步展示了如何使用手勢和繪制視圖進(jìn)行輸入和輸出株茶。

視圖(UIView)

視圖(UIView)是iOS中至關(guān)重要的部分,所有的東西都是通過視圖來繪制飘哨,按鈕UIButton是一個視圖,標(biāo)簽UILabel是一個視圖。視圖在屏幕上是一塊矩形區(qū)域设江,你可以通過坐標(biāo)來對他的大小范圍進(jìn)行設(shè)置。

視圖是層層嵌套的攘轩,每個視圖都有一個父視圖叉存,和一個或多個子視圖。要注意視圖之間的層級關(guān)系度帮,因為這會影響到顯示的問題歼捏。

UIWindow

UIWindow在iOS中并不是很重要,因為iOS中只有一個UIWindow够傍,而在Mac上就會有多個UIWindow甫菠。

self.view

每一個控制器UIViewController都會有一個自己的UIView挠铲,我們在控制器中可以通過self.view來獲取他冕屯。獲取到之后我們就可以對他添加一些子視圖來處理我們的應(yīng)用。

我們可以通過方法將UIView添加到某個UIView中拂苹,也可以將某一個UIView移除安聘。

- (void)addSubview:(UIView *)aView; //添加一個子視圖
- (void)removeFromSuperview;        //將自身從父視圖中移除

位置和大小

每一個UIView都有控制他位置和大小的坐標(biāo),設(shè)置合理的坐標(biāo)才能讓視圖合理的顯示在屏幕上瓢棒。了解坐標(biāo)我們就要先了解下邊幾個概念浴韭。

  • CGFloat

    浮點(diǎn)型,UIView坐標(biāo)中所有的參數(shù)都是使用CGFloat浮點(diǎn)型進(jìn)行設(shè)置的脯宿。

  • CGPoint

    一個C語言結(jié)構(gòu)體念颈,用來表示點(diǎn)坐標(biāo),含有兩個參數(shù)x和y连霉,使用x和y來確定一個坐標(biāo)的橫豎位置榴芳。

    CGPoint p = CGPointMake(10.0, 20.0);
        p.x += 20;      //向右移動20個點(diǎn)。
    

- CGSize

    一個C語言結(jié)構(gòu)體跺撼,用來描述UIView的大小窟感,含有兩個參數(shù)width和height。

    ```
    CGSize s = CGSizeMake(100.0, 200.0);
    s.height += 100;    //變高100個點(diǎn)歉井。
    ```

- CGRect

    一個C語言結(jié)構(gòu)體柿祈,包含前面的`CGPoint`和`CGSize`。

    ```
    CGRect r = CGRectMake(10.0, 20.0, 100.0, 200.0);
    ```

- 原點(diǎn)

    iOS中的原點(diǎn)在整個視圖的左上角,橫軸為X軸躏嚎,越向右值越大蜜自。豎軸為Y軸,越向下值越大紧索。這一點(diǎn)與笛卡爾坐標(biāo)系不同袁辈。

    <center>![](斯坦福大學(xué)iOS公開課筆記(7)-繪制視圖和手勢/Coordinates.png)</center>

- bounds

  這是你的坐標(biāo)系中繪制區(qū)域的原點(diǎn),以及高度和寬度珠漂。
  
- frame
   
  也是用來設(shè)置你的坐標(biāo)系中繪制區(qū)域的位置和高度和寬度晚缩。只不過他是基于你的父視圖的位置的。
  
- center

  表示你所在的父視圖的坐標(biāo)中的中心位置媳危,注意荞彼!沒有屬性可以得到你自身的中心,你只能使用自己的bounds的寬和高除以二獲取自身的中心位置待笑。
  
- bounds和frame的區(qū)別

    bounds和frame雖然都是表示視圖的位置和大小鸣皂,但是他們之前還是有一些區(qū)別的,如圖暮蹂,當(dāng)視圖發(fā)生旋轉(zhuǎn)之后寞缝,bounds還是((0,0) (200,250)),而frame則變?yōu)榱?(140,65) (320,320))。
    
    <center>![](斯坦福大學(xué)iOS公開課筆記(7)-繪制視圖和手勢/frameAndBounds.png)</center>
    
    
### 創(chuàng)建一個視圖
 
 創(chuàng)建視圖可以使用`storyboard`直接拖拽或者使用代碼來`alloc init`生成一個視圖
 
 

CGRect labelRect = CGRectMake(20,20,50,30);
UILabel *label = [[UILabel alloc] initWithFrame:labelRect];
label.text = @"Hello";
[self.view addSubView:label];


當(dāng)我們要繪制一個自定義的視圖的使用仰泻,只要重寫實現(xiàn)UIView中的`drawRect`方法就可以了荆陆。系統(tǒng)會自動調(diào)用它。

********注意:不要調(diào)用****`drawRect`****方法集侯,只是重寫并實現(xiàn)他********如果想要重繪視圖被啼,調(diào)用`setNeedsDisplay`就可以了。

另外可以使用`UIBezierPath`來繪制你需要的圖形棠枉,關(guān)于`UIBezierPath`的具體使用可以看[這里](http://zhangzr.cn/2017/04/05/iOS-UIBezierPath%E7%BB%98%E5%88%B6%E7%9A%84%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/)浓体。

關(guān)于自定義視圖的具體使用,下面的Demo中會寫的清清楚楚辈讶,所以這邊就不多說了命浴。

## UIGestureRecognizer

手勢是iOS中的輸入部分。添加手勢只需要兩個步驟

1.這一步一般由控制器完成贱除,為自己添加一個手勢識別器生闲。
2.這一步一般由視圖自己完成,處理手勢完成后發(fā)生的事情勘伺。

### UIPanGestureRecognizer 拖動手勢

  • (void)setPannableView:(UIView*)pannableView
    {
    _pannableView = pananbleView;
    UIPanGestureRecognizer *pangr = [UIPanGestureRecognizer alloc] initWithTarget:pannableView action: @selector(pan:)];
    [pannableView addGestureRecognnizer:panr];
    }

### UIPinchGestureReccognizer 捏合手勢

@property CGFloat scale; 捏合手勢距離
@property (readonly) CGFloat velocity; 每分鐘變化的速度


### UIRotationGestureRecgnizer 旋轉(zhuǎn)手勢

@property CGFloat rotation; 弧度
@property (readonly) CGFloat velocity; 每秒變化的速度


### UISwipeGestureRecgnizer 滑動手勢

@property UISwipeGestureRecognizerDirection direction 滑動方向
@property NSUInteger numberOfTouchesRequired; 幾只手指來完成


### UITapGestureRecognizer 點(diǎn)擊手勢

@property NSUInteger numberOfTapsReqired跪腹;幾次點(diǎn)擊
@property NSUInteger numberOfTouchesRequired; 幾只手指來完成


## 繪制紙牌 Demo

這個繪制紙牌的Demo中運(yùn)用了之前所講的繪制和手勢的知識。我們會使用到文字和圖片的繪制以及滑動(swip)手勢和捏合(pinch)手勢飞醉。

    <center>![](斯坦福大學(xué)iOS公開課筆記(7)-繪制視圖和手勢/showSuperCard.gif)</center>

### 創(chuàng)建 view

首先我們新建一個UIView冲茸,在共有方法里聲明他的花色和大小以及是否正面向上的屬性屯阀,并重寫他們的setter方法,在他們的值發(fā)生改變的時候調(diào)用`setNeedDisplay`方法來更新樣式轴术。

@interface PlayingCardView : UIView

@property (nonatomic) NSUInteger rank;
@property (nonatomic ,copy) NSString *suit;
@property (nonatomic) BOOL faceUp;

@end


@implementation PlayingCardView

  • (void)setRank:(NSUInteger)rank
    {
    _rank = rank;
    [self setNeedsDisplay];
    }

  • (void)setSuit:(NSString *)suit
    {
    _suit = suit;
    [self setNeedsDisplay];
    }

  • (void)setFaceUp:(BOOL)faceUp
    {
    _faceUp = faceUp;
    [self setNeedsDisplay];
    }

@end


 ### 設(shè)置比例

在繪制卡片之前我們先通過幾個方法和宏定義來做一些適配性的東西保證卡片在不同的大小下都可以完美的顯示出來难衰。

    ![](斯坦福大學(xué)iOS公開課筆記(7)-繪制視圖和手勢/card_big.png)
    
    ![](斯坦福大學(xué)iOS公開課筆記(7)-繪制視圖和手勢/card_small.png)

define CORNER_FONT_STANDARD_HEIGHT 180.0

define CORNER_RADIUS 12.0

  • (CGFloat)cornerScaleFactor
    {
    return self.bounds.size.height/CORNER_FONT_STANDARD_HEIGHT;
    }

  • (CGFloat)cornerRadius
    {
    return CORNER_RADIUS * [self cornerScaleFactor];
    }

  • (CGFloat)cornerOffSet
    {
    return [self cornerRadius]/3.0;
    }


### 繪制

繪制部分主要是通過重寫`-(void)drawRect:(CGRect)rect`方法來實現(xiàn)

#### 繪制圖片部分

  • (void)drawRect:(CGRect)rect
    {
    //使用UIBezierPath繪制一個圓角。

    UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:[self cornerRadius]];

    [roundedRect addClip];

    [[UIColor whiteColor] setFill];
    UIRectFill(self.bounds); //調(diào)用C

[[UIColor blackColor] setStroke];
[roundedRect stroke];


if(self.faceUp)
{
    //根據(jù)撲克牌的名字找到對應(yīng)的圖片
    UIImage *faceImage = [UIImage imageNamed:[NSString stringWithFormat:@"%@%@",self.suit,[self rankAsString]]];
    if(faceImage)
    {
        //將圖像部分按比例縮小
        CGRect imagrRect = CGRectInset(self.bounds,
                                       self.bounds.size.width * (1.0 - self.faceCardScaleFcator),
                                       self.bounds.size.height * (1.0 - self.faceCardScaleFcator));
        //繪制圖片
        [faceImage drawInRect:imagrRect];
    }
    else
    {
        [self drawPips];
    }
    
    //繪制文字
    [self drawCorners];
}
else
{
    [[UIImage imageNamed:@"cardBcak"] drawInRect:self.bounds];
}

}


#### 繪制文字部分

  • (void)drawCorners
    {
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = NSTextAlignmentCenter;
UIFont *cornerFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
cornerFont = [cornerFont fontWithSize:cornerFont.pointSize * [self  cornerScaleFactor]];

NSAttributedString *cornerText = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n%@",[self rankAsString],self.suit] attributes:@{NSFontAttributeName : cornerFont ,NSParagraphStyleAttributeName : paragraphStyle}];

//繪制文字
CGRect textBounds;
textBounds.origin = CGPointMake([self cornerOffSet], [self cornerOffSet]);
textBounds.size = [cornerText size];
[cornerText drawInRect:textBounds];


//旋轉(zhuǎn)
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, self.bounds.size.width, self.bounds.size.height);
CGContextRotateCTM(context, M_PI);
[cornerText drawInRect:textBounds];

}


### 添加滑動手勢

滑動手勢是使用storyboard中脫線的方式來實現(xiàn)的逗栽,和添加一個`UIButton`的點(diǎn)擊事件差不多盖袭,將添加的滑動手勢拖入到控制器中并實現(xiàn)方法就可以了。

  • (IBAction)swipe:(id)sender {

    self.playingCardView.faceUp = !self.playingCardView.faceUp;

}


### 添加捏合手勢

捏合手勢是使用代碼添加的彼宠,在view中添加手勢的響應(yīng)方法并把它放到公有文件中鳄虱。

  • (void)pinch:(UIPinchGestureRecognizer *)gesture
    {
    if(gesture.state == UIGestureRecognizerStateChanged ||
    gesture.state == UIGestureRecognizerStateEnded)
    {
    self.faceCardScaleFcator *= gesture.scale;
    gesture.scale = 1.0;
    }
    }

  • (void)pinch:(UIPinchGestureRecognizer *)gesture;

然后在控制器中將它添加到view中

[self.playingCardView addGestureRecognizer:[[UIPinchGestureRecognizer alloc] initWithTarget:self.playingCardView action:@selector(pinch:)]];

-----
以上就是斯坦福大學(xué)iOS公開課第七課的筆記。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凭峡,一起剝皮案震驚了整個濱河市拙已,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摧冀,老刑警劉巖倍踪,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異索昂,居然都是意外死亡建车,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門椒惨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缤至,“玉大人,你說我怎么就攤上這事框产∑啾” “怎么了错洁?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵秉宿,是天一觀的道長。 經(jīng)常有香客問我屯碴,道長描睦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任导而,我火速辦了婚禮忱叭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘今艺。我一直安慰自己韵丑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布虚缎。 她就那樣靜靜地躺著撵彻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陌僵,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天轴合,我揣著相機(jī)與錄音,去河邊找鬼碗短。 笑死受葛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偎谁。 我是一名探鬼主播总滩,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼巡雨!你這毒婦竟也來了咳秉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鸯隅,失蹤者是張志新(化名)和其女友劉穎澜建,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝌以,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炕舵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了跟畅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咽筋。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徊件,靈堂內(nèi)的尸體忽然破棺而出奸攻,到底是詐尸還是另有隱情,我是刑警寧澤虱痕,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布睹耐,位于F島的核電站,受9級特大地震影響部翘,放射性物質(zhì)發(fā)生泄漏硝训。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一新思、第九天 我趴在偏房一處隱蔽的房頂上張望窖梁。 院中可真熱鬧,春花似錦夹囚、人聲如沸纵刘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽假哎。三九已至蛔翅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間位谋,已是汗流浹背山析。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掏父,地道東北人笋轨。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像赊淑,于是被迫代替她去往敵國和親爵政。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容