UIView---彙總

視圖、繪圖、貼圖、手勢、變形、佈局、動畫、動力、特效 UIBezierPath、UIGestureRecognizer、CGAffineTransform、frame、bounds、center、transform、UITouch、UIEvent、Layout、Autoresizing、Auto Layout、Animation、UIImage、NSTimer、UIView、Core Animation、CALayer、CAAnimation、CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup、CATransform3D、UIDynamicAnimator、UIGravityBehavior、UICollisionBehavior、UIAttachmentBehavior、 UISnapBehavior、UIPushBehavior、NSNotification ========================================================================================================= 知識點 1、繪圖 今天: 1.繪圖 1.1基本概念 屏幕:不少個晶體組成的,分辨率1920X1080,一行有1920個晶體,一共有1080行,每個晶體發三種顏色的光(red,green,blue) 圖片: 點陣圖:一堆點,每個點是一個顏色,圖片的分辨率指的就是存儲的圖片的點的個數 圖片中的每個點是用4個整數來存儲的,這四個整數分別對象該點的red(0-255)、green(0-255),blue(0-255),alpha。一個點就須要4個字節來存儲,依據這個規律就能夠計算圖片的大小了。但爲了壓縮圖片的大小,將一個點周圍的四個點計算一個平均值,用一個點的值來代替這四個點, 矢量圖: 存儲的是生成圖形所須要通過計算的數學公式,因此放大後不會失真 像素 2.OC對象與圖形的轉換 內存中的OC對象,會基於系統提供的默認規則,繪製成平面圖後顯示到屏幕上。 繪製的過程本質是由底層的Core Graphics 這一組C語言的API實現 系統爲編程人員提供了一個可編程的接口,在指定的位置添加繪製的代碼之後,就可讓系統在原有的繪製基礎上增長自定義的繪製內容 3.繪圖的實現 [Demo1_Graphics] 實現步驟: a。重寫UIView的drawRect方法。該方法由系統自動調用,不能本身手動調用。由於drawRect方法只是系統一整套繪製流程中的一個環節。 b。獲取繪製的上下文對象 c。設置上下文對象的繪製起始點 d。添加路徑 e。設置描邊或填充的顏色 f。繪製路徑 MyView.h 繼承自UIView MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { // 獲取系統的上下文對象
    CGContextRef context = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(context, 40, 40); CGContextAddLineToPoint(context, 40, 140); CGContextAddLineToPoint(context, 140, 40); CGContextAddLineToPoint(context , 40, 40); //設置描邊的顏色
 CGContextSetStrokeColorWithColor(context , [[UIColor redColor] CGColor]); CGContextSetFillColorWithColor(context, [[UIColor greenColor]CGColor]); //按照路徑描邊 //CGContextStrokePath(context); //CGContextFillPath(context);
 CGContextDrawPath(context, kCGPathFillStroke); } @end MyViewController.h MyViewController.m #import "MyViewController.h"
#import "MyView.h"

@interface MyViewController () @end

@implementation MyViewController - (void)viewDidLoad { [super viewDidLoad]; MyView *view = [[MyView alloc]initWithFrame:self.view.frame]; 將自定義的view加到controller view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:view]; }  4. UIBezierPath貝塞爾曲線 4.1 是OC語言對c語言繪圖的一部分API的封裝結果 4.2 做用:更方便的繪製直線、曲線、矩形、圓弧、橢圓等 4.3 繪製直線 【Demo2_BezierPath_Line】 path.lineWidth 設置線條寬度 path.lineCapStyle = kCGLineCapButt;設置線頭兒的樣式 path.lineJoinStyle = kCGLineJoinRound;設置交叉點的樣式 [[UIColor redColor] setStroke];設置線條顏色 [[UIColor greenColor] setFill];設置填充色 1)在故事板中拉入一個view,並在第三個檢查器class與本身建立的類關聯起來 2)建立貝塞爾路徑實例 UIBezierPath *path = [UIBezierPath bezierPath]; 3)繪製,填充顏色、線條顯示出來 [path stroke]; [path fill]; MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { //建立貝塞爾路徑的實例
    UIBezierPath *path = [UIBezierPath bezierPath]; [path addArcWithCenter:CGPointMake(120, 120) radius:50 startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; [path addLineToPoint:CGPointMake(50, 50)]; //移動到起始點 //[path moveToPoint:CGPointMake(50, 50)]; //[path addLineToPoint:CGPointMake(50, 150)]; //[path addLineToPoint:CGPointMake(200, 50)]; //[path addLineToPoint:CGPointMake(50, 50)]; //設置顏色
 [[UIColor redColor] setStroke]; [[UIColor greenColor] setFill]; //設置path的經常使用屬性
    path.lineWidth = 10; //設置線頭兒的樣式 //path.lineCapStyle = kCGLineCapButt; //設置交叉點的樣式 //path.lineJoinStyle = kCGLineJoinRound; //繪製
 [path stroke]; //[path fill]; 
} 4.4繪製圓弧 【Demo2_BezierPath_Line】 M_PI_2 M_PI [path addArcWithCenter:CGPointMake(120, 120) radius:50 startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; 練習: 定製圓形的下載進度提示條 【Demo3_Custom_DownloadView】 // 重繪視圖
 [self setNeedsDisplay]; DownloadView.h DownloadView.m #import "ViewController.h"
#import "DownloadView.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet DownloadView *downloadView; @property (weak, nonatomic) IBOutlet UISlider *slider; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.slider.value = 0; } - (IBAction)downloadNumber:(UISlider *)sender { self.downloadView.progressValue = sender.value; } DownloadView.h #import <UIKit/UIKit.h>

@interface DownloadView : UIView @property(nonatomic,strong)UIColor *progressColor; @property(nonatomic)CGFloat progressValue;//0~1之間的浮點數

@end DownloadView.m #import "DownloadView.h"

@implementation DownloadView //重寫setter方法
- (void)setProgressValue:(CGFloat)progressValue{ // 保留原有的set方法的操做
    _progressValue = progressValue; // 重繪視圖
 [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { UIBezierPath *path = [UIBezierPath bezierPath]; //圓顯示在屏幕中心
    CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); [path addArcWithCenter:center radius :(self.bounds.size.width-20)/2 startAngle:M_PI_2*3 endAngle:self.progressValue*2*M_PI+M_PI_2*3 clockwise:YES]; if (self.progressColor) {//設置了即爲設置後的顏色,若是沒設置就顯示默認的藍色
 [self.progressColor setStroke]; }else{ [[UIColor blueColor] setStroke]; } path.lineWidth = 8; [path stroke]; } @end   4.5繪製曲線 【Demo4_BezierPath_Curve】 MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(140, 40)]; 起始座標 第一個拉伸的點 [path addCurveToPoint:CGPointMake(40, 180) controlPoint1:CGPointMake(40, 40) controlPoint2:CGPointMake(140, 180)]; [path addCurveToPoint:CGPointMake(140, 320) controlPoint1:CGPointMake(140, 180) controlPoint2:CGPointMake(40, 320)]; [[UIColor redColor] setStroke]; path.lineWidth = 6; [path stroke]; } @end4.6繪製其餘圖形 (矩形,圓形,橢圓) 【Demo5_BezierPath_Others】 MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { //繪製圓角矩形 // UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40, 40, 200, 150) cornerRadius:10]; //圓形
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(40, 40, 200, 200)]; [[UIColor redColor] setStroke]; [[UIColor greenColor] setFill]; path.lineWidth = 8; [path fill]; [path stroke]; } @end  5.繪製字符串 【Demo6_Draw_String】 使用NSString帶有的繪製方法完成: drawAtPoint: drawInRect: 根據字符串的內容計算對應的高度: boundingRectWithSize: MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { NSString *str = @"Hello World"; //設置字符串的格式
    NSDictionary *strAttributes = @{ NSFontAttributeName:[UIFont systemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; [str drawAtPoint:CGPointMake(40, 40) withAttributes:strAttributes]; //長字符串的繪製
    NSString *str2 = @"looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog String"; //計算出該字符串所佔的空間大小 //計算字符串的高
    CGRect strRect = [str2 boundingRectWithSize:CGSizeMake(250, 999) options:2 attributes:strAttributes context:nil]; [str2 drawInRect:CGRectMake(40, 80,250,strRect.size.height) withAttributes:strAttributes]; } @end6.繪製圖片 【Demo7_Draw_Image】 UIImage *image = [UIImage imageNamed:@"icon80.png"]; [image drawAtPoint:CGPointMake(50, 50)];//按圖片原始大小顯示
    [image drawInRect:imageRect];//根據設定的範圍對圖片進行縮放
MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { CGRect imageRect = CGRectMake(50, 50, 200, 200); UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:imageRect]; //按照路徑剪切
 [path addClip]; UIImage *image = [UIImage imageNamed:@"icon80.png"]; //[image drawAtPoint:CGPointMake(50, 50)];
 [image drawInRect:imageRect]; } @end  做業: 1.參考資源1,繪製聊天氣泡 寫一個視圖類:MessageView +message:NSString 要求: a。只作保持在視圖右上角的狀況 b。最寬不能超過200,高度根據消息的內容來計算 ViewController.h #import <UIKit/UIKit.h>

@interface ViewController : UIViewController @end ViewController.m #import "ViewController.h"
#import "TRMessageView.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; TRMessageView *view = [[TRMessageView alloc]initWithMessage:@"中文測試一下總體到了屏幕的右側會是什麼樣子呢?"]; view.frame = CGRectMake(0, 20, 320, view.height); [self.view addSubview:view]; TRMessageView *view2 = [[TRMessageView alloc]initWithMessage:@"你來我往的對話中,爲何會有一條灰色的這麼難看的橫線顯示在哪裏呢?"]; view2.frame = CGRectMake(0, 20+view.height, 320, view2.height); [self.view addSubview:view2]; } @end TRMessageView.h #import <UIKit/UIKit.h>

@interface TRMessageView : UIView @property(nonatomic,readonly)CGFloat height; -(instancetype)initWithMessage:(NSString *)message; @end TRMessageView.m #import "TRMessageView.h"

@interface TRMessageView() @property(nonatomic,strong)NSString *message; @property(nonatomic)CGFloat messageWidth; @property(nonatomic)CGFloat messageHeight; @property(nonatomic,readwrite)CGFloat height; @end


@implementation TRMessageView -(instancetype)initWithMessage:(NSString *)message{ self = [super init]; if (self) { self.message = message; CGRect msgRect = [self.message boundingRectWithSize:CGSizeMake(200, 999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:15] } context:nil]; self.messageWidth = msgRect.size.width; self.messageHeight = msgRect.size.height; self.height = 40+self.messageHeight; self.backgroundColor = [UIColor whiteColor]; } return self; } - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); //繪製氣泡
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(280-self.messageWidth, 10, self.messageWidth+20, self.messageHeight+20) cornerRadius:10]; [path moveToPoint:CGPointMake(300, self.messageHeight+20)]; [path addLineToPoint:CGPointMake(310, 30+self.messageHeight)]; [path addLineToPoint:CGPointMake(290, 30+self.messageHeight)]; [[UIColor lightGrayColor] setFill]; [path fill]; CGContextRestoreGState(context); CGContextSaveGState(context); //繪製字符串
    [self.message drawInRect:CGRectMake(290-self.messageWidth, 20, self.messageWidth, self.messageHeight) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor whiteColor]}]; } @end2.繪製餅圖 寫一個視圖類: PieChartView +radius:CGFloat半徑 +width:CGFloat 線寬 +data:NSArray數據 +[item]: PieChartViewItem PieChartViewItem +color:UIColor 顏色 +value:CGFloat  0~1 佔整體的百分比 TRPieChartViewItem.h #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TRPieChartViewItem : NSObject @property(nonatomic,strong)UIColor *color; @property(nonatomic)CGFloat value; -(instancetype)initWithColor:(UIColor *)color andValue:(CGFloat)value; @end TRPieChartViewItem.m #import "TRPieChartViewItem.h"

@implementation TRPieChartViewItem - (instancetype)initWithColor:(UIColor *)color andValue:(CGFloat)value{ self = [super init]; if (self) { self.color = color; self.value = value; } return self; } @end TRPieChartView.h #import <UIKit/UIKit.h>

@interface TRPieChartView : UIView @property(nonatomic)CGFloat radius; @property(nonatomic)CGFloat lineWidth; @property(nonatomic,strong)NSArray *data; @end TRPieChartView.m #import "TRPieChartView.h"
#import "TRPieChartViewItem.h"

@implementation TRPieChartView -(NSArray *)data{ if (!_data) { TRPieChartViewItem *item1 = [[TRPieChartViewItem alloc]initWithColor:[UIColor redColor] andValue:0.25]; TRPieChartViewItem *item2 = [[TRPieChartViewItem alloc]initWithColor:[UIColor blueColor] andValue:0.5]; TRPieChartViewItem *item3 = [[TRPieChartViewItem alloc]initWithColor:[UIColor blackColor] andValue:0.15]; TRPieChartViewItem *item4 = [[TRPieChartViewItem alloc]initWithColor:[UIColor greenColor] andValue:0.1]; _data = @[item1,item2,item3,item4]; } return _data; } -(CGFloat)lineWidth{ if (!_lineWidth) { _lineWidth = 10; } return _lineWidth; } -(CGFloat)radius{ if (!_radius) { _radius = 100; } return _radius; } - (void)drawRect:(CGRect)rect { CGFloat startAngel = M_PI_2*3; for (TRPieChartViewItem *item in self.data) { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); UIBezierPath *path = [UIBezierPath bezierPath]; // 畫弧線
        [path addArcWithCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) radius:self.radius startAngle:startAngel endAngle:(item.value*2*M_PI+startAngel) clockwise:YES]; startAngel +=item.value*2*M_PI; //畫直線
        [path addLineToPoint:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; //線寬
        path.lineWidth = self.lineWidth; path.lineCapStyle = kCGLineCapButt; //填充色
 [item.color setFill]; //線條顏色 //[[UIColor grayColor] setStroke]; //繪製填充邊線
 [path fill]; //[path stroke];
 CGContextRestoreGState(context); CGContextSaveGState(context); } } @end3.自定義Cell,圖片是圓角的 新聞客戶端中的自定義Cell,裏面的圖片作成圓角的 =============================================================== 知識點 2、貼圖、美化 1. iOS的設備的種類 1.1設備的分辨率和座標系大小(2倍關係) 1.2Retina屏設備對圖片的處理 a。程序中的圖片:在不一樣尺寸的圖片名稱上添加@2x 或 @3x這樣的標識便可。系統會根據當前設備的不一樣,來選擇加載哪一個版本的圖片 b。AppIcon應用程序圖標:屏幕上有一個尺寸,設置界面上也有圖標,搜索結果中也有圖標,設定圖片資源庫中的AppIcon裏面不一樣尺寸的圖片後,完成設置 2、9切片技術 2.1 爲何須要9切片(9 Slice技術) 用代碼來實現基於一個簡單圖片,產生不一樣尺寸的圖片的一種手段 2.2切片原則 4個角不變,中間部分能夠橫向或縱向拉伸或複製 兩種模式:Tile 切片複製 (默認模式) Stretch切片拉伸 2.3 實現方法 a。利用xcode工具中的圖片資源庫中的9切片功能 b。編寫代碼實現切片 如: #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *btnImageView; 和故事版中的image連線 @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *btnImage = [[UIImage imageNamed:@"delete_btn"] resizableImageWithCapInsets:UIEdgeInsetsMake(9, 12, 9, 12) resizingMode:UIImageResizingModeStretch]; 編代碼實現九切片功能 self.btnImageView.image = btnImage; } @end

