UI-1

---恢復內容開始---git

1程序員

一-開發以前

1.學習大綱

-w1000
技術目標:github

  • 強化編程思想:抽取封裝能力,思考解決能力,框架設計能力
  • 強化自我能力:解決問題能力,自學能力,知識存儲記錄能力

2.項目啓動過程

運行就是打包的過程,把包放到模擬器中,此時設置一系列的內容,找到程序的入口(MainInterface),依次按照步驟來.編程

3.拖拽的控件

  • 爲何用weak?
    拖拽的控件所在的控制器都是被強引用所存在的,這個控制器被強引用,控制器的view被控制器強引用,view的控件被view強引用。因此外部拖線這件事其實就是我拿到這個控件,而不須要strong再引用了。json

  • 什麼能夠單擊事件?
    通常繼承UIControl的都有單擊事件數組

  • 常見錯誤
    • 屬性連線出問題了(找不到屬性或者屬性多了):this class is not key value coding-compliant for the key xxxxxx
    • 方法出問題了(找不到方法了): unrecoginzed selector sent to instance

二-UI

UIView

  1. 概念
    屏幕上全部的UI元素都叫作控件,全部控件都繼承自UIView,哪怕是UIControl也是繼承UIView.這些控件的基本屬性都放到了公共的UIView中.
  2. 常見屬性/方法
    • superView: 父控件
    • subViews: 子控件
    • tag: 標識
    • frame: 控件在父控件的位置尺寸(以父控件左上角爲00)
    • bounds : 控件的位置尺寸(以本身左上角爲00)
      • 因此通常只改尺寸,xy都是0 (通常layer層用)
    • center : 控件中心(以父控件左上角爲00)
    • addSubView: 添加
    • removeFromsuperView: 從父控件移除
    • viewWithTag:根據tag找到View
      • 儘可能少使用tag,由於效率差,很亂
  3. ViewDidLoad:
    • 系統調用
    • 控制器的View加載完畢調用
  4. 經常使用控件:

UILabel

用於顯示文字xcode

  1. 屬性
    • numberofLines: 文字行數,等於0的時候自動換行
    • lineBreakMode: 換行模式,是頭部省略仍是尾部省略仍是中間省略
    • font: 字體

UIImageView

