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

1 篇文章 0 订阅
1 篇文章 0 订阅

纯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)
        })
    }

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值