3. 對控件的貼圖美化 3.1 UIButton 四種狀態的設置:經過代碼或故事板 四種狀態的切換: Normal:正常 Highlighted:高亮,按下後不擡起的狀態 Selected:經過修改selected屬性設置 .selected=YES(按鈕被選中) Disabled:經過修改enabled屬性設置 .enabled=NO(按鈕不可用狀態) - (IBAction)changeState:(UIButton *)sender { 將按鈕連線,用代碼修改 [self.button setSelected:!sender.selected];//連續點擊,持續變化 // [sender setSelected:YES];//是否改變,只變化一次 //sender setEnabled:YES // 按鈕擺在那不動:normal // 點下,不擡起:highLighted // 點下,鬆手:normal // 進入到seleted狀態:用代碼修改seleted屬性 // enabled狀態:用代碼改
} 以下:view+image+button+field,經過故事板實現便可,不須要編程  3.2 UISlider setMaximumTrackImage:設置滑動過的區域的背景圖 setMinimumTrackImage:設置未滑動到的區域的背景圖 setThumbImage:設置滑塊中拖動按鈕部分的圖片 如: - (void)viewDidLoad { [super viewDidLoad]; [self.slider setMaximumTrackImage:[[UIImage imageNamed:@"playing_volumn_slide_foreground"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 4, 4, 4) resizingMode:UIImageResizingModeTile]forState:UIControlStateNormal]; [self.slider setMinimumTrackImage:[UIImage imageNamed:@"playing_volumn_slide_bg"] forState:UIControlStateNormal]; [self.slider setThumbImage:[UIImage imageNamed:@"playing_volumn_slide_sound_icon"] forState:UIControlStateNormal]; } 4. tintColor 統一管理一個視圖中全部子視圖和子視圖的子視圖的顏色,批量修改一些視圖的顏色 1.顏色受控制的因素 擁有 xxxTintColor屬性,如UISwitch,可使用屬性修改 沒有xxxTintColor,受從UIView中繼承來的tintColor影響 2.self.window.tintColor影響整個應用的風格,除非某一個視圖特別設置了本身的tintColor顏色 5. UIAppearance 遵照此協議的對象,能夠批量設置某種控件的外觀(顏色、貼圖等)(只針對某一類控件) 1.獲取方式 +(instancetype)appearance; 2.使用方式 拿到此對象後,經過這個對象設置背景、顏色等來批量設置某一類控件的外觀 [ [ UISlider appearance] setTintColor: [ UIColor redColor ] ] 如: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[UISlider appearance]setTintColor:[UIColor purpleColor]]; [[UIButton appearance]setBackgroundImage:[UIImage imageNamed:@"delete_btn"] forState:UIControlStateNormal]; return YES; } 6. UINavigationBar美化 6.1 設置NavigationBar的顏色 //設置導航欄的背景色
            naviBar.barTintColor = [UIColor blackColor]; //設置是否透明
        naviBar.translucent = YES; 6.2 給NavigationBar貼圖 //設置背景圖(圖片的高度,豎屏時通常設置爲64個點,橫屏時高度是52個點)
    [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarDefault"] forBarMetrics:UIBarMetricsDefault];豎屏顯示 [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarLandscapePhone"] forBarMetrics:UIBarMetricsLandscapePhone];橫屏顯示 6.3 設置返回按鈕的圖片 naviBar.backIndicatorImage = [UIImage imageNamed:@"back_btn"]; naviBar.backIndicatorTransitionMaskImage =[UIImage imageNamed:@"back_btn"]; naviBar.tintColor = [UIColor redColor];設置按鈕顏色 6.4 設置標題欄的文字字體 naviBar.titleTextAttributes = @{ NSFontAttributeName:[UIFont boldSystemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; 6.5 設置標題爲任意視圖 UIStepper *stepper = [[UIStepper alloc]init]; self.navigationItem.titleView = stepper; 6.6 設置狀態欄風格 (顯示電池欄的風格) //重寫方法,用於設置狀態的風格
- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } 6.7 是否顯示狀態欄 //重寫方法,設置狀態欄隱藏
- (BOOL)prefersStatusBarHidden { return YES; } 6.8 隱藏NavigationBar [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UINavigationBar *naviBar = self.navigationController.navigationBar; naviBar.barTintColor = [UIColor blackColor]; naviBar.translucent = YES; //設置背景圖
    [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarDefault"] forBarMetrics:UIBarMetricsDefault]; [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarLandscapePhone"] forBarMetrics:UIBarMetricsLandscapePhone]; //設置返回按鈕的的圖片
    naviBar.backIndicatorImage = [UIImage imageNamed:@"back_btn"]; naviBar.backIndicatorTransitionMaskImage =[UIImage imageNamed:@"back_btn"]; naviBar.tintColor = [UIColor redColor]; //設置標題欄的文字字體
    naviBar.titleTextAttributes = @{ NSFontAttributeName:[UIFont boldSystemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; //設置標題爲其餘視圖 //UITextField *textField = [[UITextField alloc]init];
    UIStepper *stepper = [[UIStepper alloc]init]; self.navigationItem.titleView = stepper; } - (IBAction)hideNavigationBar:(UIButton *)sender { [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; } @end GreenViewController.h GreenViewController.m #import "GreenViewController.h"

@interface GreenViewController () @end

@implementation GreenViewController //重寫方法,用於設置狀態的風格
- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } //重寫方法,設置狀態欄隱藏
- (BOOL)prefersStatusBarHidden { return YES; }    點擊item獲得的界面 7. UITableViewCell的背景貼圖 實現步驟: a。故事板中修改TableView的分割線(Separator)爲None b。故事板中修改TableViewCell的背景色(Background)爲clearColor c。cell.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"list"]]; cell.selectedBackgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"listSeleted」]];選中後的背景圖設置顯示 如: MyTableViewController.h MyTableViewController.m #import "MyTableViewController.h" 
@interface MyTableViewController () @end

@implementation MyTableViewController - (void)viewDidLoad { [super viewDidLoad]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; cell.textLabel.text = @"Hello World"; cell.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"list"]]; cell.selectedBackgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"listSelected"]]; return cell; }  格顯示的是虛線 做業: 聊天氣泡: 用9slicing實現 類:MessageView +message:NSString +fromMe:BOOL +messageLabel:UILabel +messagePopImageView:UIImageView//圖,切片
 效果: a。屏幕最上方添加一個文本框和一個發送按鈕 b。屏幕下方已經存在一些聊天的消息,其中本身說的內容在屏幕右側,對方說的內容在屏幕的左側 c。在文本框中輸入內容後,算做本身說的內容,而後點擊發送按鈕,在界面中追加一個氣泡,在屏幕的右側,裏面顯示文本框中輸入的內容,而且鍵盤收起,文本框內容清空 -(void)refresh{ if(fromMe) 顯示藍色的氣泡在右上角 大小根據message屬性計算 else 顯示灰色的氣泡在左上角 大小,計算 } 參考:H02資源包 追加:看Apple官方的NavigationBar的demo ===================================================================== 知識點 3、手勢(UIGestureRecognizer)、變形 1.手勢(GestureRecognizer) 1.1什麼是手勢 用戶在view上的一些觸屏操做,諸如 點、滑動、捏合。。。 1.2 手勢的分類 a。一次性手勢 觸屏動做發生之後,方法只會響應一次。如:點擊如下屏幕、解鎖動做 b。連續性手勢 觸屏動做發生之後,方法會連續響應屢次。如:長按、捏合、移動、旋轉 1.3 手勢的本質 本質是一個對象,當用戶針對視圖發生了必定的動做以後,系統會檢測到該動做,並根據具體的動做建立不一樣種類的手勢對象,該對象中會存儲與動做有關的一些數據,如觸屏動做的座標點、滑動的快慢、移動的距離。 若是發生的是一次性手勢動做,那麼就調用一次方法,若是發生的是連續性手勢動做,那麼就屢次調用響應方法 1.4 如何使用手勢 step1:建立手勢對象 step2:設置與該種手勢相關的屬性 step3:將手勢對象與須要檢測的視圖關聯在一塊兒 1.5 具體的手勢種類 全部手勢的父類:UIGestureRecognizer 6種手勢: UIXXXGestureRecognizer UITapGestureRecognizer 點擊一下屏幕 UISwipeGestureRecognizer 輕掃屏幕,如解鎖 UIPinchGestureRecognizer 捏合手勢 UIPanGestureRecognizer 移動手勢 UILongPressGestureRecognizer 長按手勢 UIRotationGestureRecognizer 旋轉手勢 2.具體的手勢使用 2.1 UITapGestureRecognizer (一次性手勢) 【Demo1_TapGestureRecognizer】 經常使用屬性: .numberOfTapsRequired 設置點擊數 手指點幾下 .numberOfTouchesRequired 設置觸點數 幾個手指點擊 CGPoint location=[gr locationInView:self.view];獲取點擊動做時,出點的絕對座標 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //step1 建立手勢對象
    UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; //step2 設置手勢的屬性
    tapGR.numberOfTapsRequired = 1; tapGR.numberOfTouchesRequired = 1; //step3 將手勢與視圖關聯起來
 [self.view addGestureRecognizer:tapGR]; } -(void)tap:(UITapGestureRecognizer *)gr { CGPoint location = [gr locationInView:self.view]; NSLog(@"(%.2f,%.2f)",location.x,location.y); } @end

    2.2 UISwipeGestureRecognizer(一次性手勢) 【Demo2_SwipeGestureRecognizer】 經常使用屬性: .numberOfTouchesRequired觸點的個數 .direction 輕掃的方向 注意:direction屬性爲枚舉值,而且是能夠進行組合的枚舉值,多個枚舉值之間使用 「|」按位「或」進行運算。 補充:1<<? 表達式的含義是:對於二進制的數字1進行向左移位,符號右側是幾,就向左移動幾位。 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)]; swipeGR.numberOfTouchesRequired = 1; //設置輕掃動做的方向
    swipeGR.direction = UISwipeGestureRecognizerDirectionLeft|UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:swipeGR]; } -(void)swipe:(UISwipeGestureRecognizer *)gr{ NSLog(@"swipe... ..."); } @end

    2.3 UILongPressGestureRecognizer(連續性手勢) 【Demo3_LongPressGestureRecognizer】 經常使用屬性: longGR.minimumPressDuration = 1;//設置最少按下的持續時間
 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)]; //設置最少按下的持續時間
    longGR.minimumPressDuration = 1; [self.view addGestureRecognizer:longGR]; } -(void)longPress:(UILongPressGestureRecognizer *)gr{ NSLog(@"long press... ..."); } @end

    2.4 UIPinchGestureRecognizer(連續性手勢,捏合) 【Demo4_PinchGestureRecognizer】 CGFloat scale = gr.scale; //手勢的變化比率,向外擴展時,爲大於1的數,向內捏合時,爲小與1的數
   CGFloat velocity = gr.velocity;//手勢的變化速率,向外擴展時,爲正數,向內捏合時,爲負數
 以上兩個屬性不是用來設置的,而是在手勢發生時用來讀取的。 練習: 界面上 有一個UITextView,看小說,增長手勢識別,若是快速擴,小說出現,快速捏,小說隱藏,速度不快時,表明放大或縮小小說的文字大 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UITextView *textView;//連線

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView.editable = NO; UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; [self.view addGestureRecognizer:pinchGR]; } -(void)pinch:(UIPinchGestureRecognizer *)gr{ CGFloat scale = gr.scale;比率 CGFloat velocity = gr.velocity; 速率 //NSLog(@"scale=%.2f,velocity=%.2f",scale,velocity);
    if (velocity > 6) { self.textView.hidden = NO; } else if (velocity < -6){ self.textView.hidden = YES; } else{ // 改變字體
        self.textView.font = [UIFont systemFontOfSize:17*scale]; } } 2.5 UIRotationGestureRecognizer (連續性手勢,旋轉) 【Demo5_RotationGestureRecognizer】 經常使用屬性: CGFloat rotation = gr.rotation; 表明手勢旋轉的弧度。順時針旋轉時,爲正數,逆時針旋轉時爲負數 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView;//image上添加圖片

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; [self.view addGestureRecognizer:rotationGR]; } -(void)rotation:(UIRotationGestureRecognizer *)gr{ //CGFloat rotation = gr.rotation; //NSLog(@"%.2f",rotation); //實現圖片的選轉
    self.imageView.transform = CGAffineTransformMakeRotation(gr.rotation); } @end
    
    2.6 UIPanGestureRecognizer(連續性手勢,拖動) 【Demo6_PanGestureRecognizer】 經常使用屬性: //獲取移動到的位置在視圖座標系中的絕對位置
    CGPoint location = [gr locationInView:self.view]; //獲取移動到的新位置相對於移動動做起始點的座標的橫縱向的偏移
    CGPoint translation = [gr translationInView:self.view]; ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.view addGestureRecognizer:panGR]; } -(void)pan:(UIPanGestureRecognizer *)gr{ //獲取移動到的位置在視圖座標系中的絕對位置
    CGPoint location = [gr locationInView:self.view]; //獲取移動到的新位置相對於移動動做起始點的座標的橫縱向的偏移
    CGPoint translation = [gr translationInView:self.view]; self.myImageView.transform=CGAffineTransformMakeTranslation(translation.x, translation.y);//相對
    NSLog(@"location:(%.2f,%.2f) translation:(%.2f,%.2f)",location.x,location.y,translation.x,translation.y); } @end

