iOS纯Swift代码构建一个功能完善的APP

Posted yofer张耀琦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS纯Swift代码构建一个功能完善的APP相关的知识,希望对你有一定的参考价值。

纯Swift代码构建一个功能完善的APP

源代码地址:https://github.com/yoferzhang/FoodPin

效果演示

ios11之后,导航栏可以设置这样变大的效果。

在 ViewController 的 viewDidLoad() 方法中添加下面这行代码可以实现:

    // iOS11之后这个属性可以让导航栏往下滑动的时候title变大
    navigationController?.navigationBar.prefersLargeTitles = true

向右滑动菜单:

向左滑动菜单:

tableView,actionSheet

详情页面

导航栏透明,并修改大字体状态的title颜色, viewDidLoad()

    navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
    navigationController?.navigationBar.shadowImage = UIImage()
    
    // 设置导航栏title的大字体状态的颜色
    if let customFont = UIFont(name: "PingFangSC-Medium", size: 40.0) 
        navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 231.0/255.0, green: 76.0/255.0, blue: 60.0/255.0, alpha: 1.0), NSAttributedString.Key.font: customFont]
    

详情页面的导航栏变透明,返回按钮变色

        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        navigationController?.navigationBar.shadowImage = UIImage()
        navigationController?.navigationBar.tintColor = UIColor.white

调整tableView的顶部位置

        detailTableView.contentInsetAdjustmentBehavior = .never

全局修改导航栏的返回按钮 application(_:didFinishLaunchingWithOptions:) 中添加

        let backButtonImage = UIImage(named: "back")
        UINavigationBar.appearance().backIndicatorImage = backButtonImage
        UINavigationBar.appearance().backIndicatorTransitionMaskImage = backButtonImage

修改详情页状态栏,

    /// 状态栏颜色
    override var preferredStatusBarStyle: UIStatusBarStyle 
        return .lightContent
    

可以没有生效,因为会用导航栏controller的颜色,为了让可以针对性修改页面,加一个Extension文件,UINavigationController+Ext.swift

import UIKit

extension UINavigationController 
    open override var childForStatusBarStyle: UIViewController? 
        return topViewController
    


添加地图信息

自定义 annotationView,实现 MKMapViewDelegate

    //MARK: - MKMapViewDelegate
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? 
        let identifier = "MyMarker"
        
        if annotation.isKind(of: MKUserLocation.self) 
            return nil
        
        
        // Reuse the annotation if possible
        var annotationView: MKMarkerAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView
        
        if annotationView == nil 
            annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        
        
        annotationView?.glyphText = "?"
        annotationView?.markerTintColor = UIColor.orange
        
        return annotationView
    

        mapView.showsTraffic = true
        mapView.showsScale = true
        mapView.showsCompass = true

测试一些动画

代理回调,将选择的表情回调给详情页,展示在 headerView 的右下角

静态列表,textField使用

图片选择器

改用 CoreData 存储数据,并用 NSFetchedResultsController 监听;新建局部刷新首页 tableview

删除后,局部刷新首页 tableview

    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? 
        let deleteAction = UIContextualAction(style: .destructive, title: "Delete")  (action, soureView, comletionHandler) in
            if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) 
                let context = appDelegate.persistentContainer.viewContext
                
                if let currentVC = self.currentViewController() as? YQRestaurantTableViewController 
                    let restaurantToDelete = currentVC.fetchResultController.object(at: indexPath)
                    context.delete(restaurantToDelete)
                    
                    appDelegate.saveContext()
                
                
            
            
            comletionHandler(true)
        

更新rating 表情,同样是数据库级别的更新,加 appDelegate.saveContext() 就可以

    //MARK: - YQRestaurantReviewViewControllerDelegate
    func onClickRateButtonInReviewVC(rate: RateModel) 
        restaurant.rating = rate.image
        refreshRatingImageView(rateImage: rate.image)
        
        if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) 
            appDelegate.saveContext()
        
    

添加搜索栏,支持name搜索,搜索状态时禁止左右滑动的编辑态

tabBarController

