私家書藏 - iOS 實戰

Lesson - 1

  1. 設置 tabBar 的三個 viewController

  2. 設置三個 tabBarController 的圖片和選中時候的顏色

    tabBarController.tabbar.tintColor = [UIColor colorWithRed:80/255.0 green:150/255.0 blue:130/255.0 alpha:1];
    
  3. 設置 icon 和啟動圖片

    • icon 有對應的尺寸, 像素為 點數x 放大倍數
    • 設置 app 名字可以在 info.plist 中添加 Bundle display name 字段, 對應的 string 值為 app 的名字

Lesson - 2

  1. 點擊第二個 Tab 彈出掃碼界面
    • 截取 tabBar 的點擊事件, 通過設置 delegate 實現
    • 重寫 - tabBarController: shouldSelectViewController: 這個方法, 在方法中判斷, 如果當前 view 是第二個視圖, 則 return NO, 達到不選中第二個 tab 的效果
  2. 左上角返回按鈕, 右上角開啟和關閉手電筒
    • 因為要在左上角和右上角分別實現一個按鈕, 則將 scannerViewController 嵌套在 navigationController 中
    • 將導航欄設置成透明, 并且把導航欄底部的線刪除了
self.navigationController.navigationBar.translucent = YES;
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
  1. 掃面界面的 UI 實現
    • 需要將掃描 View 的幾個內容暴露在外初始化: 掃描區域的大小, 掃描區域相對于中心點的偏移量
    • 繪制半透明遮罩 (由四個矩形組成)
    • 繪制中間掃描區域的白色描邊
    • 繪制中間掃描區域的四個角落
    • 給掃描區域中的掃描線添加動畫, 使用了 CABasicAnimation
  2. 識別 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];
}

  1. 使用豆瓣 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];
    
  2. 在進行獲取書籍信息的時候, 顯示 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];
```
  1. 升到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 進行操作
      • 適用于業務場景的調用, 應對單獨的增刪改查操作
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容