3.變形(Transform) 3.1什麼是變形 視圖發生了位移、縮放、旋轉這樣的變化叫作變形。 3.2 如何實現變形? 經過修改視圖對象的.transform屬性完成變化的效果 位移:translation 縮放:scale 旋轉:rotation 3.3 transform屬性 類型:CGAffineTransform(仿射)類型的結構體 結構體中包含了6個可變的值和3個定值組成的 3 X 3的矩陣,修改了6個數據中的某一個或某幾個就能夠實現變形,實際上這6個數很難計算,藉助於一些系統的API實現數值的改變。 3.4 修改transform屬性的API 位移變換:CGAffineTransformMakeTranslation() 相對最原始變化的 CGAffineTransformTranslate() 相對修改後變化的 縮放變換:CGAffineTransformMakeScale() CGAffineTransformScale() 旋轉變換:CGAffineTransformMakeRotation() CGAffineTransformRotate() 回到原始狀態: CGAffineTransformIdentity 重點注意:變形與自動佈局是衝突的,因此在使用變形時,必定要關閉AutoLayout,不關閉的話,產生的效果沒法預計。 【Demo7_Transform】 界面建立後,沒有作任何變形以前,系統會將每個視圖當前的transform記錄到一個常量中CGAffineTransformIdentity,當使用Makexxx()方法進行仿射變換,計算新的矩陣,都是基於這個常量進行變形計算的。當使用沒有Make的那組方法時,每次計算新的矩陣都是以傳入的transform的值做爲基準。 3.5 transform屬性的初始常量 CGAffineTransformIdentity 如:經過點擊按鈕實現圖片變化 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //位移
- (IBAction)translation:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeTranslation(0, 350);
    self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, 3, 3); //self.imageView.center = CGPointMake(self.imageView.center.x+2, self.imageView.center.y+2);
} //縮放
- (IBAction)scale:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, 1.2, 1.2); } //旋轉
- (IBAction)rotation:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeRotation(M_PI_4);
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, -M_PI_4); } //回到原始位置
- (IBAction)identity:(UIButton *)sender { self.imageView.transform = CGAffineTransformIdentity; } @end4.手勢+變形 4.1 使用pan手勢實現位移 CGPoint translation = [gr translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; //將這一次移動的偏移量歸零
 [gr setTranslation:CGPointZero inView:self.view]; 4.2 使用pinch手勢實現縮放變形 // 實現圖片的縮放
     self.imageView.transform = CGAffineTransformScale(self.imageView.transform,gr.scale, gr.scale); gr.scale = 1;// 

    4.3 使用rotation手勢實現旋轉變形            // 實現圖片的旋轉
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation); gr.rotation = 0; 4.4 多手勢共存的問題 解決步驟: a。遵照協議 b。設置各個手勢的代理 c。實現一個方法 (遵照協議時點開發放尋找粘貼過來便可) - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } 5.在storyboard中實現手勢 【Demo8_GestureRecognizer_Storyboard】 1.從資源庫中拖拽某種類型的手勢對象到視圖中 2.若是拖拽時就想與某視圖關聯起來,那麼就把手勢對象拖到視圖中,若是不想關聯,那麼就拖拽到場景的資源條上 3.選中要關聯的視圖,按住control,連線到場景的資源條上的手勢對象 4. TransformViewController.m #import "TransformViewController.h"

@interface TransformViewController ()<UIGestureRecognizerDelegate> //遵照協議
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation TransformViewController - (void)viewDidLoad { [super viewDidLoad]; //pan手勢
    UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.view addGestureRecognizer:panGR]; //pinch手勢
    UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; //設置pinch的代理
    pinchGR.delegate = self; [self.view addGestureRecognizer:pinchGR]; //rotation手勢
    UIRotationGestureRecognizer *rotationGR = [[ UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; //設置rotation的代理
    rotationGR.delegate = self; [self.view addGestureRecognizer:rotationGR]; } -(void)pan:(UIPanGestureRecognizer *)gr{ //實現圖片的位移 //CGPoint location = [gr locationInView:self.view];
    CGPoint translation = [gr translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; //將這一次移動的偏移量歸零
 [gr setTranslation:CGPointZero inView:self.view]; } -(void)pinch:(UIPinchGestureRecognizer *)gr{ // 實現圖片的縮放
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform,gr.scale, gr.scale); gr.scale = 1; } -(void)rotation:(UIRotationGestureRecognizer *)gr{ // 實現圖片的旋轉
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation); gr.rotation = 0; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } @end  【綜合練習】: 圖片查看器: 1)使用代碼想view中添加一個UIImageView對象,UIImageView的大小和圖片大小一致,找一張大圖(用大象) 2)使用center屬性將ImageView移動到屏幕的中央 3)使用transform屬性將imageView縮放到屏幕恰好能顯示的下正常圖片的內容,且保持寬高比 4)對imageView增長rotation手勢,支持圖片旋轉 5)對imageView增長pinch手勢,支持圖片的縮放 6)對imageView增長pan手勢,支持圖片的移動 7)對imageView增長tap手勢,牀架回到到第3步 注意:手勢不要添加到self.view,要添加到圖片上,記得打開imageView的用戶交互(.userInteractionEnable=YES) 做業: ViewController.m #import "ViewController.h"

@interface ViewController ()<UIGestureRecognizerDelegate>//遵照協議
 @property(nonatomic,strong)UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //建立ImageView
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]]; self.imageView = imageView; //設置初始的狀態
 [self loadImageView]; //添加
 [self.view addSubview:imageView]; //開啓交互
    imageView.userInteractionEnabled = YES; //設置手勢
    UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; tapGR.numberOfTapsRequired = 2; [self.imageView addGestureRecognizer:tapGR]; UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; pinchGR.delegate = self; [self.imageView addGestureRecognizer:pinchGR]; UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.imageView addGestureRecognizer:panGR]; UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; rotationGR.delegate =self; [self.imageView addGestureRecognizer:rotationGR]; } -(void)loadImageView{ //設置中心點
    self.imageView.center = self.view.center; CGFloat scaleX = self.view.bounds.size.width/self.imageView.bounds.size.width; CGFloat scaleY = self.view.bounds.size.height/self.imageView.bounds.size.width; self.imageView.transform = CGAffineTransformMakeScale(MIN(scaleX, scaleY), MIN(scaleX, scaleY)); } //移動
-(void)pan:(UIPanGestureRecognizer *)panGR{ CGPoint translation = [panGR translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; [panGR setTranslation:CGPointZero inView:self.view]; } //縮放
-(void)pinch:(UIPinchGestureRecognizer *)pinchGR{ self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinchGR.scale, pinchGR.scale); pinchGR.scale = 1; } //旋轉
-(void)rotation:(UIRotationGestureRecognizer *)rotationGR{ self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotationGR.rotation); rotationGR.rotation = 0; } //回到起始點中心點
-(void)tap:(UITapGestureRecognizer *)gr{ [self loadImageView]; } //實現旋轉和縮放同時實現的方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } @end  www.raywenderlich.com 2.根據文檔,把一個TableCell實現移動。 長按Cell後,拖到哪裏就放在哪裏 ==================================================================== 知識點 5、座標系、觸控 1.座標系(frame、bounds、center、transform) 1.1 frame屬性 【Demo1_Frame_Bounds_Center_Transform】 a。什麼是frame? 類型:CGRect結構體類型 做用:該視圖左頂點在父視圖的座標系中的位置,以及,該視圖在父視圖中佔據的寬和高 b。直接修改了frame屬性時,其餘屬性如何變化? bounds:會被改變 center:會被改變 transform:不會被改變 c。何時使用到frame? 當把一個視圖添加到父視圖中時,必定要重設定frame屬性 1.2 bounds屬性 (相對與本身的) a。什麼是bounds屬性? 類型:CGRect結構體類型 做用:描述的是該視圖的座標系頂點的值,以及該視圖自身的大小 b。直接修改了bounds屬性時,其餘屬性如何變化? frame: 會被改變 center:不會被改變 transform:不會被改變 c。何時使用bounds屬性? 當須要定位視圖時,要讀取父視圖的大小,那麼就是用父視圖的bounds 當修改視圖內的子視圖的位置時,能夠修改視圖的bounds的座標起點,從而讓子視圖的位置發生偏移,實現移動的效果 #import "OtherViewController.h"

@interface OtherViewController () @end

@implementation OtherViewController - (void)viewDidLoad { [super viewDidLoad]; UIView *view1=[[UIView alloc]initWithFrame:CGRectMake(100, 200, 80, 100)]; view1.backgroundColor=[UIColor redColor]; [self.view addSubview:view1]; } - (IBAction)button:(UIButton *)sender { [self.view setBounds:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y+10, self.view.bounds.size.width, self.view.bounds.size.height)]; } @end 點擊按鈕,圖片垂直向上移動 1.3 center屬性 a。什麼是center屬性? 類型:CGPoint結構體類型 做用:描述的是該視圖的中心點,在父視圖座標中的位置 b。直接修改了center屬性時,其餘屬性如何變化? frame:會被改變 bounds:不會被改變 transform:不會被改變 c。何時用center? 須要修改視圖的位置,也就是位移時,須要修改center 1.4 transform屬性 a。什麼是transform屬性? 類型:CGAffineTransform結構體類型 做用:描述該視圖的變形狀態 b。直接修改了transform屬性時,其餘屬性如何變化? frame:會 bounds:不會 center:不會 c。結論: 變形前,frame和bounds保持變化的一致性,變形後,frame表明的是在視圖中表現出來的外觀,因此會隨着變形而記錄不一樣的外觀狀態,但bounds不是用來表現的,只是記錄大小的,因此不會改變,bounds的座標系也不會改變 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self print]; } //直接修改frame
- (IBAction)changFrame:(UIButton *)sender { CGRect frame=self.imageView.frame; frame.origin.x+=4; frame.origin.y+=4; frame.size.width+=4; frame.size.height+=4; self.imageView.frame=frame; [self print]; } //直接修改bounds
- (IBAction)changeBounds:(UIButton *)sender { CGRect bounds=self.imageView.bounds; //bounds.origin.x+=4; // bounds.origin.y+=4;
    bounds.size.width+=4; bounds.size.height+=4; self.imageView.bounds=bounds; [self print]; } //直接修改center
- (IBAction)changeCenter:(UIButton *)sender { CGPoint center=self.imageView.center; center.x+=4; center.y+=4; self.imageView.center=center; [self print]; } //直接修改transform
- (IBAction)changeTransform:(UIButton *)sender { self.imageView.transform=CGAffineTransformTranslate(self.imageView.transform, 4, 4); self.imageView.transform=CGAffineTransformScale(self.imageView.transform, 1.3, 1.3); self.imageView.transform=CGAffineTransformRotate(self.imageView.transform, M_1_PI); [self print]; } -(void)print{ NSLog(@"\nframe:%@\nbounds:%@\ncenter:%@\ntransform:%@", NSStringFromCGRect(self.imageView.frame), NSStringFromCGRect(self.imageView.bounds), NSStringFromCGPoint(self.imageView.center), NSStringFromCGAffineTransform(self.imageView.transform)); } @end 點擊了bounds按鈕 原始: frame:{{91, 33}, {112, 100}} bounds:{{0, 0}, {112, 100}} center:{147, 83} transform:[1, 0, 0, 1, 0, 0] 點擊後: frame:{{89, 31}, {116, 104}} bounds:{{0, 0}, {116, 104}} center:{147, 83} transform:[1, 0, 0, 1, 0, 0] 2.觸控(UITouch) 2.1 是什麼? 是一個UITouch類型的對象,當用戶touch視圖時,會自動產生UITouch對象 2.2 如何獲取Touch 須要自定義視圖類,覆蓋類中的指定的方法,在方法中才能獲取到這個Touch對象 2.3 有什麼用? 能夠跟蹤用戶在視圖上手指移動的軌跡,判斷用戶的意圖,以此進行繪圖、塗鴉、手寫等操做 2.4 怎麼用? step1:自定義一個視圖類 step2:重寫類中的方法便可 touchesBegan:withEvent://手指接觸視圖時調用
                        touchesMoved:withEvent://手指在視圖上移動時調用
                        touchesEnded:withEvent://手指離開視圖時調用
 注意:手勢是對觸控的一個封裝 【Demo3_UITouch】 MyView.h(本身建立的類,關聯到VC) #import "MyView.h"
@implementation MyView //手指接觸調用
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch*touch=[touches anyObject]; CGPoint location=[touch locationInView:self]; NSLog(@"手指接觸屏幕:(%.2f,%.2f)",location.x,location.y); } //手指在視圖移動時
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch*touch=[touches anyObject]; CGPoint location=[touch locationInView:self]; NSLog(@"手指在視圖上移動:(%.2f,%.2f)",location.x,location.y); } //離開時
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"手指離開視圖"); } @end 手指接觸屏幕:(147.00,87.00) 手指在視圖上移動:(146.50,89.00) 手指在視圖上移動:(148.50,92.00) 手指離開視圖 練習:簡易畫板 【Demo4_Touch_Paint】 PaintView.h PaintView.m #import "PaintView.h"

@interface PaintView () //記錄全部路徑的可變數組
@property(nonatomic,strong)NSMutableArray *paths; @end