About页面;使用元组;分别用 WKWebViewSFSafariViewController 打开web页面

使用iCloud,在 CloudKit Dashboard 中创建数据;原本是想上传图片,但 Dashboard 一上传那图片就 停止响应了,苹果这个做的有点坑==

然后用 Convenience API:

    func fetchRecordsFromCloud() 
        let cloudContainer = CKContainer.default()
        let publicDatabase = cloudContainer.publicCloudDatabase
        let predicate = NSPredicate(value: true)
        let query = CKQuery(recordType: "Restaurant", predicate: predicate)

        publicDatabase.perform(query, inZoneWith: nil)  (results, error) in
            if let error = error 
                print(error)
                return
            

            if let results = results 
                print("Completed the download of Restaurant data")
                self.restaurants = results
                DispatchQueue.main.async(execute: 
                    self.discoverTableView.reloadData()
                )
            
        
    

代码中拉取到的数据结构:

改用 Operational API。因为 Convenience API 不能只请求携带某些字段,它会把所有数据都完整拉下来

    func fetchRecordsFromCloud() 
        let cloudContainer = CKContainer.default()
        let publicDatabase = cloudContainer.publicCloudDatabase
        let predicate = NSPredicate(value: true)
        let query = CKQuery(recordType: "Restaurant", predicate: predicate)
        
        let queryOperation = CKQueryOperation(query: query)
        queryOperation.desiredKeys = ["name", "iamge"]
        queryOperation.queuePriority = .veryHigh
        queryOperation.resultsLimit = 50
        queryOperation.recordFetchedBlock =  (record) -> Void in
            self.restaurants.append(record)
        
        
        queryOperation.queryCompletionBlock =  [unowned self] (cursor, error) -> Void in
            if let error = error 
                print("Failed to get data from iCloud -\\(error.localizedDescription)")
                
                return
            
            
            print("Successfully retrieve the data from iCloud")
            DispatchQueue.main.async(execute: 
                self.discoverTableView.reloadData()
            )
        
        
        publicDatabase.add(queryOperation)
    

使用 UIActivityIndicatorViewUIRefreshControl

将数据存储到iCloud

    func saveRecordToCloud(restaurant: RestaurantMO!) -> Void 
        // Prepare the record to save
        let record = CKRecord(recordType: "Restaurant")
        record.setValue(restaurant.name, forKey: "name")
        record.setValue(restaurant.type, forKey: "type")
        record.setValue(restaurant.location, forKey: "location")
        record.setValue(restaurant.phone, forKey: "phone")
        record.setValue(restaurant.summary, forKey: "description")
        
        let imageData = restaurant.image! as Data
        
        // Resize the image
        let originalImage = UIImage(data: imageData)!
        let scalingFactor = (originalImage.size.width > 1024) ? 1024 / originalImage.size.width : 1.0
        let scaledImage = UIImage(data: imageData, scale: scalingFactor)
        
        // Write the image to local file for temporary use
        let imageFilePath = NSTemporaryDirectory() + restaurant.name!
        let imageFileURL = URL(fileURLWithPath: imageFilePath)
        try? scaledImage?.jpegData(compressionQuality: 0.8)?.write(to: imageFileURL)
        
        // Create image asset for upload
        let imageAsset = CKAsset(fileURL: imageFileURL)
        record.setValue(imageAsset, forKey: "image")
        
        // Get the Public iCloud Database
        let publicDatabase = CKContainer.default().publicCloudDatabase
        
        // Save the record to iCloud
        publicDatabase.save(record, completionHandler:  (record, error) -> Void in
            // Remove temp file
            try? FileManager.default.removeItem(at: imageFileURL)
        )
    

以上是关于iOS纯Swift代码构建一个功能完善的APP的主要内容,如果未能解决你的问题,请参考以下文章

ipad版简单美团界面功能实现(纯swift编写)

美丽说demo(纯swift代码)

iOS 多国语言本地化与App内语言切换(Swift)

iOS开发——实用篇Swift篇&QQ登入界面实现

转iOS的APP资源,开源的哦

从零开始的iOS开发:10 | 如何构建一个APP