Lesson - 1
設置 tabBar 的三個 viewController
-
設置三個 tabBarController 的圖片和選中時候的顏色
tabBarController.tabbar.tintColor = [UIColor colorWithRed:80/255.0 green:150/255.0 blue:130/255.0 alpha:1];
-
設置 icon 和啟動圖片
- icon 有對應的尺寸, 像素為 點數x 放大倍數
- 設置 app 名字可以在 info.plist 中添加
Bundle display name
字段, 對應的 string 值為 app 的名字
Lesson - 2
- 點擊第二個 Tab 彈出掃碼界面
- 截取 tabBar 的點擊事件, 通過設置 delegate 實現
- 重寫
- tabBarController: shouldSelectViewController:
這個方法, 在方法中判斷, 如果當前 view 是第二個視圖, 則return NO
, 達到不選中第二個 tab 的效果
- 左上角返回按鈕, 右上角開啟和關閉手電筒
- 因為要在左上角和右上角分別實現一個按鈕, 則將 scannerViewController 嵌套在 navigationController 中
- 將導航欄設置成透明, 并且把導航欄底部的線刪除了
self.navigationController.navigationBar.translucent = YES;
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
- 掃面界面的 UI 實現
- 需要將掃描 View 的幾個內容暴露在外初始化: 掃描區域的大小, 掃描區域相對于中心點的偏移量
- 繪制半透明遮罩 (由四個矩形組成)
- 繪制中間掃描區域的白色描邊
- 繪制中間掃描區域的四個角落
- 給掃描區域中的掃描線添加動畫, 使用了 CABasicAnimation
- 識別 ISBN, 設置預覽畫面, 通過真機運行
self.captureSession = [[AVCaptureSession alloc] init];
// 事務開始配置
[self.captureSession beginConfiguration];
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice
error:&error];
// 捕獲錯誤, 如果沒有錯誤則繼續執行
if (error) {
NSLog(@"Input device error : %@", error);
return;
}
if ([self.captureSession canAddInput:captureInput]) {
[self.captureSession addInput:captureInput];
}
// 設置輸出
AVCaptureMetadataOutput *captureOutput = [[AVCaptureMetadataOutput alloc] init];
// 設置了代理, 需要實現代理中的方法
[captureOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
if ([self.captureSession canAddOutput:captureOutput]) {
[self.captureSession addOutput:captureOutput];
captureOutput.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code];
}
// 添加預覽畫面
CALayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
layer.frame = self.view.layer.bounds;
[self.view.layer addSublayer:layer];
// 事務結束配置
[self.captureSession commitConfiguration];
// 事務開始運行
[self.captureSession startRunning];
#pragma mark - 通過代理方法, 進行 ISBN 識別
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
NSString *ISBN = nil;
AVMetadataObject *metadata = [metadataObjects firstObject];
ISBN = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
if (ISBN != nil) {
NSLog(@"%@", ISBN);
// [self fetchBookWithISBN:ISBN];
[self AFNetworkingFetchBookWithISBN:ISBN];
}
[self.captureSession stopRunning];
[self.scanView stopAnimation];
}
-
使用豆瓣 API 查詢書籍的詳細信息
- 使用 AFNetworking 框架發送 get 請求
// 豆瓣通過 isbn 查詢書籍信息的 api 為 https://api.douban.com/v2/book/isbn/:name NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.douban.com/v2/book/isbn/%@", ISBN]]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSessionTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { if (error) { NSLog(@"%@", error); return ; } // NSLog(@"%@, %@", response, responseObject); // 對 responseObject 進行處理, 顯示彈窗等 }]; [task resume];
-
在進行獲取書籍信息的時候, 顯示 loading 狀態
// 在后臺進行網絡數據的獲取 // 網絡數據獲取開始之前, 顯示加載狀態 // 網絡數據獲取之后, 在顯示彈窗之前, 將加載狀態的 view 隱藏 // 在主線程顯示加載中 dispatch_async(dispatch_get_main_queue(), ^{ [self showLoadingView]; }); NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.douban.com/v2/book/isbn/%@", ISBN]]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSessionTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { if (error) { NSLog(@"%@", error); return ; }
// NSLog(@"%@, %@", response, responseObject);
NSString *title = [responseObject objectForKey:@"title"];
NSString *author = [[responseObject objectForKey:@"author"] firstObject];
NSString *alertMsg = [NSString stringWithFormat:@"%@\n%@\n%@", title, ISBN, author];
// 主線程操作
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
/****** 進行彈窗的操作 ******/
});
}];
[task resume];
```
-
升到iOS10之后,需要設置權限的有:
麥克風權限:Privacy - Microphone Usage Description 是否允許此App使用你的麥克風? 相機權限:Privacy - Camera Usage Description 是否允許此App使用你的相機? 相冊權限:Privacy - Photo Library Usage Description 是否允許此App訪問你的媒體資料庫? 通訊錄權限:Privacy - Contacts Usage Description 是否允許此App訪問你的通訊錄? 藍牙權限:Privacy - Bluetooth Peripheral Usage Description 是否許允此App使用藍牙? 語音轉文字權限:Privacy - Speech Recognition Usage Description 是否允許此App使用語音識別? 日歷權限:Privacy - Calendars Usage Description 定位權限:Privacy - Location When In Use Usage Description 定位權限: Privacy - Location Always Usage Description 位置權限:Privacy - Location Usage Description 媒體庫權限:Privacy - Media Library Usage Description 健康分享權限:Privacy - Health Share Usage Description 健康更新權限:Privacy - Health Update Usage Description 運動使用權限:Privacy - Motion Usage Description 音樂權限:Privacy - Music Usage Description 提醒使用權限:Privacy - Reminders Usage Description Siri使用權限:Privacy - Siri Usage Description 電視供應商使用權限:Privacy - TV Provider Usage Description 視頻用戶賬號使用權限:Privacy - Video Subscriber Account Usage Description
AVAuthorizationStatus authStatus = [AVCaptureDeviceauthorizationStatusForMediaType:AVMediaTypeVideo];
if (authStatus ==AVAuthorizationStatusRestricted || authStatus ==AVAuthorizationStatusDenied) {
// 權限為開啟 (此應用程序沒有被授權訪問的照片數據。可能是家長控制權限)
}
Lesson - 3
- 書籍詳情頁面布局
- 導航欄透明
- 透過導航欄可以看到背面的一個 imageView, 橙色的
- 左上角為返回按鈕
- 橙色背景上的內容為書籍的基本信息, 可以滾動
- 下部分為書籍的詳細信息, 可以滾動
- 書籍的基本信息和詳細信息在同一個 scrollView 上, 當 scrollView 向上滾動的時候, 詳細信息的視圖會遮住背景, 當 scrollView 向下滾動的時候, 設置代理, 將背景圖片的高度拉伸, 造成下拉的效果
IMG.PNG
- 設計數據庫的表結構
return @[
@"CREATE TABLE IF NOT EXISTS 'TB_BOOK_ENTITY' \
('id' INTEGER PRIMARY KEY AUTOINCREMENT, \
'doubanId' INTEGER UNIQUE, 'isbn10' TEXT, 'isbn13' TEXT, \
'title' TEXT, 'doubanURL' TEXT, 'imageURL' TEXT, 'publisher' TEXT, \
'pubdate' TEXT, 'price' TEXT, 'summary' TEXT, 'author_intro' TEXT)",
@"CREATE TABLE IF NOT EXISTS 'TB_BOOK_AUTHOR' \
('bookId' INTEGER, 'name' TEXT)",
@"CREATE TABLE IF NOT EXISTS 'TB_BOOK_TRANSLATOR' \
('bookId' INTEGER, 'name' TEXT)",
@"CREATE TABLE IF NOT EXISTS 'TB_BOOK_TAG' \
('bookId' INTEGER, 'name' TEXT, 'count' INTEGER)"
];
}
- 分層, 添加 DAO (Data Access Object) & Service 層
- DAO
- 與 Model 一一對應, 對應 Model 的增刪改查等功能, 只和一個 Model 進行通信
- insertModel
- queryModel
- deleteModel
- Service
- 跨表, 跨 DAO 進行操作
- 適用于業務場景的調用, 應對單獨的增刪改查操作
- DAO