@implementation PaintView - (NSMutableArray *)paths{ if (!_paths) { _paths = [NSMutableArray array]; } return _paths; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ //獲取UITouch對象
    UITouch *touch = [touches anyObject]; CGPoint startPoint = [touch locationInView:self]; // 建立路徑
    UIBezierPath *path = [UIBezierPath bezierPath]; [path setLineWidth:3]; [path moveToPoint:startPoint]; // 將路徑對象記錄到數組屬性中
 [self.paths addObject:path]; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint currentPoint = [touch locationInView:self]; //將剛剛建立的路徑添加一個直線到該點 //從數組中取出最後一個元素,就是剛剛手指落下時 //建立的路徑
    UIBezierPath *currentPath = [self.paths lastObject]; [currentPath addLineToPoint:currentPoint]; //重繪
 [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { //繪製全部路徑
    for (UIBezierPath *path in self.paths) { [path stroke]; } } @end  做業: 1. 作一個界面上畫矩形的效果 按下手指後開始畫,拖動時大小變化,鬆手後定在屏幕上,支持繪製多個矩形 2. 在做業1的基礎上,支持選擇繪製的顏色,支持線條的粗細設置 3. 在做業1或2的基礎上,增長橡皮功能 4. 支持各類形狀—矩形,圓角矩形,橢圓。。。。 ======================================================================================================= 知識點 6、佈局 1.佈局 (Layout)控制器中的view 1.1 什麼是佈局? 是指在一個視圖中如何擺放它的子視圖(安排子視圖的位置和大小) 1.2 爲何要佈局? 屏幕的尺寸會常常發生變化或者隨着設備不一樣,屏幕尺寸也會不一樣,只要屏幕大小發生了變化,座標系也會隨之變化,因而變化前設置的frame在新的座標系中定位就會與期待的不符,因此就須要在屏幕發生變化時從新佈局指定frame 【Demo5_Layout】 1.3 可能致使屏幕大小發生變化的緣由 a。設備不一樣(3.5寸 4存。。。。) b。屏幕方向不一樣 c。狀態欄 隱藏 特殊的狀態欄:來電時,綠色狀態欄 錄音時,紅色狀態欄 開啓我的熱點,藍色狀態欄 d。各類Bar NavigationBar: 44/32 若是設置了prompt,bar會更高 TabBar:49個點高 ToolBar:44/32 個點 iOS7中,導航欄擠佔了狀態欄,高度是64/52 e。鍵盤 彈出時擠佔屏幕,高度不肯定,由於中英文鍵盤的高度不一樣 1.4 如何佈局 方法一:純代碼佈局,古老的方法 理念:當屏幕發生變化時,自動執行一段咱們寫好的代碼,代碼中從新計算了視圖的frame,從而達到在新座標系下從新定位的目的 特色:功能強大,很是繁瑣 方法二:Auto Resizing 之前的一種自動佈局技巧 理念:記錄視圖與父視圖的邊緣爲可調整或固定值,而後屏幕發生變化時,依據這段相對的距離,從新佈局視圖 特色:操做簡單,功能有限 方法三:Auto Layout 最新的自動佈局方法 理念:將視圖與視圖之間的位置以及視圖自身的大小,用多個約束來記錄,當屏幕發生變化時,系統根據定好的約束,自動計算知足該約束狀況下的新的座標值,而後調整位置 特色:簡單易用 注意:以上的佈局方式,選擇其一使用。 4. 純代碼佈局 4.1 理念:在屏幕大小發生變化時,經過代碼的方式改變視圖的frame 4.2 重寫控制器中方法:viewDidLayoutSubviews:便可 該方法,在屏幕發生變化時,由系統自動調用,因此,改變frame的代碼寫在這個方法中就會被自動執行了。 注意:使用純代碼佈局時,必定要關閉AutoLayout,不然代碼可能會無效 【Demo5_Layout】 【練習】 1.兩個等寬的按鈕,高40,有背景色 ——————————————— |               20                    20             |
            |-20-[button1]-10-[button2]-20-|
    2.在1的基礎上,加一個大小會變化的ImagView(內有圖片) imageView離屏幕上、下、左、右保持70,502020
    3.在2的基礎上,增長三個按鈕,大小是20X20,永遠排列在屏幕的右下角 【b1】-10-【b2】-10-【b3】-20-|
                             20                20                20          | ———————————————| b1,2,3離下邊緣都是20個點 時間:半個小時 補充: 關掉AutoLayout之後,drawRect方法中針對視圖繪製的圖形在屏幕旋轉時會被拉伸,解決該問題的話,須要設置視圖的「contentMode」設置爲「redraw」便可 解決方法:設置視圖的的contentMode爲redraw便可 ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *button1; @property (weak, nonatomic) IBOutlet UIButton *button2; @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UIButton *b1; @property (weak, nonatomic) IBOutlet UIButton *b2; @property (weak, nonatomic) IBOutlet UIButton *b3; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10)/2; CGRect frame = CGRectMake(20, 20, buttonWidth, 40); self.button1.frame = frame; frame.origin.x += buttonWidth + 10; self.button2.frame = frame; frame.size = CGSizeMake(self.view.bounds.size.width-20-20, self.view.bounds.size.height-70-50); frame.origin = CGPointMake(20, 70); self.imageView.frame = frame; frame.size = CGSizeMake(20, 20); frame.origin = CGPointMake(self.view.bounds.size.width-20-20, self.view.bounds.size.height-20-20); self.b3.frame =frame; frame.origin.x -= (10+20); self.b2.frame = frame; frame.origin.x -= (10+20); self.b1.frame = frame; } @end 故事板中的界面隨意佈局就好,作一個控件的建立就行了 2.UIView對內部的子視圖的佈局(典型應用:TableViewCell對內部子視圖的佈局) 1.1 如何實現? step1:自定義視圖,繼承自UIView step2:重寫自定義視圖的方法 a。 viewWillLayoutSubViews b。 layoutSubViews c。 viewDidLayoutSubView 方法執行的順序:a->b->c 通常重寫 layoutSubViews方法便可。 練習:音樂列表 【Demo1_TableViewCell_Layout】 Mondel TRMusic.h #import <Foundation/Foundation.h>

@interface TRMusic : NSObject @property (nonatomic, copy) NSString * name;//歌曲名
@property (nonatomic, copy) NSString * album;//專輯
@property (nonatomic, copy) NSString * artist;//藝術家
 @property (nonatomic) NSTimeInterval duration;//時長
 @property (nonatomic) BOOL highQuality;//高品質
@property (nonatomic) BOOL downloaded;//下載

@end TRMusic.m #import "TRMusic.h"

@implementation TRMusic @end TRMusicGroup.h #import <Foundation/Foundation.h>
#import "TRMusic.h" typedef NS_ENUM(NSInteger, TRMusicGroupState) { TRMusicGroupStateNormal, //音樂組的狀態
 TRMusicGroupStateDownloading, TRMusicGroupStateDownloaded }; @interface TRMusicGroup : NSObject @property (nonatomic, copy) NSString * name;//組名字
 @property (nonatomic, strong) NSArray * musics;//多個音樂
 @property (nonatomic) TRMusicGroupState state;//狀態

+ (NSArray *) fakeData; @end TRMusicGroup.m #import "TRMusicGroup.h"

@implementation TRMusicGroup + (NSArray *) fakeData { NSMutableArray * musics = nil; TRMusic * music = nil; musics = [NSMutableArray array]; music = [[TRMusic alloc] init]; music.name = @"Burn"; music.album = @"Burn - Single"; music.artist = @"Ellie Goulding"; music.duration = [self durationWithMinutes:3 andSeconds:51]; music.downloaded = YES; music.highQuality = NO; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Summertime Sadness (Cedric Gervais Remix)"; music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single"; music.artist = @"Lana Del Rey"; music.duration = [self durationWithMinutes:6 andSeconds:52]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Spectrum"; music.album = @"Clarity"; music.artist = @"Zedd"; music.duration = [self durationWithMinutes:4 andSeconds:3]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"It's Time"; music.album = @"It’s Time"; music.artist = @"Imagine Dragons"; music.duration = [self durationWithMinutes:4 andSeconds:0]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Dancing in The Moonlight"; music.album = @"Dancing In The Moonlight: The Best Of Toploader"; music.artist = @"Toploader"; music.duration = [self durationWithMinutes:3 andSeconds:53]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; TRMusicGroup * g1 = [[TRMusicGroup alloc] init]; g1.name = @"國外單曲"; g1.musics = [musics copy]; g1.state = TRMusicGroupStateDownloaded; musics = [NSMutableArray array]; music = [[TRMusic alloc] init]; music.name = @"你有本事搶男人"; music.album = @"好大的膽子"; music.artist = @"雪姨"; music.duration = [self durationWithMinutes:3 andSeconds:18]; music.downloaded = NO; music.highQuality = NO; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"餵雞"; music.album = @"六十年代生人"; music.artist = @"劉歡"; music.duration = [self durationWithMinutes:3 andSeconds:41]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"忐忑"; music.album = @"自由鳥"; music.artist = @"龔琳娜"; music.duration = [self durationWithMinutes:4 andSeconds:03]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; TRMusicGroup * g2 = [[TRMusicGroup alloc] init]; g2.name = @"國內神曲"; g2.musics = [musics copy]; g2.state = TRMusicGroupStateNormal; TRMusicGroup * g3 = [[TRMusicGroup alloc] init]; g3.name = @"Calvin Harris 專輯"; g3.musics = @[]; g3.state = TRMusicGroupStateNormal; TRMusicGroup * g4 = [[TRMusicGroup alloc] init]; g4.name = @"Ellie Gounding 專輯"; g4.musics = @[]; g4.state = TRMusicGroupStateNormal; return @[g1, g2, g3, g4]; } + (NSTimeInterval) durationWithMinutes:(int)minutes andSeconds:(int)seconds { return minutes * 60 + seconds; } @end MusilcTableViewController.h #import <UIKit/UIKit.h>
#import "TRMusicGroup.h"
@interface MusilcTableViewController : UITableViewController @property(nonatomic,strong)TRMusicGroup*musicGroup; @end MusilcTableViewController.m #import "MusilcTableViewController.h"
#import "MusicTableViewCell.h"
#import "TRMusic.h"
@interface MusilcTableViewController () @end

@implementation MusilcTableViewController - (void)viewDidLoad { [super viewDidLoad]; } //獲取列表內容
-(TRMusicGroup *)musicGroup{ if (!_musicGroup) { _musicGroup=[TRMusicGroup fakeData][0]; } return _musicGroup; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.musicGroup.musics.count; } /**/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MusicTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MusicCell" forIndexPath:indexPath]; //找出音樂,獲取數據
    TRMusic* music=self.musicGroup.musics[indexPath.row]; //將音樂賦給cell
    cell.music=music; return cell; } @end MusicTableViewCell.h #import <UIKit/UIKit.h>
#import "TRMusic.h"

@interface MusicTableViewCell : UITableViewCell @property(nonatomic,strong)TRMusic*music; @end MusicTableViewCell.m #import "MusicTableViewCell.h"
@interface MusicTableViewCell () //擴展屬性
@property (weak, nonatomic) IBOutlet UILabel *nameLabel; @property (weak, nonatomic) IBOutlet UILabel *durationLabel; @property (weak, nonatomic) IBOutlet UILabel *artistLabel; @property (weak, nonatomic) IBOutlet UIImageView *downloadedImageView; @property (weak, nonatomic) IBOutlet UIImageView *highQualityImageView; @end

@implementation MusicTableViewCell //重寫set方法
-(void)setMusic:(TRMusic *)music{ _music = music; //將music的各個屬性放到對應的控件上
    self.nameLabel.text = self.music.name; self.durationLabel.text=[NSString stringWithFormat:@"%d:%02d",(int)self.music.duration/60,(int)self.music.duration%60]; self.artistLabel.text=[[self.music.artist stringByAppendingString:@"-"]stringByAppendingString:self.music.album]; self.downloadedImageView.hidden = !self.music.downloaded; self.highQualityImageView.hidden = !self.music.highQuality; } //重寫 cell對本身內部子視圖的佈局
-(void)layoutSubviews{ [super layoutSubviews]; CGFloat x=self.downloadedImageView.frame.origin.x; if (self.music.downloaded) { x+=20; } if (self.music.highQuality) { CGRect rect=self.highQualityImageView.frame; rect.origin.x=x; self.highQualityImageView.frame=rect; x+=20; } CGRect fram=self.artistLabel.frame; fram.origin.x=x; self.artistLabel.frame=fram; } @end1.2. 佈局對狀態欄和各類Bar的處理 使用屬性:topLayoutGuide.length//屏幕上方當前被佔據的區域的長度 
                         bottomLayoutGuide.length//屏幕下方當前被佔據的長度
 【Demo2_Layout_Bar】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *button; @property (weak, nonatomic) IBOutlet UILabel *label; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidLayoutSubviews{ CGRect frame = self.button.frame; frame.origin.x = self.view.bounds.size.width-20-frame.size.width; frame.origin.y = self.topLayoutGuide.length+10; self.button.frame = frame; frame = self.label.frame; frame.origin.x = self.view.bounds.size.width -20 - frame.size.width; frame.origin.y = self.view.bounds.size.height - self.bottomLayoutGuide.length - frame.size.height; self.label.frame = frame; } //點擊屏幕隱藏工具欄