用於顯示圖片瀏覽器

  1. 屬性
    • contentMode: 填充模式
      帶有scale的會縮放,不帶的不會縮放,可是須要裁剪 typedef NS_ENUM(NSInteger, UIViewContentMode) { UIViewContentModeScaleToFill,// 徹底壓縮或拉伸 UIViewContentModeScaleAspectFit, // 寬高比不變,不會變形 UIViewContentModeScaleAspectFill,// 寬高比不變,填充 UIViewContentModeRedraw,// 從新繪製 UIViewContentModeCenter, UIViewContentModeTop, UIViewContentModeBottom, UIViewContentModeLeft, UIViewContentModeRight, UIViewContentModeTopLeft, UIViewContentModeTopRight, UIViewContentModeBottomLeft, UIViewContentModeBottomRight, };緩存

    • clipsToBounds: 裁剪多餘部分
    • animationImages: 設置動畫圖片(放一個數組)
    • animationRepeatCount: 播放次數
    • animationDuration: 播放時間

  2. 設置毛玻璃效果
    因爲UIToolBar自帶毛玻璃效果,因此能夠給UIImageView增長UIToolBar的方法設置毛玻璃的簡單效果。UIToolBar有一個barStyle枚舉能夠設置毛玻璃樣式,配合alpha透明度能夠作設置。

  3. 序列幀動畫

  • 加載圖片的兩種方式:
    1. UIImageNamed
      • 就算指向他的指針被銷燬,該資源也不會從內存銷燬
      • 放到Assets裏的蹄片,只能imageNmaed加載,默認就有緩存的
      • 因此是圖片常用的時候,就把圖片放Assets裏,用imageNamed方法
    2. imageWithContentsOfFile
      • 指向他的指針被銷燬,資源就從內存中小時
      • 沒法緩存,用於不常用的大批量的圖片
      • 從資源路徑中找(SandBox)
      • 手機裏的緩存數據都是在沙盒中
      • 圖片放到Assets裏就拿不到路徑了,放到項目中能夠。具體能夠在查看沙盒的時候找Bundle包,裏面有的圖片資源就是項目中的,沒有的就是放到Assets裏面的
      • 拿到圖片路徑:

        NSString *path = [[NSBundle mainBundle] pathForResource:@"資源名字" ofType:@"資源類型"];
        self.imgView.image = [UIImage imageWithContentsOfFile:path];
  • 關於顏色:
    • 白色的RGB都是255
    • 黑色的RGB都是0
    • 灰色的RGB都同樣,靠近0就是深灰,靠近255就是淺灰
    • 還有什麼hex格式,argb格式等

UIButton

按鈕既能顯示文字又能顯示圖片,還能隨時調整內部圖片文字的位置

  1. 狀態
    • normal:通常
    • hightlighted:高亮
    • disabled:不可點擊
  2. 內容圖片和背景圖片
    • 內容圖片不會隨按鈕變大而變化
    • 背景圖片會隨着按鈕變化而拉伸
  3. 屬性
    • 文字,圖片等設置都須要用set方法,由於要區分狀態
    • 設置按鈕字體:button.titleLabel.font
    • 得到按鈕的文字,文字顏色,圖片,背景圖片 :xxxForState
  4. button不一樣於imageView和label,它是用addTarget監聽的,可是其實均可以經過手勢添加監聽。
  5. 調整按鈕內部子控件位置:默認的是圖片左邊,文字右邊,可是開發是各類需求的

    當本身算完按鈕每部距離何時,可能出現文字顯示不全問題,這時候只須要sizeToFit,可是有時會出現文字錯位問題!由於這個方法可能會修改center,那麼能夠先sizetofit算,而後再修改center便可。

    方法1: UIButton有兩個方法返回CGRect,能夠自定義Button重寫這兩個方法
    ```objc{
    • (CGRect)titleRectForContentRect:(CGRect)contentRect;
  • (CGRect)imageRectForContentRect:(CGRect)contentRect;
    方法2: 其實既然都重寫了,不如直接在`layoutSubViews`方法裏面修改 方法3: 不須要重寫一個新的Button,直接修改內邊距objc{
    CGFloat labelWidth = modelButton.titleLabel.frame.size.width;  
    CGFloat imageWith = modelButton.imageView.frame.size.width;  
    modelButton.imageEdgeInsets = UIEdgeInsetsMake(0, labelWidth, 0, -labelWidth);  
    modelButton.titleEdgeInsets = UIEdgeInsetsMake(0, -imageWith, 0, imageWith);  

    ```

    ```objc
    /*
    1、按鈕的狀態
    1.UIControlStateNormal
    1> 除開UIControlStateHighlighted、UIControlStateDisabled、UIControlStateSelected之外的其餘狀況,都是normal狀態
    2> 這種狀態下的按鈕【能夠】接收點擊事件

2.UIControlStateHighlighted
1> 【當按住按鈕不鬆開】或者【highlighted = YES】時就能達到這種狀態
2> 這種狀態下的按鈕【能夠】接收點擊事件

3.UIControlStateDisabled
1> 【button.enabled = NO】時就能達到這種狀態
2> 這種狀態下的按鈕【沒法】接收點擊事件

4.UIControlStateSelected
1> 【button.selected = YES】時就能達到這種狀態
2> 這種狀態下的按鈕【能夠】接收點擊事件

2、讓按鈕沒法點擊的2種方法
1> button.enabled = NO;
*【會】進入UIControlStateDisabled狀態

2> button.userInteractionEnabled = NO;
*【不會】進入UIControlStateDisabled狀態,繼續保持當前狀態

*/

```
  1. 圖片拉伸
    在一些聊天軟件中,那些聊天氣泡,美工都是準備一張圖的,這時候這個Button的背景就是圖片,可是Button很大的時候拉伸很難看。此時須要代碼進行拉伸。這種圖片通常都是要保護一部分不被拉伸,例如四個角什麼的
    • 代碼拉伸
    // 拉伸
    UIImage *img = [UIImage imageNamed:@"1"];
    // 方法一:返回一張受保護而且拉伸平鋪的圖片(edge是受保護區域),此時就留下了圖片最中心1,1的像素點無線平鋪
    UIImage *resizableImage = [img resizableImageWithCapInsets:UIEdgeInsetsMake(img.size.height * 0.5, img.size.width * 0.5, img.size.height * 0.5 - 1, img.size.width * 0.5 - 1)];
    // 方法二:左邊和右邊須要保護的區域
    UIImage *strechImage = [img stretchableImageWithLeftCapWidth:img.size.width * 0.5 topCapHeight:img.size.height * 0.5]    
    [self.btn setBackgroundImage:resizableImage forState:UIControlStateNormal];

    其實這些能夠寫在分類裏,返回一張受保護的圖片(寫一個UIImage分類)

    • 直接拉伸
      選擇Slicing,會自動計算最合適的保護區域,要不本身拽。

懶加載

訪問數據就是重寫get方法,通常的控件,數組等都應該用懶加載

plist

開發中有一些小數據能夠存儲在plist中。例如不少頁面用的數據,NSArray或者NSDictionary之類的數據。

  1. 建立
    • 生成plist只有可能添加的是字典或者數組。通常是直接在plist中添加,或者代碼寫好字典數組,而後writeToFile到本地,而後拽到項目中
  2. 解析
    ```objc{
    // 寫入
    NSArray *array = @[@"1",@"2",@{@"aaa":@"aa"}];
    [array writeToFile:@"/Users/aixiaoxin/Desktop/study.plist" atomically:YES];

    // 讀取

    NSArray *arr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"study" ofType:@"plist"]];
    NSLog(@"%@",arr);

    ```

    字典轉模型

所謂模型,就是專門用來存放數據的對象。

方法:

  1. 純手工:本身創造模型,模型新增構造方法initWithDict等,而後外界賦值,內部實現.
    ```objc{
    -(instancetype)initWithDict:(NSDictionary *)dict {

    if (self == [super init]) {

    self.name = dict[@"name"];
    
     self.icon = dict[@"icon"];

    }
    return self;
    }
    ```

  2. kvc字典轉模型:

  3. YYModel:

自定義控件

  • 代碼建立

自定義UIView,通常在init初始化方法中添加本身的子控件(initWithFrame中寫就能夠,這個方法init也會調用),在layoutsubView中佈局frame(這裏能拿到self.frame),再引入模型接口,在模型的set方法中賦值模型,設置數據(或者提供接口方法直接設置)

  • xib建立
  1. xib:是輕量級的,用來描述局部的UI界面 .xib打包後就是.nib。因此加載是經過nib加載的。
  2. 加載xibView:
    ```objc{
    // 讀取xib
    // last是最後一個數組,由於一個xib可能拽了不少view,其實通常狀況下就一個,便於開發
    UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:@"Play" owner:nil options:nil] lastObject];
    xibView.frame = CGRectMake(100, 100, 300, 100);
    [self.view addSubview:xibView];

    ```
  3. xib的綁定和連線
    和代碼相似,關聯類,而後傳入模型等。
  4. 注意
    • 若是xib各處都用,那應該提供快速的建立方法

      ```objc{
      // 快速加載xib
      +(instancetype)play {
      return [[[NSBundle mainBundle] loadNibNamed:@"Play" owner:nil options:nil] lastObject];
      }

  • 若是xib的.m中,還想用代碼建立子控件,此時和純代碼是不同的,純代碼是init和initWithFrame方法。xib是initWithCoder:,在這裏建立子控件就能夠了。
  • 若是子控件是從xib中建立的initWithCoder中建立的,此時控件是處於爲喚醒狀態,此時要用到awakeFromNib方法,在這裏能夠添加xib中建立的子控件的子控件。其實若是想在xib中再加控件,統一這個方法就行。
  • xib建立的是不能夠用allocinit直接加載的。
  1. 加載原理
    xib轉化成xml代碼,裏面有控件全部的設置。

UIView漸變更畫

方法

KVC

  1. KVC 能夠取值/賦值/字典轉模型等。

    • 賦值:setValueForKey:能夠進行自動類型轉換,若是用KVC和網絡搭建,很是方便。通常一個對象KVC賦值屬性值是可行的。而 setValueForKeyPath: keyPath是能夠嵌套對象的,假如賦值一我的的狗屬性的名字(點語法點出來),就能夠 person setValue: @"旺財 forKeyPath:@"dog.name"。其實後者包含前者所有功能,因此直接用setValueForKeyPath就行。

    • 改變類的私有變量: 通常私有類都是在.m的{}中,此時是點不出來的,這意味着我定義了一個_age,而我直接能夠setValueForKeyPath:@"_age"來修改這個值(寫@"age"都行,他會去找下劃線和不帶下劃線的)。

    • 字典轉模型:

    ```objc{
    -(instancetype)initWithDict:(NSDictionary *)dict {

    if (self == [super init]) {

    // 廢棄

    // self.name = dict[@"name"];
    // self.icon = dict[@"icon"];

    // KVC字典轉模型
     [self setValuesForKeysWithDictionary:dict];

    }
    return self;
    }
    -(void)setValue:(id)value forUndefinedKey:(NSString *)key {
    }```
    KVC字典轉模型的問題:若是有模型嵌套,就會出問題,由於是暴力的鍵值對賦值。固然,此時就會用到框架(YYModel,MJExtension)

  • 取值:valueForKeyPath方法,開發通常不怎麼用,由於點語法就好了
  • 運行時的時候KVC很是強大

KVO

Key Value Observing(鍵值監聽)當某個對象的屬性發生改變時進行監聽。假如監聽一個對象的名字改變,scrollView的contentOffSet改變等。
若是一個類用KVO監聽,蘋果會自動爲這個類生成一個子類(查看isa指針的時候就是NSKVONotifying_XXX類型),因此用的多了性能不好
- - -

監聽屬性,就要給屬性的對象增長觀察者

MYModel *model = [MYModel new];
    // 增長監聽觀察後,那麼應該有個方法來進行 監聽完成後的做爲
    [model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
    model.name = @"改變前";
    model.name = @"改變後";
    [model removeObserver:self forKeyPath:@"name"];
/**
 監聽屬性值改變後

 @param keyPath 要改變的屬性
 @param object 要改變的屬性所屬的對象
 @param change 改變的內容
 @param context 上下文
 */
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    NSLog(@"%@==%@===%@",keyPath,object,change);
    
}

結果:

2017-03-20 18:10:22.341 button[6755:1544348] name==<MYModel: 0x60800022d7e0>==={
    kind = 1;
    new = "\U6539\U53d8\U524d";
}
2017-03-20 18:13:10.575 button[6785:1563494] name==<MYModel: 0x618000030500>==={
    kind = 1;
    new = "\U6539\U53d8\U540e";
}

UIScrollView

設備的屏幕大小是有限的,普通的View不具有滾動功能,UIScrollView能夠經過滾動展現大量內容。
- - -

  1. 基本使用
    • 將須要展現的內容添加到UIScrollViez中
    • 若是想要滾動,設置contentSize屬性,也就是滾動範圍(能夠遠大於本體scrollView的size),因此當contentSize尺寸減去本體size是負數的話就沒法滾動了,怎麼也要大於本體尺寸
    • 默認scroll就設置了clipsToBounds = YES,也就是內容超出邊框後就隱藏
    • 默認scroll設置了彈簧效果
    • 沒法滾動?
      • 沒有設置contentSize
      • scrollView.scrollEnabled設置爲NO(只是不能滾動)
      • scrollView.userInteraction設置爲NO(失去任何交互能力)
      • scrollView.subViews自帶兩個滾動條
      • 滾動就是修改contentOffset,此時能夠用set方法加一個動畫
  2. 常見屬性
    • bounces默認YES,彈簧效果
    • alwaysBouncesHorizontal默認NO,和下一個方法同樣,設置YES的時候可讓沒有contentsize的scrollView滾動(只是一個彈簧效果)
    • alwaysBouncesVertical默認NO,這兩個值就算設置YES也沒區別,由於這時候已經設置了contentSize。當沒有設置contentSize的時候,若是設置這兩個是YES就能夠滾動了,就像網絡圖片還沒下載完成,只有下拉才能下載,而後加載contentsize,這時候就須要用到這兩個屬性了
    • showHorizontalScrollIndicator展現水平滾動條
    • showVerticalScrollIndicator展現垂直滾動條
    public var contentOffset: CGPoint // 滾動視圖偏移量
        public var contentSize: CGSize // 滾動視圖的內容大小
        public var contentInset: UIEdgeInsets // scrollview的contentview的頂點相對於scrollview的位置
    
        public var directionalLockEnabled: Bool // default NO. if YES, try to lock vertical or horizontal scrolling while dragging
        public var bounces: Bool // 是否開啓回彈效果
        public var alwaysBounceVertical: Bool // 是否始終水平回彈
        public var alwaysBounceHorizontal: Bool // 是否始終垂直回彈
        public var pagingEnabled: Bool // 是否分頁(開啓後滑動有自動定位功能)
        public var scrollEnabled: Bool // 是否能夠滾動
        public var showsHorizontalScrollIndicator: Bool // 是否顯示水平滾動條
        public var showsVerticalScrollIndicator: Bool // 是否顯示垂直滾動條
        public var indicatorStyle: UIScrollViewIndicatorStyle // 滾動條的樣式(黑色/白色/默認) 
        public var scrollsToTop: Bool // 默認YES,單擊上方狀態欄(服務商和電池那個地方),會自動回到頂端
  3. 重要屬性

    • contentOffSet,是一個CGPoint屬性,是一個偏移量
      • 能夠控制內容滾動的位置
      • 能夠得知內容滾動的位置(get)
    • contentInset,是UIEdgeInset屬性,是內邊距,分別是上左下右,滾動的時候會多出來一起不顯示的部分就是內邊距效果,會變相的增長額外的滾動距離
  4. 三者區別
  5. 代理(監聽行爲)

在UIScrollView滾動時候就會告訴代理,代理髮送一系列消息。

public protocol UIScrollViewDelegate : NSObjectProtocol {
@available(iOS 2.0, *)
optional public func scrollViewDidScroll(scrollView: UIScrollView) // 滾動的時候
@available(iOS 3.2, *)
optional public func scrollViewDidZoom(scrollView: UIScrollView) // 滾動視圖已經縮放時候
@available(iOS 2.0, *)
optional public func scrollViewWillBeginDragging(scrollView: UIScrollView) // 將要開始拖動視圖調用
@available(iOS 5.0, *)
optional public func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) // 將要結束拖拽視圖調用
@available(iOS 2.0, *)
optional public func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) // 已經結束拖拽視圖
@available(iOS 2.0, *)
optional public func scrollViewWillBeginDecelerating(scrollView: UIScrollView) // 即將減速的時候
@available(iOS 2.0, *)
optional public func scrollViewDidEndDecelerating(scrollView: UIScrollView) // 減速中止的時候
@available(iOS 2.0, *)
optional public func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) // 滾動動畫結束時候
@available(iOS 2.0, *)
optional public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? // 設置進行縮放的子視圖(誰縮放)
@available(iOS 3.2, *)
optional public func scrollViewWillBeginZooming(scrollView: UIScrollView, withView view: UIView?) // 將要進行縮放時候
@available(iOS 2.0, *)
optional public func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) // 完成縮放的時候
@available(iOS 2.0, *)
optional public func scrollViewShouldScrollToTop(scrollView: UIScrollView) -> Bool // return a yes if you want to scroll to the top. if not defined, assumes YES
@available(iOS 2.0, *)
optional public func scrollViewDidScrollToTop(scrollView: UIScrollView) // 點擊狀態欄回到頂部,僅針對可上下滾動的scrollview 有效}

注意: 任何OC對象均可以成爲代理,哪怕你SCrollView滾動,讓一條狗遵照ScrollViewDelegate而且實現方法成爲代理,那再狗的.m中就能夠監聽到scrollView滾動

6.代理(監聽行爲)

scrollView能夠經過手勢完成內容縮放放大
1. 用代理找到要縮放的scrollViewviewForZoomingInScrollView
2. 設置縮放比例:

```
    scrollView.maximumZoomScale = 2.0
    scrollView.minimumZoomScale = 0.5
    scrollView.bouncesZoom = true // 縮放屬性是否回彈 
```

7.分頁功能
- 就像蘋果手機開機的分頁頁面,當你滾動的時候,左邊比較多右邊比較少,那麼就自動滾動到左邊,這就是分頁功能。不少App的分頁滾動功能,也是依據分頁來實現的。
其實就是一個屬性pageingEnable開啓後就能夠了。系統分頁的判斷是按照scrollView的大小來分的。若是要添加分頁控件再自行添加UIpageControl
- 不少分頁的點都用得圖片,這樣看起來很好看,可是其實觀察UIpageControl頭文件是沒有圖片選擇的,它隱藏在.m的私有拓展中有一個屬性_currentPageImage,_otherPageImage,此時能夠經過KVC來轉化成本身喜歡的圖片
- 分頁定時器:每隔必定的時間,但願scrollView作一些事情,去滾動,要用到定時器NSTimer。在用戶即將拖拽scrollView的時候中止定時器,不在拖拽的時候開啓定時器。

1.一個定時器要不永久開啓,只要一中止就自動銷燬了,只能建立一個新的
2.程序一啓動會默認開啓一條線程,是主線程,主線程顯示刷新UI界面,處理用戶交互界面,因此主頁面在進行別的操做的時候,定時器可能會卡住。因此要把`NSTimer`添加到運行循環(修改定時器在runloop的模式,目的是無論主線程在作什麼,都會分配必定時間處理事情)。
// 添加到運行循環
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

常見控件監聽

隨便一個控件,點開頭文件,若是繼承自UIControl就均可以經過addTarget來監聽,有些特殊的提供delegate就能夠經過代理來監聽。像TextField這類比較特殊,它既有代理也繼承UIControl,此時二者均可以監聽開始編輯,文字改變,結束編輯等狀態的。

屏幕適配

  1. 程序員只需關注的是點,而不是像素,一個點所容納的像素越多,越清晰。在iphone4S時代,屏幕尺寸固定,那麼固定值算就能夠適配。在5和5s時代尺寸變化了,此時還沒法用autolayout(由於還要適配ios5),此時用的是AutoresizingMask,在iphone6時代開始用AutoLayOut

  2. Autoresizing
    • Autoresizing和AutoLayout是不兼容的,想要使用如今須要去掉AutoLayout。我只在xib中用過,就是六根線。外面四根線是和父親的關係,裏面兩根線是子類的關係(選擇了會跟隨父控件伸縮)
    • 代碼實現就是有個AutoResizingMask枚舉,能夠選擇是上左下右怎麼適配
    • 只能解決子控件和父控件之間的關係
    • AutoLayout比Autoresizing強得多
  3. AutoLayout
    • ios6 開始引用,不過真正從xcode5開始大量使用,也是如今的主流
    • 能夠解決任何控件之間的關係
    • 用自動佈局,就不要在設置frame
    • 利用約束參照完成佈局
    • 左對齊/右對齊/頂部對齊/底部對齊
    • 中心點x和父控件同樣/中心點y和父控件同樣
    • 兩個控件中心點x同樣/中心點y同樣

    • 在作pad留言板的時候,由於用的是autoResizing,對於UILabel老是文字居中顯示,這時候上下端會出現不少空缺,解決辦法只能計算文字到底多高,在固定高度,而用了AutoLayout就能夠完美解決這個問題。UILabel只須要給一個位置就不報錯,尺寸會自動根據文字內容而計算寬高,此時應該設置下最大寬度(不是真實寬度)Relation->LessThan,告訴UILabel何時開始換行。那麼固定位置和寬度,UILabel就會自動剔除上下兩端的空格了。
    • 讓父控件的高度跟隨子控件伸縮:例如不少表格類型的app,每一個cell高度都不一樣,由於裏面的子控件截然不同。 其實這時候cell 就不能直接設置高度了,而是要設置本身底部和會影響到你的子類的關係,例如你的子類最後一個控件的底永遠和父類的底差10個點,那麼無論子類怎麼變高,父容器也會跟着變。
  4. 約束優先級:兩個互相沖突的約束若是修改優先級,那麼優先級較高的生效,當優先級較高的失效了或者刪除了,優先級較低的纔會生效。例如三個方塊並排放各自距離20,當中間的刪除後,讓第三個自動到中間位置,這時候就用到優先級了。

代碼實現AutoLayout

  1. 禁止autoresizingself.myView.translatesAutoresizingMaskIntoConstraints = NO;
  2. 建立NSLayoutconstraint類建立約束關係
    • 寬高什麼的添加到本身上
    • 和父控件之間控制位置的約束添加到父控件上
    • 兩個平等的控件(都是兒子)之間的約束添加到父控件上
  3. VFL可視化語言
  4. 修改約束:

    // 修改約束
    self.myWidth.constant = 25;
    [UIView animateWithDuration:2.0 animations:^{
        // 須要強制更新
        [self.view layoutIfNeeded];
    }];

Masonry

- 目前最流行的第三方框架
- [Masonry/SnipKit](https://github.com/SnapKit/Masonry)
- 兩個pch上面的宏定義可讓`mas_`所有省略
- `makeConstraints`是添加新的約束
- `updateConstraints`是更新約束
- `remakeConstraints`是刪除以前全部約束,而後添加新的約束

UITableView

基本

  1. TableView分爲PlainGroup兩種style類型,這個是隻讀的,意味着只有在建立tableView的時候能夠設置。
  2. indexPath分爲sectionrow兩個屬性,分別是組和行,根據這個能夠肯定惟一的一行
  3. cell.accessoryView能夠設置系統cell右側的那個按鈕狀態樣式
  4. UITableView內部自動封裝了一套複用機制。會讓空閒的cell進入可重用線程池,當有新的cell出現會先去線程池中找有沒有可複用的,沒有才會建立。假若有100組數據,須要100個cell,可是手機上每屏只能放下10個,其實這時候只需建立11個cell就夠用了。每個數據模型就是一個cell。經過數據源方法來對每一個cell進行數據設置。經過代理方法設置關於tableView的頭,尾等視圖設置

UITableView常見屬性

  1. rowHeight:每一行cell高度
  2. sectionHeader(Footer)Height:每一組頭尾高度
  3. separateStyle:分割線樣式(刪除分割線separateNone)
  4. tableHeader(footer)View:整個tableView的頭尾部,上面的是每一組的頭尾,這個是整個的(插播個廣告什麼的)

Cell常見屬性

  1. accessoryView--accessoryType:都是設置右邊控件的(View優先級更大)
  2. selectedStyle:選中樣式(有Blur,Gray,None等,ios6以前有效果,7以後所有都是灰色)
  3. backgroundView:cell背景能夠是好看的圖片,selectedBackgroundView:選中的背景圖片
  4. contentView:cell上添加的東西都是添加在contentView上的。由於有時候cell刪除,滑動,整個cell都向左移動了,此時若是移動cell很是麻煩,可是移動contentView就方便多了
  5. 自帶cell中的imageView,textLabel等屬性都是延遲加載的,是懶加載的,用到纔會加載

數據源方法

  • 提供幾組,幾行,每個cell什麼樣子,數據是什麼

代理方法

  • 提供cell單機事件
  • 提供cell的頭/尾視圖設置,頭/尾高度設置,設置了這些,前面屬性設置的高度就失效了。
  • 提供了每一行的高度,rowHeight是有侷限性的,這個可讓每一個cell高度不一樣

UITableViewController

  • 每個控制器都有View,在UITableViewController中:self.viewself.tableView是一個對象。
  • 當數據比較少,還想去掉沒有數據的分割線時:能夠設置self.tableView.tableFooterView = [UIView new]

性能優化

  • cell標準寫法.註冊方法

自定義等高的cell

  • 不管是系統自帶cell仍是自定義建立註冊的cell,這個[cell class]都是經過cell alloc initWithStyle方法實現的
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    
    
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        
        _name = [UILabel new];
         [self.contentView addSubview:_name];
        
    }
    return self;
    
    
}
  • 至於cell內部天然要用約束來控制。當須要用frame計算的時候通常會寫在layoutifNeed裏面,由於這裏才能拿到self的frame.可是用約束計算的話直接寫在cell alloc initWithStyle方法裏就行(寫在addSubView之後),由於這是根據父控件的約束,無論父控件如何
  • xib建立cell時候註冊nib
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([MyTableViewCell class]) bundle:nil] forCellReuseIdentifier:@"cell"];
  • 一個tableView顯示不一樣的cell:因爲cellforRowAtIndexpath方法返回一個cell,因此能夠根據indexpath改變cell。說白了就是註冊N個cell和reusedId,根據indexPath來dequeue不一樣的cell。廣告cell就這麼來的
  • 自定義分割線:添加高度爲1的UIView

靜態cell和動態cell

  • 動態cell是數據.數量.高度等等都是動態獲取的
  • 靜態cellStatic Cells是寫死的,在sb中/xib中直接修改cell類型而後繪製出來的。能夠作一些設置界面,而後經過代理監聽
  • 靜態動態只是建立區別,功能都是實現cell
  • 靜態cell 也是能夠自定義的,也能夠畫畫而後關聯類,而後從waakefromNib讀取關聯的cell

字典轉模型

  • 字典轉模型無非就是遍歷數組,而後拿到數組裏的每個字典,而後給模型用KVC賦值,這是一個重複的過程,因此要省事,用插件。並且有的模型很複雜,嵌套模型不少,這麼寫起來更麻煩。
  • MJExtension
    GitHubMJExtension
    ---
    model-objetArrayWith...

  • YYModel
    GitHubYYModel
    ---
    model-yy_modelWithJson..


自定義不等高的cell

  • (計算不等高UILabel)若是frame計算,須要注意UILabel內容不同的時候,要想計算它的高度,須要
UILabel *lab = [[UILabel alloc] init];
    // 100是固定寬度 後者是最大寬度,不限制
    CGSize size = CGSizeMake(100, MAXFLOAT);
    // 計算出高度
    CGFloat height = [lab.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:size].height;
  • 一些app都是frame計算的,假如需求是frame來計算不等高度的cell。控制器在heightForRowAtIndexpath方法中能夠拿到模型方便計算,可是在這裏計算要調用無數次,性能不好,這時候還必須先返回一個高度給cell,因此一開始以爲應該給數據模型增長全部的cell子控件frame 和總高度frame屬性,在總高度屬性中,利用懶加載來計算 高度/各個frame,而後外界heightForRowAtIndexpath直接設置高度。可是這麼作,重用刷新就會出現問題,由於刷新的時候高度大於0,可是不是你想要的高度。真正作法是刷新的時候,拿到json的時候,字典轉模型的時候,建立一個新的frame模型,裏面存放着高度和各個cell子控件的frame,每次刷新數據就綁定好,而後heightForRowAtIndexpath直接拿frame模型。
  • 打印各類方法執行順序,假如10條數據在頁面,實際上是先執行10次heightForRowAtIndexpath纔會執行cellForRowAtIndexPath,說白了就是cell展現前,全部高度早就計算好了。
  • masonry每次都會從新計算,在一些很複雜很複雜的cell控件中,其實frame算性能比較好。(一哥們親身經歷)
  • cell內部計算的時候也不必定寫在layoutsubVies,寫在模型的set方法也能夠,由於這時候是確定有frame的
  • self.tableView.estimatedRowHeight:預估高度,會優化性能,讓heightForRowAtIndexpath執行次數少不少。並且沒有估算的時候,是先執行heightForRowAtIndexpath後執行cellForRowAtIndexPath。當寫了估算行高後,反過來了,由於已經有一個默認高度了。
    - - -

數據刷新

  • 全局刷新:reloadData:就是從新調用數據源方法
  • 局部刷新:reloadRowsAtIndexPath:適合模型數量不變
  • 添加刷新: insertRowsAtIndexPath
  • 刪除刷新:deleteRowsAtIndexPath

左滑刪除

  • 實現代理方法就能夠出現滑動刪除
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    // 刪除模型,動畫單行刷新
    [self.dataSource removeObjectAtIndex:indexPath.row];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];   
}
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{
    return @"刪除";
}
  • 左滑出現多個按鈕(例如微信,滑動出現刪除/關注),此時只須要一個新方法,若是新增了這個方法,上面的return 刪除監聽就實效了。
-(NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"關注" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        
        // 關注

    }];
    action1.backgroundColor = [UIColor orangeColor];
    
    UITableViewRowAction *action2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"刪除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        
        
        // 刪除模型,動畫單行刷新
        [self.dataSource removeObjectAtIndex:indexPath.row];
        
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
        
    }];
    action2.backgroundColor = [UIColor redColor];
    
    return @[action1,action2];
}

若是想點擊後退出編輯模式,tableView.editing = no

  • 編輯模式tableView.editing = yes時,左側就會出現刪除按鈕,其實就是上方的那個編輯模式。並且編輯模式有三種
// 設置cell的編輯模式,有NONE,插入,刪除三種
    override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
        
        return UITableViewCellEditingStyle.Insert
        
    }
  • 批量刪除
    有倆屬性,編輯模式下就能夠批量勾選等等

UICollectionView

  • 流水佈局UICollectionViewFlowLayout:說白了就是當裏面內容變寬了變窄了這個那個了,可是整個佈局會改變。就像手機界面,刪除一個app,後面的會滑上去。
  • self.collrctionView 不等於 self.view,不像tableView,collectionView是添加到view上的。
  • flowLayout佈局的時候能夠設置item的大小,行間距,item間距,滾動方向,每一組內邊距(sectionInset),
  • self.collectionView能夠設置分頁(pagingEnable),彈簧效果(bounces),隱藏滾動條(showH..)等操做,其實不少都是UIScrollView的屬性

  • 相冊照片瀏覽器

// 必需要有佈局,自帶循環機制,每個item就是每個cell
// 必需要註冊cell,而且必需要自定義cell,由於collectionView的默認cell什麼都沒有!
// 調整尺寸什麼的都是佈局的事,cell自定義後經過代理來完成註冊,數量,模型內容
// 當要作的內容例如item大小不一的時候,系統沒法知足,此時要自定義流水佈局

#import "FlowLayout.h"
/*
    自定義佈局:只要瞭解5個方法
 
 - (void)prepareLayout;
 
 - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
 
 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
 
 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior

 - (CGSize)collectionViewContentSize;

 */
@implementation FlowLayout

/*
 UICollectionViewLayoutAttributes:肯定cell的尺寸
 一個UICollectionViewLayoutAttributes對象就對應一個cell
 拿到UICollectionViewLayoutAttributes至關於拿到cell
 */


// 重寫它方法,擴展功能

// 何時調用:collectionView第一次佈局,collectionView刷新的時候也會調用
// 做用:計算cell的佈局,條件:cell的位置是固定不變
// - (void)prepareLayout
//{
//    [super prepareLayout];
//    
//    NSLog(@"%s",__func__);
//    
//}


// 做用:指定一段區域給你這段區域內cell的尺寸(就是這個rect,一開始系統固定的,以後超過這個值就新增)
// 能夠一次性返回全部cell尺寸,也能夠每隔一個距離返回cell
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
//    NSLog(@"%s",__func__);
// 這時候就返回全部了
    NSArray *attrs = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, MAXFLOAT, MAXFLOAT)];
    
    return attrs;
    
}

// 何時調用:用戶手指一鬆開就會調用
// 做用:肯定最終偏移量
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{

    // 拖動比較快 最終偏移量 不等於 手指離開時偏移量
    
    // 最終偏移量
    CGPoint targetP = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity];
    
    // 獲取collectionView偏移量
    NSLog(@"%@ %@",NSStringFromCGPoint(targetP),NSStringFromCGPoint(self.collectionView.contentOffset));
    
    
    return CGPointZero;
}

// Invalidate:刷新
// 在滾動的時候是否容許刷新佈局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
    return YES;
}

// 計算collectionView滾動範圍
//- (CGSize)collectionViewContentSize{
//    return [super collectionViewContentSize];
//}

MVC

  • M是模型,V是視圖,C是控制器。View顯示什麼取決於M,控制器負責把數據模型給View。MVC由於模型的存在解決cell循環利用表格出bug了。只須要記住,不要隨意直接修改cell上的值,要改,就改模型。

通知

  • 每個應用程序都有一個NSNotificationCenter實例,負責不一樣對象之間消息傳遞。
  • 我作一件事要讓外界知道,我就發佈通知(post),誰來監聽誰就(post),這個過程是一對多的,我廣播發布,誰註冊了監聽就把通知給誰。
  • NSNotification一個通知有三個屬性
    1. name:通知名字
    2. object:通知發佈者(id)
    3. userInfo:傳遞內容信息(字典)
// 發佈通知(object是誰發送)
    [[NSNotificationCenter defaultCenter] postNotificationName:@"RemoveNotification" object:self userInfo:@{@"money":self.wine.money}];
    // 監聽通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(remove:) name:@"RemoveNotification" object:nil];

- (void)remove:(NSNotification*)noti {
    
    NSLog(@"%@---%@---%@",noti.name,noti.object,noti.userInfo);
    int money = [[noti.userInfo objectForKey:@"money"] intValue];
    self.totalPriceLabel.text = [NSString stringWithFormat:@"%d",[self.totalPriceLabel.text intValue]-money];
    
}

object誰發佈的name什麼通知。能夠不寫name,那就是監聽這個object的全部通知。

  • 移除通知remove,當對象被銷燬,就刪除
  • 通知是有順序的,要先監聽add,再發出post,不然兼聽不到
  • add通知的時候還有一個方法會讓填寫一個隊列和block,隊列不須要的時候寫nil,這個也是能夠用的。當隊列須要,填寫的隊列就決定block在哪裏執行。並且這個通知的移除不是通常的removeself!由於是系統觀察的,方法你都沒寫!
@property (nonatomic, weak) id observe;
@end

@implementation ViewController
- (void)test
{
    // 方式一:
    // Observer:觀察者
    // selector:只要一監聽到通知,就會調用觀察者這個方法
    // Name:通知名稱
    // object:誰發出的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveNote) name:@"note" object:nil];

}

- (void)test2
{
    // Name:通知名稱
    // object:誰發出的通知
    // queue:決定block在哪一個線程執行,nil:在發佈通知的線程中執行
    // [NSOperationQueue mainQueue]:通常都是使用主隊列
    // usingBlock:只要監聽到通知,就會執行這個block
    // 注意:必定要記得移除
    _observe = [[NSNotificationCenter defaultCenter] addObserverForName:@"note" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        
        // 只要監聽到通知 就會調用
        NSLog(@"%@",[NSThread currentThread]);
        
        NSLog(@"%@",self);
        
    }];
}


// 一個對象即將銷燬就會調用
- (void)dealloc
{
    // 移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:_observe];
}
// 異步:監聽通知 主線程:發出通知 接收通知代碼在主線程
// 主線程:監聽通知 異步:發出通知 接收通知代碼在異步
// 注意:在接收通知代碼中 能夠加上主隊列任務

UIDevice通知

  • UIDevice提供一個單例UIDevice-currentDevice,表明設備,能夠獲取一些設備信息,例如電池電量,電池狀態,設備類型,設備系統等等。
  • 之前的代碼會判斷系統版本sytemVersion來進行代碼不一樣的寫法,能夠用於系統適配
  • UIDevice會不間斷的發佈一些通知,例如
    1. 設備旋轉
    2. 電池狀態改變
    3. 電池電量
    4. 近距離傳感器(例如接電話後屏幕變黑)

鍵盤通知

  • 鍵盤也有一些系統的通知,來判斷鍵盤狀態

    -w500

UI進階(多控制器就是進階)

基礎

啓動頁LaunchScreen

  • 能夠用自帶的sb設置,也能夠用Assset裏面的啓動頁設置。
  • sb設置的底層實現:把LauchScreen裏的內容生成了一張圖片儲存在沙盒中

info.plist

  • 做用:設置應用程序配置信息。最外層節點是一個字典
  • Bundle name:應用程序名稱(項目名稱通常不是中文的,由於要打包,可是app不少中文名字,這時候在這裏改這個選項是中文,例如 財務審批
  • Bundle identifier:應用程序惟一標識(上傳appStore的時候必須有這個,作推送的時候也必須有這個(推送是把消息發送給蘋果服務器,服務器根據你手機的Bundle identifier來找到你這個app))
  • Bundle version string , short:版本號,軟件版本號
  • Bundle version:應用程序打包版本號

PCH

  • 做用:
    • 自定義Log
    // 定義debugFKLog
    #ifdef DEBUG
    #define FKLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
    #else
    #define FKLLog(...)
    #endif
    • 存儲公共宏
    • 存儲公共頭文件(自定義的分類等)
  • 從xcode6開始蘋果不推薦PCH,就是不編譯了。如今須要建立pch後,在Build Settings - 搜索prefix - 尋找 LLVM 7.0 Lauguage - pch改YES - 填寫pch路徑fullPath
  • 原理:app編譯時候,把pch全部內容拷貝到全部文件中(若是是混合開發,有c文件的話就會報錯了,由於c不識別pch裏面你的UI宏,這時候還給在pch作設置)

UIApplication

  • UIApplication是應用程序的象徵。每個app只有一個,是單例。sharedApplication
  • 一個ios程序啓動後建立的第一個對象就是UIApplication,利用它而已作一些應用層設置。例如
    • applicationIconBadgeNumber:設置app右上角紅色提醒數字
  1. 設置圖標
  2. 註冊通知
  3. 設置圖標屬性

    ```
    /**
    取得用戶受權
    */
  • (void)badgeNotification:(UIApplication *)application {
    // 取得用戶受權顯示通知[BadgeNumberUIApplication層]
    id typeBadge = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
    id typeSound = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound categories:nil];
    id typeAlert = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
    [application registerUserNotificationSettings:typeBadge];
    [application registerUserNotificationSettings:typeSound];
    [application registerUserNotificationSettings:typeAlert];
    }
    ```
// ios 8後須要受權,目前只會寫一種受權方式,iOS10有新方法
    NSInteger times = arc4random() % 100;
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:times];
- `networkActivituIndicatorVisible`:設置聯網小菊花的可見性(Bool)通常寫在網絡方法中
- `statusBarHidden`:設置狀態欄隱藏

```

/**
想要使用 默認要在info.plist新增最後一個鍵值對,選no,這時候控制器設置無效
全局設置狀態欄白色
全局設置導航欄背景mainColor
全局設置導航欄標題文字顏色白色,微軟雅黑
全局設置導航欄Item顏色 白色
*/

  • (void)systemSetting {

    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    [[UINavigationBar appearance] setBarTintColor:mainColor];
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
    [[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, [UIFont fontWithName:@"MicrosoftYaHei" size:18.0], NSFontAttributeName, nil]];
    }
    ```

    // 不是全局 交給每一個控制器獨立控制,默認是交給控制器的
    -(UIStatusBarStyle)preferredStatusBarStyle {
    
    return UIStatusBarStyleLightContent;
    }
    -(BOOL)prefersStatusBarHidden {
    
    return YES;
    }
    • keyWindow:應用程序主窗口

    • 強大的openURL方法 [NSURL URLWithString:]-->根據協議頭tel: sms:http:等來區分
      • 能夠打電話
      • 發短信
      • 發郵件
      • 打開網絡資源
      • 打開其餘app
  • UIApplication代理:
    app容易受到干擾,打電話這個那個會切出去。當這些系統干擾出現的時候,app須要作一些事。例如保存數據等。此時UIApplication會有代理監聽(也就是AppDelegate裏面那一堆方法)
    • 系統來電等
    • 程序啓動關閉等
    • 收到內存警告

應用程序啓動原理

  1. 執行main函數->執行UIApplicationMain->建立UIApplication對象->執行代理
  2. 開啓運行循環(主運行循環),保證app不退出(死循環)
  3. 加載info.plist(一些基本屬性,而後看看有沒有main.sb,有就加載,沒有就建立)
  4. 啓動完畢,進入appDelegate代理

UIWindow

UIWindow是一個特殊的UIView,ios啓動完畢後,啓動的第一個視圖控件就是UIWindow,而後建立控制器View,把控制器view加到UIWindow上。因此說沒有UIWindow就看不到任何UI界面的。

  • 純代碼寫app的時候window是要手動建立的
  • self.window makeKeyAndVisible的做用是顯示,把跟控制器的view加載到個人window上。
  • 其實鍵盤,狀態欄也是一個UIWindow
  • 從ios9後,若是添加了多個窗口,例如又建立了UIWindow,makeKey了,狀態欄就沒了,消失了,解決辦法就是讓狀態欄給應用程序管理。
  • windowLevel:窗口層級(不一樣窗口誰前誰後能夠分層級)Alert > StatusBar > Normal

控制器如何加載View?

  1. 控制器利用loadView方法,專門建立控制器View。當控制器的View第一次使用的時候調用此方法。那麼loadView作了什麼?

    1.  判斷若是控制器是sb加載的,就找sb的View設置爲本身當前View
     2.  若是是xib加載,就把xibView設置本身View
     3.  若是都不是,就會建立一個空白的View

    一旦重寫了這個方法,那麼這個View就須要本身建立了,這樣能夠自定義控制器最一開始的View。

  2. 控制器View都是懶加載的
  3. 若是一個控件是透明的,那麼它不能接收事件。一開始建立的控制器不是透明的,只是顏色是透明的,是能夠接收事件的。

UITexiField

  1. self.inputView:修改文本框彈出鍵盤類型

UIPickerView/UIDatePicker

PickerView

代理選擇設置內容。通常配合UITextField的鍵盤類型設置爲是自定義的PickerView

DatePicker

datepickerMode: 日期模式能夠選擇想要的年月日
locale:設置區域爲localeWithLocaleId:@"zh"中國
監聽日期改變用addTarget-Valuechange

項目中這些選項都有,例如左邊國家右邊國旗的界面, 年月日時間的界面, 選擇城市(市區)的界面。國家國旗就是一個pickerView,自定義View弄上imageView和label,用代理完成。年月日就如上,選擇城市~~

String

字符串 用copy目的是外界修改了,不會影響到本身。其實,一個字符串屬性被賦值的時候,self.name = @"xxx"這個賦值的值,要不就是寫死的,要不就是網絡獲取的,可是必定都是NSString類型。而copy屬性呢,會在set方法的時候作一次copy,copy會作一次判斷,判斷外界給的值得類型是可變的仍是不可變的,若是是不可變的,直接賦值,若是是可變的,就copy一份賦值。因此其實app的字符串都是不可變的,因此寫strong也是能夠的,甚至會少一次判斷,性能上會高一些。財務審批NSString很是多,這一點用strong是可行的。

---恢復內容結束---

相關文章
相關標籤/搜索