- (IBAction)changeBar:(UITapGestureRecognizer *)sender { [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; [self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES]; } - (BOOL)prefersStatusBarHidden{ return YES; } @end3. 手動設置Autoresizing 佈局 3.1 是什麼? 是舊版本(iOS5以前)的自動佈局奇數。操做簡單,API簡單,功能也簡單,有侷限性,好久之前叫 struts/spring(架構/彈性)技術 3.2 核心理念 當界面大小發生變化時,根據變化的比例,對子視圖進行同比例的變化 3.3 怎麼樣 step1:關閉AutoLayout step2:選中須要佈局的子視圖 step3:打開檢查器5 step4:點亮須要的紅線 外框(4個)紅線負責子視圖到父視圖的邊緣 內框(2個)紅線負責子視圖內部是否能夠拉伸 【Demo3_Autoresizing】 4.編寫代碼實現Autoresizing 佈局 Autoresizing和代碼佈局能夠同時使用,用代碼補齊Autoresizing的不足 button.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin; 代碼設置時,規則描述與在檢查器中描述相反,只須要設置可變的邊距 如: - (void)viewDidLoad { [super viewDidLoad]; /**/ UIButton* button=[UIButton buttonWithType:UIButtonTypeSystem]; [button setTitle:@"button1" forState:UIControlStateNormal]; [button setBackgroundColor:[UIColor redColor]]; button.frame=CGRectMake(self.view.bounds.size.width-120, 20, 100, 40); [self.view addSubview:button]; //點亮紅線
    button.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin; } 5.Autolayout(自動佈局) 5.1 是什麼? 是從iOS6開始的一個新的佈局技術,功能強大,操做複雜。從xcode5開始,慢慢好用了。在xcode6中,功能更強大了。 核心理念:使用約束(constraint)來描述控件在視圖中的位置,當屏幕大小發生變化時,系統會根據你設定的約束自動計算出frame的值,而後將該值賦給控件,實現控件的排布 5.2 使用故事板爲控件添加約束 【Demo4_AutoLayout】 5.3 操做要點 a。選中控件,分析6點,上下左右及控件的寬高須要哪些約束才能肯定 b。約束的添加能夠經過屏幕下方的選項,或者是,選中控件後,按住control,連線到屏幕邊緣或其餘視圖 c。能夠添加的約束有:對齊方式(與中心點對齊或與其餘控件對齊)、與邊緣或其餘視圖的間距(前導間距和尾部邊距)、視圖的寬高是給定值仍是以其餘視圖作參照標準 d。添加約束後,正確的結果出現時,屏幕中只有藍色的線,存在紅色虛線框框時,表明視圖佔據的區域,有橘色線條時,表明當前擺放位置與定義的位置有距離,能夠經過底部的第三個選項菜單,選擇更新某個視圖的frame或更新全部視圖的frame e。選中一個視圖,查看第5個檢查器能夠看到該視圖已經添加了的約束,能夠選中約束脩改約束的內容 f。選中一個視圖,經過查看場景的文檔結構圖,觀察該場景下的約束是否有錯誤或警告,若是有,能夠點擊該場景的右上角的紅色點點,進入說明界面,紅色的提示爲一場,必須修改成正確,方可表明系統承認約束,能夠進行佈局,橘色的提示,通常是實際位置與約束位置有誤差,只要更新frame,就可讓橘色的警告消失 6.Auto Layout 代碼建立約束 1.1 何時用? 當子視圖對象時代碼建立時,而且須要給子視圖佈局時,只能用代碼來進行自動佈局 1.2 如何添加約束? step1:建立約束對象 NSLayoutConstraint (API) step2:將約束添加到父視圖 1.3 建立約束對象 方法一:使用萬能公式 + (instancetype)constraintWithItem:(id)view1
                 attribute:(NSLayoutAttribute)attr1
                 relatedBy:(NSLayoutRelation)relation
                        toItem:(id)view2
                 attribute:(NSLayoutAttribute)attr2
               multiplier:(CGFloat)multiplier
                  constant:(CGFloat)c 公式:view1.attr1<relation>view2.attr2*multiplier +contant 如: button.left = self.view.left*0 + 20 button.right = self.view.width*1 + (-20) 注意:translateAutoresizingToConstraints這個屬性默認是YES,這個屬性表明:將視圖默認自帶的Auto resizing特性是否自動轉換爲對應的約束。既然使用代碼來建立約束,那麼就不要讓系統自帶的轉換過來的約束影響添加的自定義約束,因此該屬性要設置爲NO,爲了保證效果,能夠將視圖以及視圖的父視圖的該屬性都設置爲NO //關閉視圖自身的翻譯
    button1.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; 【Demo1_Autolayou_Code】 如: - (void)viewDidLoad { [super viewDidLoad]; UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem]; [button1 setTitle:@"button1" forState:UIControlStateNormal]; button1.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:button1]; //關閉視圖自身的翻譯
    button1.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; //建立約束
    NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:0 constant:20]; [self.view addConstraint:c1]; NSLayoutConstraint *c2 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:0 constant:20]; [self.view addConstraint:c2]; //
    NSLayoutConstraint *c3 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:150]; [self.view addConstraint:c3]; } 方法二:一次建立多個約束,使用VFL(Visual Format Language) + (NSArray *)constraintsWithVisualFormat:(NSString *)format
            options:(NSLayoutFormatOptions)opts 參數2:對齊方式
            metrics:(NSDictionary *)metrics
                   views:(NSDictionary *)views 參數4:建立添加的對象 特色:功能強大 【Demo2_Autolayout_Code_VFL】 1.4 VFL(Visual Format Language) a。是什麼? 一個字符串,具備必定的格式,表明一些約束的含義 b。如何寫VFL字符串? | 表明父視圖的邊 V:| 表明垂直方向的父視圖的上邊 [ ] 表明一個子視圖(或控件) ( ) 表明一個條件(== 、 >=、<=)==能夠省略 - 表明間距,默認的8個點 -xxx- 表明間距是多少 [button2(button1)] :button1與button2的高度相同 如: |-20-[button1]-10-[button2(button1)]-10-[button3(button1)]-20-| V:|-20-[button1] c。metrics參數 (用於替換參數3) 用於指定VFL字符串中能夠替換的值,是一個字典類型 如:NSDictionary *metrics = @{@"left":@20,@"space":@10,@"right":@20}; d。NSDictionaryOfVariableBinding()函數 (用於替換參數4) NSDictionary *dictionary = NSDictionaryOfVariableBindings(b1,b2,b3); 生成的字典以下: @{@"b1":b1,@"b2":b2,@"b3":b3} 如: #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //需求:屏幕上方 添加三個等寬的按鈕
    UIButton *b1 = [UIButton buttonWithType:UIButtonTypeSystem]; [b1 setTitle:@"button1" forState:UIControlStateNormal]; b1.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b1]; UIButton *b2 = [UIButton buttonWithType:UIButtonTypeSystem]; [b2 setTitle:@"button2" forState:UIControlStateNormal]; b2.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b2]; UIButton *b3 = [UIButton buttonWithType:UIButtonTypeSystem]; [b3 setTitle:@"button3" forState:UIControlStateNormal]; b3.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b3]; //1.添加約束的第一步:關閉自動翻譯
    b1.translatesAutoresizingMaskIntoConstraints = NO; b2.translatesAutoresizingMaskIntoConstraints = NO; b3.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; //下面的函數會將傳入的多個引用構建成以下的字典形式: //@{@"b1":b1,@"b2":b2,@"b3":b3}
    NSDictionary *dictionary = NSDictionaryOfVariableBindings(b1,b2,b3); NSDictionary *metrics = @{@"left":@20,@"space":@10,@"right":@20}; //2.第二步:建立約束 //2.1準備一個VFL //NSString*hVFL=@"|-20-[button1]-10-[button2(==button1)]-10-[button3(==button1)]-20-|";
     NSString *hVFL = @"|-left-[b1]-space-[b2(b1)]-space-[b3(b1)]-right-|"; //2.2建立約束
    NSArray *cs = [NSLayoutConstraint constraintsWithVisualFormat:hVFL options:NSLayoutFormatAlignAllCenterY metrics:metrics views:dictionary]; //3.將約束添加到父視圖中
 [self.view addConstraints:cs]; NSString *vVFL = @"V:|-left-[button1]"; cs = [NSLayoutConstraint constraintsWithVisualFormat:vVFL options:0 metrics:metrics views:@{@"button1":b1}]; [self.view addConstraints:cs]; } @end======================================================================= 知識點 7、動畫 1.動畫 (Animation) 1.1 是什麼? 「幀動畫」:一幀 是一張靜態的圖片,通常狀況下,1秒鐘達到24,5幀的時候,人眼就分辨不出圖片的切換過程,就有連續的效果產生 幀率(FPS)Frame Per Second 1.2 iOS中的動畫 UIImage 類,自帶一些方法,能夠作簡單動畫 NSTimer 類,間隔指定時間,產生切換效果 UIView類 原本提供了動畫的功能 底層的Core Animation 提供了動畫的支持 在iOS7中增長一些動畫功能: UIKit Dynamic 動力 Motion Effects 特效 Sprite Kit (2D引擎) 2. UIImage動畫 【Demo3_UIImage_Animation】 //duration:播放一組圖片用的時間
    UIImage *image = [UIImage animatedImageNamed:@"ship-anim" duration:1*5/30]; 1秒播放30幀,播放一張圖片須要1/30,5張照片 self.imageView.image = image; 3. NSTimer 動畫 4.1 是什麼? 一個計時器類,用於定時向指定對象發消息 4.2 如何使用? 【Demo4_NSTimer】 1.//建立計時器 //使用schedule。。開頭的方法時,定時器建立完畢就會啓動
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES]; //使用timerWith。。。開頭的方法建立timer //定時器不會在建立完畢後啓動 //須要使用代碼將定時器添加到時間循環中才能啓動
    self.timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES]; 2.//啓動定時器
 [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; 3.//關閉定時器
 [self.timer invalidate]; 練習:【Demo5_NSTimer_Alpha】 使用NSTimer作一個圖片淡入的效果(經過修改alpha透明度值來完成) #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)NSTimer *timer; @property(nonatomic)NSInteger count; @end

@implementation ViewController #define FPS 30.0
#define DURATION 5.0

- (void)viewDidLoad { [super viewDidLoad]; self.imageView.alpha = 0; self.timer = [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(changeAlpha:) userInfo:nil repeats:YES]; } //勻速動畫的公式 //當前值 = 開始值+當前幀數*(結束值-開始值)/(幀率*動畫時長)
-(void)changeAlpha:(NSTimer *)timer{ //count表明當前幀數
    self.count++; self.imageView.alpha = 0 + self.count*(1-0)/(FPS*DURATION); if (self.count>=FPS*DURATION) { [timer invalidate]; } } @end

    4.3 勻速動畫 公式:當前值= 開始值+當前幀數*(結束值-開始值)/(幀率*動畫時長) 這個值能夠是:center transform frame alpha 【Demo6_NSTimer_Animation】 4.4 變速動畫 由快到慢、由慢到快、由慢到快再到慢 公式: 當前值 = 上一次的值+(目標值-上一次值)*漸進因子 漸進因子根據狀況調節 【Demo7_NSTimer_Animation】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *airCraft; @end

@implementation ViewController #define FPS 30.0

- (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)start:(id)sender { [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(move:) userInfo:nil repeats:YES]; } //當前值=上一次的值+(目標值-上一次的值)*漸進因子 /* 400 + (100 - 400)*0.1 = 370 30p 370 + (100 - 370)*0.1 = 343 27p 343 + (100 - 343)*0.1 = 319.7 24.3 */
-(void)move:(NSTimer *)timer{ CGPoint center = self.airCraft.center; center.y = center.y+(50-center.y)*0.05; self.airCraft.center = center; if (center.y<=51.0) { [timer invalidate];//結束
 } } @end

5. UIView 動畫:真正的動畫,有專門的API 5.1 是什麼 有UIKit專門製做動畫的API,這些API的底層對Core Animation的封裝,能夠輕鬆實現動畫,不用再計算每一幀的值來實現動畫的效果 5.2 製做動畫的步驟 step1:設置須要動畫的視圖的初始值 step2:給UIView類發消息,告訴UIView類須要什麼樣的動畫 step3:將動畫結束的狀態(屬性值),即變化的結果,寫入到一個Bloack中 [UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{ //設置動畫結束時,被動畫的那個視圖的結束狀態
        self.airCraft.center = endCenter; self.airCraft.transform = transform; } completion:nil]; 【Demo8_UIView_Animation】 5.3 動畫的高級選項 先慢後快再慢 UIViewAnimationOptionCurveEaseInOut 愈來愈快 UIViewAnimationOptionCurveEaseIn 愈來愈慢 UIViewAnimationOptionCurveEaseOut 勻速 UIViewAnimationOptionCurveLinear 動畫重複 UIViewAnimationOptionRepeat 反着執行動畫,要配合Repeat選項 UIViewAnimationOptionAutoreverse 要求:啓動後,從屏幕左邊彈出label,從屏幕下邊彈出image,而後點擊按鈕,飛機實現旋轉飛行,並重復飛行 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *airCraft; @property (weak, nonatomic) IBOutlet UILabel *welcomeLabel; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CGRect endFrame = self.welcomeLabel.frame; CGRect startFrame = endFrame; startFrame.origin.x = -startFrame.size.width; //1.設置須要動畫的視圖的初始屬性
    self.welcomeLabel.frame = startFrame; self.welcomeLabel.alpha = 0.1; //2.給UIView發消息
    [UIView animateWithDuration:2.0 animations:^{ self.welcomeLabel.frame = endFrame; self.welcomeLabel.alpha = 1.0; }]; endFrame = self.airCraft.frame; startFrame = endFrame; startFrame.origin.y = self.view.bounds.size.height; self.airCraft.frame = startFrame; [UIView animateWithDuration:2.0 animations:^{ self.airCraft.frame = endFrame; }]; } - (IBAction)start:(id)sender { //這是當前中心點
    CGPoint endCenter = self.airCraft.center; //計算結束位置的y值
    endCenter.y -=300; //旋轉
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI); [UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{ //設置動畫結束時,被動畫的那個視圖的結束狀態
        self.airCraft.center = endCenter; self.airCraft.transform = transform; } completion:nil]; } @end  做業 1.飛機放到屏幕上之後,點哪,飛哪兒 2.作一個購物車的動畫 在屏幕的左上角有一個UIImageView,圖片是一個商品。 當用戶點擊此商品時,商品會從上面掉下來,落入到下面的購物車中, 注意:商品掉下來時,屏幕左上角的圖片不會消失 例: #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController #define FPS 30.0
#define MAX_SIZE 10
#define MAX_DURATION 10


- (void)viewDidLoad { [super viewDidLoad]; //啓動定時器,建立雪花
    [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(animate:) userInfo:nil repeats:YES]; } -(void)animate:(NSTimer *)timer{ //1.建立一個雪花
    UIImageView *snow = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"snow.png"]]; int viewWidth = self.view.bounds.size.width; int viewHeight = self.view.bounds.size.height; CGFloat size = MAX_SIZE+arc4random()%MAX_SIZE; snow.frame = CGRectMake(arc4random()%viewWidth, -20, size, size); [self.view addSubview:snow]; //2.建立動畫
    [UIView animateWithDuration:arc4random()%MAX_DURATION+2  delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ //3. 設置動畫結束時雪花的位置信息
        int offset = arc4random()%100 - 50; snow.center = CGPointMake(snow.center.x+offset, viewHeight-30); }completion:^(BOOL finished) { //4.落地動畫結束時,開始融雪
        [UIView animateWithDuration:arc4random()%MAX_DURATION delay:0 options:UIViewAnimationOptionCurveEaseIn  animations:^{ snow.alpha = 0; } completion:^(BOOL finished) { //5.融雪動畫結束時,將圖片移出父視圖
 [snow removeFromSuperview]; }]; }]; } ====================================================================== 知識點 7、Core Animation 1.Core Animation 1.1是什麼 是一個圖形渲染和動畫的底層框架,用於iOS和Mac OS X 1.2 能幹什麼 1)能夠提供更多更強大的圖形渲染(顯示)效果 2)能夠提供專業級的動畫效果 3)是高層圖形技術的基礎 1.3 如何使用Core Animation (內容較多,很龐大,只講經常使用的) 經過CALayer類,直接對一個視圖(UIView及子類)的 Core Animation層進行一些設置,達到須要的效果 1.4 如何得到CALayer這一層呢? 任何UIView及其子類都有一個屬性叫layer UIView CALayer .layer .frame .frame .transform .transform3D .autoresizing .autoresizing .addSubView: .addSubLayer: 【Demo1_CoreAnimation】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CALayer *layer = self.view.layer; layer.backgroundColor = [[UIColor orangeColor] CGColor]; layer.cornerRadius = 30.0; self.imageView.layer.cornerRadius = 10.0; //打開遮罩
    self.imageView.layer.masksToBounds = YES; // 加子層
    CALayer *subLayer = [CALayer layer]; subLayer.backgroundColor = [[UIColor purpleColor]CGColor]; subLayer.frame = CGRectMake(30, 200, 100, 120); subLayer.shadowColor = [[UIColor greenColor]CGColor]; subLayer.shadowOffset = CGSizeMake(2, 2); subLayer.shadowRadius = 5.0; subLayer.shadowOpacity = 0.8;陰影透明度,設置它陰影纔會顯示 subLayer.cornerRadius = 10.0; [layer addSublayer:subLayer]; //有內容的子層
    CALayer *imageLayer = [CALayer new]; imageLayer.frame = CGRectMake(180, 250, 100, 120); imageLayer.contents = (id)[UIImage imageNamed:@"d.jpg"].CGImage;//添加圖片
    imageLayer.cornerRadius = 10; imageLayer.masksToBounds = YES; [layer addSublayer:imageLayer]; } @end1.5 CAAnimation 一個抽象的動畫類型,不少時候不關心這個父類,而是使用它的子類來實現動畫 1) CAKeyframeAnimation 關鍵幀動畫 能夠根據指定的路徑進行動畫 實現步驟: step1:建立關鍵幀動畫 使用animationWithKeyPath:方法建立,同時,最後一個字符串參數必須是如下幾種選擇: position transform opacity step2:設置動畫屬性 step3:將動畫添加到視圖的layer層上 2)CABasicAnimation能夠實現縮放,旋轉,透明度等動畫 特色:設置動畫屬性主要爲兩個:fromValue 和 toValue 例:點擊按鈕,圖片按曲線移動,而且移動的時候會縮小,而且會消失 #import "AnimationViewController.h"

@interface AnimationViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation AnimationViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)start:(id)sender { UIBezierPath *path = [UIBezierPath bezierPath]; [self createPath:path]; // 建立關鍵幀動畫
    CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; // 設置相關的屬性
    moveAnimation.path = path.CGPath; //moveAnimation.duration = 2.0; //[self.imageView.layer addAnimation:moveAnimation forKey:nil]; //建立縮放動畫
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 0.1)]; //scaleAnimation.duration = 2.0; //[self.imageView.layer addAnimation:scaleAnimation forKey:nil]; //透明度動畫
    CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; alphaAnimation.fromValue = @1.0; alphaAnimation.toValue = @0.0; //alphaAnimation.duration = 2.0; //[self.imageView.layer addAnimation:alphaAnimation forKey:nil]; //建立動畫組,將全部動畫對象添加到組中 //針對組設置的動畫屬性,會被應用到組中的每個動畫上面
    CAAnimationGroup *group = [CAAnimationGroup animation]; group.animations = @[moveAnimation,scaleAnimation,alphaAnimation]; group.duration = 2.0; group.delegate = self; [self.imageView.layer addAnimation:group forKey:nil]; } //圖片消失
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ [self.imageView removeFromSuperview]; } //生成路線
-(void)createPath:(UIBezierPath *)path{ [path moveToPoint:self.imageView.center]; CGPoint tartgetPoint = CGPointMake(self.view.bounds.size.width-self.imageView.frame.size.width-20, self.view.bounds.size.height-self.imageView.frame.size.height-20); CGPoint control1 = CGPointMake(self.view.bounds.size.width-self.imageView.frame.size.width-20, self.imageView.frame.origin.y); CGPoint control2 = CGPointMake(self.imageView.frame.origin.x, self.view.bounds.size.height-20-self.imageView.frame.size.height); [path addCurveToPoint:tartgetPoint controlPoint1:control1 controlPoint2:control2]; } @end  補充:動畫中止 //中止
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ self.imageView.layer.transform = CATransform3DRotate(self.imageView.layer.transform,M_PI, 1.0, 1.0, 1.0); } 1.6CATransform3D 1)是什麼 是一個4X4的矩陣,一個結構體。描述了一個3D圖片變形的數據 2)建立 CATransform3DMakeRotation/scale/Translation//這組方法在定值常量的基礎上變形
                        CATransform3DScale/Rotate/Translate //這組方法是在傳入值的基礎上進行變形
===================================================================== 知識點 8、 UIKit Dynamic 動力特效 1. UIKit Dynamic 動力特效 1.1是什麼 中文翻譯:UIKit 動力、動力模型。。。。iOS7開始的技術。 提供了一個模擬真實世界中力學相關的動畫和交互系統,好比,重力、碰撞、吸附等。UIKit Dynamic能夠組合 可重用 1.2 UIKit Dynamic架構 a。核心部分:UIDynamicAnimator —>視圖的座標系 b。UIDynamic xx Behavior (行爲) 重力 UIGravityBehavior (.magnitude 重力的強度,即加速度) 碰撞 UICollisionBehavior //將場景視圖的四周翻譯成可碰撞的四個邊
                      collision.translatesReferenceBoundsIntoBoundary = YES; 吸附 UIAttachmentBehavior self.attachment.anchorPoint //吸附點 (一個座標)
                                                       self.attachment.frequency=1;//設置吸附行爲的頻率(左右晃動的大小)
                       self.attachment.damping=0.1;//設置吸附行爲的阻尼(上下彈跳的範圍)
 閃爍 推力 綜協力 【Demo2_Dynamic】 *****給view添加背景色,顯示小方格(方法就是重繪一下圖形,利用重寫初始化方法:而後設置self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"BackgroundTile"]]; BackgroundView.h #import <UIKit/UIKit.h>

@interface BackgroundView : UIView @property(nonatomic,strong)UIBezierPath *path; @end BackgroundView.m #import "BackgroundView.h"

@implementation BackgroundView //當故事板建立此視圖對象時調用此方法,初始化方法
- (id)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; if (self) { self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"BackgroundTile"]]; } return self; } //繪製傳入的障礙物圖形
- (void)drawRect:(CGRect)rect { [[UIColor redColor]setFill]; [[UIColor greenColor]setStroke]; [self.path stroke]; [self.path fill]; } @end
======================================================================================================= 重力 (點擊下落就向下,點擊中止即中止) ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravityBehavior; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.構建場景
    UIDynamicAnimator *animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; self.animator = animator; // 2.建立重力行爲對象
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; self.gravityBehavior = gravity; } - (IBAction)begin:(id)sender { // 3.將重力行爲添加到場景中
 [self.animator addBehavior:self.gravityBehavior]; } - (IBAction)stop:(id)sender { [self.animator removeBehavior:self.gravityBehavior];//將重力行爲從場景中移除
} @end 碰撞(依靠重力下落,而後碰到矩形框,改變成紅色而後中止) CollisionViewController.h CollisionViewController.m #import "CollisionViewController.h"
#import "BackgroundView.h"

@interface CollisionViewController ()<UICollisionBehaviorDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @end

@implementation CollisionViewController - (void)viewDidLoad{ [super viewDidLoad]; self.imageView.transform = CGAffineTransformMakeRotation(M_PI_4); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; self.animator = animator; //重力行爲
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; //設置重力行爲的強度
    gravity.magnitude = 1; [animator addBehavior:gravity]; //碰撞行爲
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[self.imageView]]; //將場景視圖的四周翻譯成可碰撞的四個邊
    collision.translatesReferenceBoundsIntoBoundary = YES; //添加一條矩形的障礙物
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 360, 280, 30) cornerRadius:10.0]; BackgroundView *myView = (BackgroundView *)self.view; myView.path = path; [myView setNeedsDisplay]; [collision addBoundaryWithIdentifier:@"MyPath1" forPath:path]; collision.collisionDelegate = self; [animator addBehavior:collision]; } //添加代理實現方法 碰撞時方框實現變色
-(void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p{ //NSLog(@"...");
    UIImageView *box = (UIImageView *)item; box.tintColor = [UIColor redColor]; box.image = [box.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; } @end 吸附(設置移動,並在移動到的點與圖片的中心點繪製直線,而後移動到哪,圖片就吸附到哪,而後有重力,圖片還會擺動) AttachmentViewController.h AttachmentViewController.m #import "AttachmentViewController.h"
#import "BackgroundView.h"

@interface AttachmentViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravity; @property(nonatomic,strong)UIAttachmentBehavior *attachment; @end

@implementation AttachmentViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (UIGravityBehavior *)gravity{ if (!_gravity) { _gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; } return _gravity; } - (UIAttachmentBehavior *)attachment{ CGPoint attachmentAnchor = CGPointMake(self.imageView.center.x, self.imageView.center.y - 100); if (!_attachment) { _attachment = [[UIAttachmentBehavior alloc]initWithItem:self.imageView attachedToAnchor:attachmentAnchor]; } return _attachment; } - (IBAction)tap:(UIPanGestureRecognizer *)sender { CGPoint location = [sender locationInView:self.view]; //將手勢滑動到的點做爲吸附行爲的錨點
    self.attachment.anchorPoint = location; } - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.animator addBehavior:self.gravity]; self.attachment.action = ^{ //繪製錨點到中心點的懸掛的線
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:self.attachment.anchorPoint]; [path addLineToPoint:self.imageView.center]; BackgroundView *bgView = (BackgroundView *)self.view; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; [self.animator addBehavior:self.attachment]; } @end     改:吸附類 移動的時候會出現繪圖綠線和重力做用,當手勢中止,一切動做都中止 AttachmentViewController.h AttachmentViewController.m #import "AttachmentViewController.h"
#import "BackgroundView.h"

@interface AttachmentViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravity; @property(nonatomic,strong)UIAttachmentBehavior *attachment; @end

@implementation AttachmentViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (UIGravityBehavior *)gravity{ if (!_gravity) { _gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; } return _gravity; } - (UIAttachmentBehavior *)attachment{ //設置錨點
    CGPoint attachmentAnchor = CGPointMake(self.imageView.center.x, self.imageView.center.y - 100); if (!_attachment) { _attachment = [[UIAttachmentBehavior alloc]initWithItem:self.imageView attachedToAnchor:attachmentAnchor]; } return _attachment; } - (IBAction)tap:(UIPanGestureRecognizer *)sender { if (sender.state==UIGestureRecognizerStateBegan) { [self.animator addBehavior:self.gravity]; self.attachment.frequency=1;//設置吸附行爲的頻率(左右晃動的大小)
        self.attachment.damping=0.1;//設置吸附行爲的阻尼(上下彈跳的範圍)
 [self drawLine]; [self.animator addBehavior:self.attachment]; }else if(sender.state==UIGestureRecognizerStateChanged){ CGPoint location = [sender locationInView:self.view]; //將手勢滑動到的點做爲吸附行爲的錨點
        self.attachment.anchorPoint = location; [self drawLine]; }else if(sender.state==UIGestureRecognizerStateEnded){ [self.animator removeBehavior:self.gravity]; [self.animator removeBehavior:self.attachment]; BackgroundView*view=(BackgroundView*)self.view; view.path=nil; [view setNeedsDisplay]; } } //執行繪圖功能
-(void)drawLine{ self.attachment.action = ^{ //繪製錨點到中心點的懸掛的線
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:self.attachment.anchorPoint]; [path addLineToPoint:self.imageView.center]; BackgroundView *bgView = (BackgroundView *)self.view; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; } @end

    ****補充: 在block塊中,只要用到self引用必需要用弱引用 -(void)drawLine{ //弱引用
    __weak UIAttachmentBehavior* weakAttachment=self.attachment; __weak UIImageView*weakImageView=self.imageView; __weak BackgroundView*weakBgView=(BackgroundView*)self.view; self.attachment.action = ^{ //繪製錨點到中心點的懸掛的線
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:weakAttachment.anchorPoint]; [path addLineToPoint:weakImageView.center]; BackgroundView *bgView = weakBgView; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; } 4. 閃爍行爲 UISnapBehavior /* 閃爍其實就是快速移動到某一點,使用變形動畫也能夠作到這個效果, 可是,使用snapBehavior,物體在移動到某點之後 會晃動如下 注意:在animator中不能添加兩種一樣的特效,因此須要先移除之前的行爲,再添加新的行爲 */ SnapViewController.h SnapViewController.m #import "SnapViewController.h"

@interface SnapViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator*dynamicAnimator; @property(nonatomic,strong)UISnapBehavior*snapBehavior; @end

@implementation SnapViewController -(UIDynamicAnimator *)dynamicAnimator{ if (!_dynamicAnimator) { _dynamicAnimator=[[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _dynamicAnimator; } - (IBAction)pan:(UIPanGestureRecognizer *)sender { CGPoint point=[sender locationInView:self.view]; //先移除原有的閃爍行爲 否則只能移一次
 [self.dynamicAnimator removeBehavior:self.snapBehavior]; self.snapBehavior=[[UISnapBehavior alloc]initWithItem:self.imageView snapToPoint:point]; [self.dynamicAnimator addBehavior:self.snapBehavior]; } @end
        
5. 推力行爲 UIPushBehavior //推力角度
    self.pushBehavior.angle=M_PI_4;//右下角 //推力大小
    self.pushBehavior.magnitude=2; //激活力 push手勢的特別之處:須要激活,不然不起做用
    self.pushBehavior.active=YES; 如:藉助移動手勢來實現力的方向 #import "PushViewController.h"

@interface PushViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIPushBehavior *pushBehavior; @end

/* push手勢的特別之處:須要激活,不然不起做用 設置 .active = YES */
@implementation PushViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; // 添加碰撞行爲,遇到邊界則中止
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[self.imageView]]; [collision setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(self.topLayoutGuide.length, 0,self.bottomLayoutGuide.length, 0) ]; [self.animator addBehavior:collision]; //添加推力行爲
    self.pushBehavior = [[UIPushBehavior alloc]initWithItems:@[self.imageView] mode:UIPushBehaviorModeContinuous]; [self.animator addBehavior:self.pushBehavior]; } - (IBAction)tap:(UITapGestureRecognizer *)sender { CGPoint point = [sender locationInView: self.view]; CGPoint center = self.imageView.center; CGFloat angle = atan2(point.y-center.y, point.x-center.x)+M_PI; //powf()函數:求某數的某幾回冪 //sqrt()函數:開平方
    CGFloat distance = sqrt(powf((point.x-center.x), 2)+powf((point.y-center.y), 2)); self.pushBehavior.angle = angle; self.pushBehavior.magnitude = distance/10; self.pushBehavior.active = YES; } @end    點擊哪就從這個方向施力 練習:SpringMessage 彈簧效果短消息: 1.思路: 利用手指移動的距離,以及item離手指點的位置的遠近,產生一個變化的值,用這個值來修改全部collectionView中的item的錨點 2.步驟 step1.首先計算scroll的距離scrollDelta step2.爲了獲得每一個item與觸摸點的之間的距離,還須要知道觸摸點的座標touchLocation。 step3.能夠根據距離對每一個錨點進行設置了:簡單地計算了原來錨點與觸摸點之間的距離distanceFromTouch,並由此計算一個係數。 step4.接下來,對於當前的item,咱們獲取其當前錨點位置,而後將其根據scrollDelta的數值和剛纔計算的係數,從新設定錨點的位置。 step5.最後須要告訴UIDynamicAnimator已經完成了對錨點的更新,如今能夠開始更新物理計算,並隨時準備collectionView來取LayoutAttributes的數據了。 SpringLayout.h #import <UIKit/UIKit.h>

@interface SpringLayout : UICollectionViewFlowLayout @property(nonatomic,strong)UIDynamicAnimator *animator; @end SpringLayout.m #import "SpringLayout.h"

/* 1. 爲每個佈局屬性對象添加行爲,讓佈局屬性對象成爲behavior的主體 2. 控制器再來詢問佈局屬性對象(layoutAttribute) 時,返回具備行爲特徵的item 3. 每當屏幕滾動一點,就根據觸點和各個item的位置的遠近,計算出一個有必定變化規律的因子,根據這個因子,有規律的調整每個佈局屬性對象的attachment Behavior的錨點,就能夠實現彈簧效果 */

@implementation SpringLayout //1. 在vc即將跟佈局對象要各個佈局屬性對象以前 //就將每個佈局屬性對象都添加上 吸附 行爲
-(void)prepareLayout{ if (!self.animator) { self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self]; //獲得整個collectionView的尺寸
        CGSize contentSize = [self collectionViewContentSize]; NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)]; //獲得整個collectionView中的全部向的 //佈局屬性對象,從而添加 吸附 行爲
        for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attribute attachedToAnchor:attribute.center]; spring.damping = 0.6; spring.frequency = 0.8; [self.animator addBehavior:spring]; } } } //2.當vc再來詢問每個佈局屬性對象時,返回 //修改過的 佈局屬性對象,或者說返回已經成爲 //吸附行爲主體 的 那個佈局屬性對象
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ //體系維護對象 按照指定的矩形區域 //返回該範圍內的行爲主體(佈局屬性對象)
    return [self.animator itemsInRect:rect] ; } //3.根據vc傳入的單元格的座標,返回該單元格 //對應的那個用來佈局這個單元格的部署屬性對象 //-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ // return [self.animator layoutAttributesForCellAtIndexPath:indexPath]; //} //4.當邊界bounds發生變化時,是否更新邊界 //思路:1.不更新邊界 // 2.邊界發生變化的緣由,是由於有滾動事件發生了 // 雖然不更新邊界,但要針對這個用戶的操做 // 修改一下錨點,以此出現彈簧效果
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ UIScrollView *scrollView = self.collectionView; //獲取滾動的距離,其實就是座標系變換的大小
    CGFloat scrollDistance = newBounds.origin.y - scrollView.bounds.origin.y; //手指所在的位置
    CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; //計算和修改每個行爲的錨點
    for (UIAttachmentBehavior *spring in self.animator.behaviors) { //由於attribute是 behavior 行爲的主體 //因此反過來,從行爲上獲取 與它綁定的主體 //就須要訪問items屬性,因爲,該行爲只關聯 //了一個主體,因此取firstObject
        UICollectionViewLayoutAttributes *attributes = [spring.items firstObject]; CGPoint center = attributes.center; CGPoint anchorPoint = spring.anchorPoint; //手指的觸點和項的中心點的遠近 //根據 項 離 手指觸點的遠近,產生一組 //不一樣大小的 新的anchor值
        CGFloat distance = fabsf(touchLocation.y - anchorPoint.y); // distance是變化的,因此除以最大距離 //也就是一屏幕的高度,取個整,算600 //到底一個小於1的可變化的值 //用這個值做爲變化因子,從而使得滾動距離 //與項離觸點遠近的變化規律相同了
        center.y += scrollDistance*(distance/600); attributes.center = center; // 更新體系內的每個行爲的狀態
 [self.animator updateItemUsingCurrentState:attributes]; } return NO; } @end ViewController.h ViewController.m #import "ViewController.h"
#import "SpringLayout.h"

@interface ViewController ()<UICollectionViewDataSource>

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; SpringLayout *layout = [[SpringLayout alloc]init]; layout.itemSize = CGSizeMake(300,40); layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10); UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout]; collectionView.showsHorizontalScrollIndicator = NO; collectionView.showsVerticalScrollIndicator = NO; [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"MyCell"]; collectionView.dataSource = self; [self.view addSubview:collectionView]; } -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return  50; } -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MyCell" forIndexPath:indexPath]; cell.backgroundColor = [UIColor lightGrayColor]; return cell; } @end  點擊屏幕發生晃動 =================================================================== 知識點 9、通知( NSNotification) 1. 通知(Notification) 1.1 是什麼? 是一種觀察者模式的具體體現 觀察者模式:一個對象(A)想知道另外一個對象(B)的狀態是否發生了改變。思路就是,在對象B上註冊一個觀察者,當對象B的狀態發生改變時,通知對象A,對象A收到通知後進行相關的處理的一種模式 其中觀察者模式的一種解決方案叫作—廣播 系統中的通知 就是廣播的體現 1.2 好處 一個對象不須要知道消息的接收者是誰,就能夠將一些消息發送給須要的接收者 有時,發送消息的對象沒法知道有哪些對象,有多少對象接收消息,也不知道對象是否存在 有時,消息的接受者和發送者太遠(遠 指的不是距離,是關係,如 控制器和視圖就很近,但Model離控制器就很遠) 1.3 具體用法 1)收聽者:找到通知中心 NSNotificationCenter,註冊要收聽的一個具體頻道 addObserver 2)發送者:找到通知中心,建立通知對象(NSNotification),使用通知中心來發送這個消息(postNotification) 3)收聽者 收到消息 處理消息(掉個方法) 4)中止收聽,不須要收聽時,找到通知中心,註銷 removeObserver 1.4關鍵的類 NSNotificationCenter,是一個單例類,使用defaultCenter方法永遠返回同一個對象,以此保證中心對象只有一個 NSNotification 通知類(封裝通知的內容等信息) 【Demo2_Notification】建立控制檯程序 Company.h #import <Foundation/Foundation.h>

@interface Company : NSObject -(void)broadcast; @end Company.m #import "Company.h"

@implementation Company -(void)broadcast{ NSNotificationCenter*center=[NSNotificationCenter defaultCenter]; //發消息
    [center postNotificationName:@"videoUpdate" object:self userInfo:@{@"title": @"錦繡園",@"episode": @"第15集"}]; } @end Vap.h Vap.m #import "Vap.h"

@implementation Vap -(id)init{ if ([super init]) { NSNotificationCenter*center=[NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(updated:) name:@"videoUpdate" object:nil]; } return self; } -(void)updated:(NSNotification*)notification{ NSDictionary*message=notification.userInfo; NSLog(@"%@已經更新到%@",message[@"title"],message[@"episode"]); } -(void)dealloc{ [[NSNotificationCenter defaultCenter]removeObserver:self]; NSLog(@"dealloc執行了"); } @end main.m #import <Foundation/Foundation.h>
#import "Company.h"
#import "Vap.h"
int main(int argc, const char * argv[]) { @autoreleasepool { Company*company=[[Company alloc]init]; Vap*vip=[[Vap alloc]init]; [company broadcast]; NSLog(@"Hello, World!"); } return 0; } 2.鍵盤通知 鍵盤彈起的通知名稱: UIKeyboardWillShowNotification 鍵盤收起的通知名稱 UIKeyboardWillHideNotification 【Demo3_Keyboard_Notification】 #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; // 註冊監聽
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyboardOpen:) name:UIKeyboardWillShowNotification object:nil]; [center addObserver:self selector:@selector(keyboardClosed:) name:UIKeyboardWillHideNotification object:nil]; } -(void)keyboardOpen:(NSNotification *)notification{ NSDictionary *message = notification.userInfo; //獲取鍵盤的起始點(0,264)
    NSValue  *value = message[UIKeyboardFrameEndUserInfoKey]; CGRect rect = [value CGRectValue]; NSLog(@"%f,%f",rect.origin.x,rect.origin.y); //NSLog(@"%@",message);
} -(void)keyboardClosed:(NSNotification *)notification{ NSLog(@"close....."); } //點擊右下角關閉鍵盤
- (IBAction)inputFinished:(UITextField *)sender { [sender resignFirstResponder]; } - (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } @end qq聊天程序 TRMessage.h #import <Foundation/Foundation.h>

@interface TRMessage : NSObject @property(nonatomic)BOOL fromMe; @property(nonatomic,strong)NSString *content; +(NSMutableArray *) demoData; @end TRMessage.m #import "TRMessage.h"

@implementation TRMessage + (NSMutableArray *)demoData{ TRMessage *message = nil; NSMutableArray *array = [NSMutableArray array]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"Hello 你好Hello 你好Hello 你好Hello 你好"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"幹嗎呢"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"沒幹嗎你呢"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"呵呵 呵呵呵"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"今天的大新聞就是蘋果手錶終於發佈了,好喜歡紅色的,可是買不起"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"就知道你買不起,那就別買了"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"仍是你送我吧"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"作夢"; [array addObject:message]; return array; } @end TRMessageCell.h #import <UIKit/UIKit.h>
#import "TRMessage.h"

@interface TRMessageCell : UITableViewCell @property(nonatomic,strong)TRMessage *message; @end TRMessageCell.m #import "TRMessageCell.h"

@interface TRMessageCell () @property (weak, nonatomic) IBOutlet UIImageView *popImageView; @property (weak, nonatomic) IBOutlet UILabel *label; @end

@implementation TRMessageCell #define CELL_MARGIN_TB      4.0     //氣泡上下外邊距
#define CELL_MARGIN_LR      10.0    //氣泡左右外邊距

#define CELL_CORNOR         18.0    //氣泡圓角半徑
#define CELL_TAIL_WIDTH     16.0    //氣泡尾巴

#define MAX_WIDTH_OF_TEXT   200.0   //文字寬度限制
#define CELL_PADDING        8.0        //氣泡內邊距



- (void)setMessage:(TRMessage *)message{ _message = message; self.label.text = self.message.content; //根據消息的來源,對label和image進行定位
    if (self.message.fromMe) {//藍色氣泡 //設置標籤內容和圖片視圖中的氣泡圖片
        self.label.textColor = [UIColor whiteColor]; UIImage *image = [UIImage imageNamed:@"message_i.png"]; image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(CELL_CORNOR, CELL_CORNOR, CELL_CORNOR, CELL_CORNOR+CELL_TAIL_WIDTH)]; self.popImageView.image = image; //1。定位Label // 先肯定文本的高度
        CGRect rectOfText = CGRectMake(0, 0, MAX_WIDTH_OF_TEXT, 999); rectOfText = [self.label textRectForBounds:rectOfText limitedToNumberOfLines:0]; CGRect frameOfLabel = CGRectZero; frameOfLabel.size = rectOfText.size; frameOfLabel.origin.y = CELL_MARGIN_TB + CELL_PADDING; frameOfLabel.origin.x = self.bounds.size.width - CELL_MARGIN_LR - CELL_TAIL_WIDTH - CELL_PADDING - rectOfText.size.width; self.label.frame = frameOfLabel; //2。定位popImageView的座標
        CGRect frameOfPop = frameOfLabel; frameOfPop.origin.x -=CELL_PADDING; frameOfPop.origin.y -=CELL_PADDING; frameOfPop.size.width += 2 * CELL_PADDING + CELL_TAIL_WIDTH ; frameOfPop.size.height += 2 * CELL_PADDING; self.popImageView.frame = frameOfPop; //3.設定單元格的bounds
        CGRect bounds = self.bounds; bounds.size.height = frameOfPop.size.height + CELL_MARGIN_TB * 2; self.bounds = bounds; }else{//灰色氣泡
        self.label.textColor = [UIColor darkGrayColor]; UIImage *image = [UIImage imageNamed:@"message_other.png"]; image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(CELL_CORNOR, CELL_CORNOR+CELL_TAIL_WIDTH, CELL_CORNOR, CELL_CORNOR)]; self.popImageView.image = image; CGRect rectOfText = CGRectMake(0, 0, MAX_WIDTH_OF_TEXT, 999); rectOfText = [self.label textRectForBounds:rectOfText limitedToNumberOfLines:0]; CGRect frameOfLabel = CGRectZero; frameOfLabel.size = rectOfText.size; frameOfLabel.origin.x = CELL_PADDING+CELL_MARGIN_LR+CELL_TAIL_WIDTH; frameOfLabel.origin.y = CELL_MARGIN_TB + CELL_PADDING; self.label.frame = frameOfLabel; CGRect frameOfPop = frameOfLabel; frameOfPop.origin.x -=(CELL_PADDING + CELL_TAIL_WIDTH); frameOfPop.origin.y -=CELL_PADDING; frameOfPop.size.width += CELL_PADDING*2+CELL_TAIL_WIDTH; frameOfPop.size.height += CELL_PADDING*2; self.popImageView.frame = frameOfPop; CGRect bounds = self.bounds; bounds.size.height = frameOfPop.size.height + CELL_MARGIN_TB *2; self.bounds = bounds; } } @end TRMessageViewController.h #import <UIKit/UIKit.h>

@interface TRMessageViewController : UIViewController @property(nonatomic,strong)NSMutableArray *messages; @end TRMessageViewController.m #import "TRMessageViewController.h"
#import "TRMessage.h"
#import "TRMessageCell.h"

@interface TRMessageViewController ()<UITableViewDataSource,UITableViewDelegate> @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UIView *inputTextView; @property (weak, nonatomic) IBOutlet UITextField *textField; @end

@implementation TRMessageViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Message"; self.messages = [TRMessage demoData]; [self.tableView registerNib:[UINib nibWithNibName:@"TRMessageCell" bundle:nil] forCellReuseIdentifier:@"Cell"]; // 設置view的背景圖
    self.inputTextView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ToolViewBkg_Black.png"]]; } -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.messages.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ TRMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; cell.message = self.messages[indexPath.row]; return cell; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ //在生成cell的時候,在cell的內部曾經 //根據圖片的大小,修改過cell的bounds屬性 //隨着修改bounds屬性,cell的frame就自動被 //修改了,變成咱們根據圖片計算出來的高度
    UITableViewCell  *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath]; return cell.frame.size.height; } //註冊監聽系統鍵盤的彈起
-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyboardAppear:) name:UIKeyboardWillShowNotification object:nil]; [center addObserver:self selector:@selector(keyboardDisappear:) name:UIKeyboardWillHideNotification object:nil]; } //鍵盤彈起時
-(void)keyboardAppear:(NSNotification *)notification{ //1.獲取鍵盤的座標體系
    CGRect frameOfKeyboard = [notification.userInfo[UIKeyboardFrameEndUserInfoKey]CGRectValue]; //2.計算輸入框的結束的座標信息
    CGRect frameOfInputView = self.inputTextView.frame; frameOfInputView.origin.y = frameOfKeyboard.origin.y - frameOfInputView.size.height; //3.計算表格須要滾動的距離
    CGPoint offset = self.tableView.contentOffset; offset.y += frameOfKeyboard.size.height; //4.爲inputTextView添加動畫
    NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions options = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]; [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ //設置動畫結束時 輸入視圖的新的位置
         self.inputTextView.frame = frameOfInputView; //動畫結束時,修改表格的內容的位置
        self.tableView.contentOffset = offset; } completion:nil]; } //鍵盤收起時
-(void)keyboardDisappear:(NSNotification *)notification{ CGRect frameOfInputView = self.inputTextView.frame; frameOfInputView.origin.y = self.view.bounds.size.height - frameOfInputView.size.height; CGPoint newOffSet = CGPointMake(0,self.tableView.contentSize.height - self.tableView.frame.size.height); NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions options = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]; [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ self.inputTextView.frame = frameOfInputView; self.tableView.contentOffset = newOffSet; } completion:nil]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self forKeyPath:UIKeyboardWillShowNotification]; [center removeObserver:self forKeyPath:UIKeyboardWillHideNotification]; } // 點擊鍵盤右下角的return按鍵
- (IBAction)send:(UITextField *)sender { // NSLog(@"%f",self.tableView.contentSize.height);
    if (![self.textField.text isEqualToString:@""]) { TRMessage *message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = self.textField.text; //清空文本框
        self.textField.text = @""; //message對象添加到數據源
 [self.messages addObject:message]; //更新表視圖顯示新增長的消息
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; // NSLog(@"%f",self.tableView.contentSize.height);
 } //[self.textField resignFirstResponder];
} @end   故事板TRMessageViewController TRMessageCell   注意:第一個檢查器中關閉自動佈局,xib中image的第五個檢查器中,點亮的紅線只有保持上左便可,其餘的關閉就能夠了。tableView中第四個檢查器中,Separator改成None,去掉表格線。Selection 改成No Selection,實現運行的時候,去掉點擊時顯示的灰色區域 ======================================================================== 知識點 10、Search Bar 搜索欄 1.Search Bar(舊版本) 故事板中的添加了Search Bar 而後到第四個檢查器 點擊勾上Shows Scope Bar 單元格要記得在第四個檢查器中註冊identifier爲cell Product.h #import <Foundation/Foundation.h> typedef NS_ENUM(NSInteger, ProductType){ ProductTypeDevice, ProductTypeSoftware, ProductTypeOther }; /*定義商品類,包含名稱和類別*/
@interface Product : NSObject @property(nonatomic,strong)NSString *name; @property(nonatomic)ProductType type; +(NSArray *)demoData; @end Product.m #import "Product.h"

@implementation Product + (NSArray *)demoData{ Product *p1 = [[Product alloc]init]; p1.name = @"iPhone4s"; p1.type = ProductTypeDevice; Product *p2 = [[Product alloc]init]; p2.name = @"iPhone5s"; p2.type = ProductTypeDevice; Product *p3 = [[Product alloc]init]; p3.name = @"iPhone6"; p3.type = ProductTypeDevice; Product *p4 = [[Product alloc]init]; p4.name = @"iPhone6 Plus"; p4.type = ProductTypeDevice; Product *p5 = [[Product alloc]init]; p5.name = @"OS X Yosemite"; p5.type = ProductTypeSoftware; Product *p6 = [[Product alloc]init]; p6.name = @"Airport Time Capsule"; p6.type = ProductTypeOther; return @[p1,p2,p3,p4,p5,p6]; } @end ProductViewController.h #import <UIKit/UIKit.h>

@interface ProductViewController : UITableViewController @property(nonatomic,strong)NSArray *products; @end ProductViewController.m #import "ProductViewController.h"
#import "Product.h"

@interface ProductViewController ()<UISearchDisplayDelegate>
//聲明一個數組,用於存儲搜索到的結果內容
@property(nonatomic,strong)NSMutableArray *searchResult; @end

@implementation ProductViewController - (void)viewDidLoad { [super viewDidLoad]; self.products = [Product demoData]; //建立 searchResult 的實例
    self.searchResult = [NSMutableArray array]; //爲顯示數據的表格註冊單元格
    [self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; } /* 當前控制器已是兩個標題視圖的 代理對象了。 一個表視圖指的是TVC自帶的表視圖 另外一個表視圖指的是用於顯示搜索結果數據展現的表視圖 */

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //須要區分參數tableView究竟是self.tableView //仍是searchBar的resultTableView //return self.products.count;
    if (tableView == self.searchDisplayController.searchResultsTableView) { return self.searchResult.count; }else{ return self.products.count; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; Product *product = nil; if (tableView == self.view) { product = self.products[indexPath.row]; }else{ product = self.searchResult[indexPath.row]; } cell.textLabel.text = product.name; return cell; } //只要在搜索框中修改了搜索的內容,當即執行此方法
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{ //根據搜索框內寫的字符串進行比對 //生成搜索結果 //搜索須要兩個數據:文本框中輸入的+分段控件中選擇的搜索類別
    NSInteger type = self.searchDisplayController.searchBar.selectedScopeButtonIndex; [self updateContentForProductName:searchString andType:type]; return YES; } //只要選擇了搜索框下面的分段控件,該方法就執行
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption{ NSString *inputStr = self.searchDisplayController.searchBar.text; [self updateContentForProductName:inputStr andType:searchOption]; return YES; } // 根據輸入的文本和選擇的類別進行匹配
-(void)updateContentForProductName:(NSString *)searchString andType:(NSInteger )type{ NSMutableArray *array = [NSMutableArray array]; for (Product *p in self.products) { //查看字符串B在A中的位置及佔用的長度 //ABCDE -> BCD location = 1 lenght = 3
        NSRange range = [p.name rangeOfString:searchString]; if (range.length > 0 && p.type==type) { [array addObject:p]; } } self.searchResult = array; } @end    2.iOS8 Search Bar (Xcode6) 參考【Demo3_SearchBar_iOS8】 思想:建立類:用於展現搜索結果的控制器的顯示模型,在主控制器建立執行搜索動做的控制器並與 本身建立的類相聯繫,並設置搜索下邊的三項分類,而且將searchResultsUpdater和searchBar分別設置爲代理,遵照協議<UISearchResultsUpdating,UISearchBarDelegate> Product.h Product.m 同上 MainTableViewController.h #import <UIKit/UIKit.h>

@interface MainTableViewController : UITableViewController @property(nonatomic,strong)NSArray *products; @end MainTableViewController.m #import "MainTableViewController.h"
#import "SearchTableViewController.h"
#import "Product.h"

@interface MainTableViewController ()<UISearchResultsUpdating,UISearchBarDelegate>
//增長屬性:用於控制搜索結果顯示的控制器
@property(nonatomic,strong)SearchTableViewController *searchResultViewController; @property(nonatomic,strong)UISearchController *searchController; @end

@implementation MainTableViewController - (void)viewDidLoad { [super viewDidLoad]; self.products = [Product demoData]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; //建立用於展現搜索結果的控制器實例
    self.searchResultViewController = [[SearchTableViewController alloc]init]; //建立執行搜索動做的控制器,並制定哪一個控制器幫助它顯示結果
    self.searchController = [[UISearchController alloc]initWithSearchResultsController:self.searchResultViewController]; //設置搜索控制器的結果更新代理對象
    self.searchController.searchResultsUpdater = self; //設置顯示的bar的大小和樣式
 [self.searchController.searchBar sizeToFit]; self.searchController.searchBar.scopeButtonTitles = @[@"設備",@"軟件",@"其它"]; 顯示幾個按鈕是根據給幾個名字 //將搜索bar添加到表頭視圖
    self.tableView.tableHeaderView = self.searchController.searchBar; self.definesPresentationContext = YES; self.searchController.searchBar.delegate = self; } - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope{ [self updateSearchResultsForSearchController:self.searchController]; } #pragma mark - UISearchResultUpdating
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{ //用戶輸入的要搜索的文本信息
    NSString *searchText = searchController.searchBar.text; //獲取選擇的scope按鈕是哪一個
    NSInteger selectedScopeButton = searchController.searchBar.selectedScopeButtonIndex; NSLog(@"%ld",selectedScopeButton); NSMutableArray *searchResult = [NSMutableArray array]; for (Product *p in self.products) { NSRange range = [p.name rangeOfString:searchText]; if (range.length > 0 && p.type==selectedScopeButton) { [searchResult addObject:p]; } } self.searchResultViewController.resultArray = searchResult; [self.searchResultViewController.tableView reloadData]; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.products.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; Product *p = self.products[indexPath.row]; cell.textLabel.text = p.name; return cell; } @end SearchTableViewController.h #import <UIKit/UIKit.h>

@interface SearchTableViewController : UITableViewController @property(nonatomic,strong)NSArray *resultArray; @end SearchTableViewController.m #import "SearchTableViewController.h"
#import "Product.h"

@interface SearchTableViewController () @end

@implementation SearchTableViewController - (void)viewDidLoad { [super viewDidLoad]; // 註冊cell
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell2"]; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.resultArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell2" forIndexPath:indexPath]; Product *p = self.resultArray[indexPath.row]; cell.textLabel.text = p.name; return cell; } @end

1.Size Classes 隨着蘋果設備的增多,屏幕尺寸愈來愈多樣化,爲了解決適配不一樣設備屏幕的問題,從iOS8開始,推出了一項配合Auto layout一塊兒用的Size Classes技術 核心理念:拋棄屏幕尺寸的概念,將不一樣種類的設備劃分到不一樣的組合內,製做界面時,關注這一個組別,就等同於對這一個組別下的全部設備進行設計界面。運行時,系統會根據當前設備,判斷屬於哪一個組別,而後找到對應組別下的AutoLayout原則,依據此原則計算座標 有哪些組別? 劃分組別的標準: 緊湊型 any 標準型 根據右下角肯定,當選到any,便可以包括, 4.應用程序間的通訊 4.1 什麼是應用程序間的通信? 一個應用給另外一個應用發點信息過去,但不多,若是說,打開圖片庫、點擊分享、打印、共享 4.2 使用場景 將一個字符串或圖片發到微博、微信等應用上 4.3 如何作? 使用一個叫作UIActivityViewController控制器完成任務 4.4 Activity 把共享時要操做的項目叫作Activity,好比說,拷貝、打印——是 Activity中的操做,微信、微博這種Activity叫作分享 【Demo4_UIActivityViewController】 ViewController.h ViewController.m #import "ViewController.h"
#import "StringReverseActivity.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *textField; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)shared:(UIButton *)sender { NSString *text = self.textField.text; //第一步 建立Activity控制器 //activityItems:要傳遞的信息 //applicationActivities:寫nil,系統會 //列出支持的全部activity
    UIActivityViewController *avc = [[UIActivityViewController alloc]initWithActivityItems:@[text] applicationActivities:nil]; //第二步:設置排除的activity
    avc.excludedActivityTypes = @[UIActivityTypeMail]; //第三步:顯示出VC
 [self presentViewController:avc animated:YES completion:nil]; } - (IBAction)customActivity:(UIButton *)sender { NSArray *itemToShare = @[@"Hello",@"World",@12345]; //第一步建立自定義的Activity的對象
    StringReverseActivity *srActivity = [[StringReverseActivity alloc]init]; //第二步 添加activity到Activity控制器上
    UIActivityViewController *avc = [[UIActivityViewController alloc]initWithActivityItems:itemToShare applicationActivities:@[srActivity]]; //第三步 推出avc
 [self presentViewController:avc animated:YES completion:nil]; } @end

    4.5自定義的Activity step1:本身寫一個類,繼承UIActivity step2:實現類內的方法 類內的6個方法必須實現 【Demo4_UIActivityViewController】 接上面的編寫 StringReverseActivity.h StringReverseActivity.m #import "StringReverseActivity.h"

@interface StringReverseActivity ()<UIAlertViewDelegate> @property(nonatomic,strong)NSMutableArray *activityItems; @end

@implementation StringReverseActivity //第一個:返回本身的Activity的類型,只要惟一便可
-(NSString *)activityType{ //得到應用程序所在的沙箱的完整路徑 //NSStringFromClass是根據類,獲取類的名稱
    return [[NSBundle mainBundle].bundleIdentifier stringByAppendingFormat:@".%@",NSStringFromClass([self class])]; } //第二個:不要求惟一,但但願短一點 //返回activity的名稱
-(NSString *)activityTitle{ return @"反轉"; } //第三個:顯示的圖片 Retina: 86 X 86 ipad: 110 X 110
-(UIImage *)activityImage{ return  [UIImage imageNamed:@"icon80"]; 圖片尺寸不行,因此不顯示 } //第四個:將共享的item傳過的數據進行檢驗,看是否能夠反轉
-(BOOL)canPerformWithActivityItems:(NSArray *)activityItems{ for (id object in activityItems) { if ([object isKindOfClass:[NSString class]]) { //只要有一個string就調用反轉方法
            return YES; } } return NO; } //第5個:查找activity的條目,只要有一個item能用就會到達這個方法
- (void)prepareWithActivityItems:(NSArray *)activityItems{ //把全部能反轉的item挑出來,放到一個數組中
    NSMutableArray *stringObjects = [NSMutableArray array]; for (id object in activityItems) { if ([object isKindOfClass:[NSString class]]) { [stringObjects addObject:object]; } } self.activityItems = stringObjects; } //第6個:執行activity,編寫邏輯---反轉
-(void)performActivity{ // 爲了保存每個反轉後的string
    NSMutableString *reverseString = [[NSMutableString alloc]init]; //反轉
    for (NSString *string in self.activityItems) { [reverseString appendString:[self myReverseString:string]]; [reverseString appendString:@"\n"]; } //顯示反轉的結果
    UIAlertView *alert = [[UIAlertView  alloc]initWithTitle:@"字符串反轉" message:reverseString delegate:self cancelButtonTitle:@"肯定" otherButtonTitles:nil]; [alert show]; } //第7個:點擊alert中的肯定按鈕後,通知activity動做結束
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ [self activityDidFinish:YES]; } //自定義方法:執行字符串的反轉
-(NSString *)myReverseString:(NSString *)paramString { NSMutableString *reversed = [[NSMutableString alloc]init]; for (NSInteger index = paramString.length-1; index>=0; index--) { [reversed appendFormat:@"%c",[paramString characterAtIndex:index]]; } return [reversed copy]; } @end 系統默認,去掉了郵件 自定義,多增長了反轉 點擊反轉,只要是字符串就倒過來顯示     5.橫豎屏的判斷 【Demo5_All_Orientation】 1.設置屏幕支持的方向 2.獲取即將要旋轉到的某個朝向 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIView *greenVIew; @property (weak, nonatomic) IBOutlet UIButton *button1; @property (weak, nonatomic) IBOutlet UIButton *button2; @property (weak, nonatomic) IBOutlet UIButton *button3; @property (weak, nonatomic) IBOutlet UIButton *button4; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //1.設置屏幕支持的方向
- (NSUInteger)supportedInterfaceOrientations{ //設置支持的設備方向
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape; } //2.獲取即將要旋轉到的某個朝向
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{ //判斷即將到達的朝向,決定選中何種佈局
    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) { //豎屏
 [self layoutPortrait]; }else{ //橫屏
 [self layoutLandscape]; } } //自定義的方法,用於豎屏時佈局
-(void)layoutPortrait{ self.greenVIew.frame = CGRectMake(20, 20, self.view.bounds.size.width-20-20, self.view.bounds.size.height-20*4-35*2); CGRect frame = CGRectMake(20, self.view.bounds.size.height-20*2-35*2, 130, 35); self.button1.frame = frame; frame.origin.x +=130+20; self.button2.frame = frame; frame.origin.y += (35+20); self.button4.frame = frame; frame.origin.x -= (130+20); self.button3.frame = frame; } //自定義的方法,用於橫屏時佈局
-(void)layoutLandscape{ } //界面顯示前判斷好方向,界面顯示的時候佈置
-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; //判斷出來的那一刻的方向
    UIApplication *app = [UIApplication sharedApplication]; UIInterfaceOrientation orientation = app.statusBarOrientation; if (UIInterfaceOrientationIsPortrait(orientation)) { [self layoutPortrait]; }else{ [self layoutLandscape]; } } @end
相關文章
相關標籤/搜索