Swift 编写的一个 ToDo App

以下所有代码都是使用Xcode Version 6.0.1 (6A317)编写的。

由于团队开发的时候使用stroyboard在合并的时候有诸多不便,所有还是使用.xib文件编写这个ToDo App.

想要实现的功能是:TableView 上可以增加待做选项,并按照时间先后排序,可以实现删除,到点通知功能。

想要实现的效果如下:

     

步骤:

1、新建一个基于Singal View Application 的工程,然后删掉storyboard,在新建两个新文件 Main.xib 和 Main.swift 作为主要的ViewController,打开 Main.xib 将 File's Owner的l类属性改为 Main(这样才可以将关联变量拖动到 Mian.swift )。

Main.xib 页面UI,一个用于展示todo list 的 tableView,然后关联一个 tableView 变量到 Main.swift文件


2、接下来设置 Mian 为rootViewController,在AppDelegate.swift中做写如下代码:

  1. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
  2.        
  3.        var viewController = Main(nibName: "Main", bundle: nil
  4.        navigationController = UINavigationController(rootViewController: viewController) 
  5.         
  6.        self.window = UIWindow(frame: UIScreen.mainScreen().bounds
  7.        self.window?.rootViewController = navigationController 
  8.        self.window?.makeKeyAndVisible() 
  9.         
  10.        return true 
  11.    } 
 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
       
        var viewController = Main(nibName: "Main", bundle: nil)
        navigationController = UINavigationController(rootViewController: viewController)
        
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window?.rootViewController = navigationController
        self.window?.makeKeyAndVisible()
        
        return true
    }

注意: var viewController = Main(nibName: "Main", bundle: nil) ,用来将 Mian.xib 与 Mian.swift 进行绑定。run 一下你就可以看到界面了。

3、然后在Main.swift 中编写一下TableView 的数据源和代理的方法。这里我们用的是 自定义的 Cell。所有新建一个 Cell.xib 和 Cell.swift 并将它们关联起来,做法和上面的相同,Cell.xib UI 如下。


  1. func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
  2.         return 20 
  3.     } 
  4.      
  5.      
  6.     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
  7.         var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? Cell 
  8.         var str: String 
  9.         if (cell == nil) { 
  10.             let nibs:NSArray = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil
  11.             cell = nibs.lastObject as? Cell 
  12.         } 
  13.          
  14.         cell?.todoTitle.text = "toDoTitle" 
  15.         cell?.time.text = "\(NSDate())" 
  16.         cell?.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator 
  17.         return cell! 
  18.     } 
  19.      
  20.      
  21.     func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
  22.  
  23.     } 
  24.      
  25.      
  26.     func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
  27.         if editingStyle == UITableViewCellEditingStyle.Delete
  28.          
  29.         } 
  30.     } 
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }
    
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? Cell
        var str: String
        if (cell == nil) {
            let nibs:NSArray = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)
            cell = nibs.lastObject as? Cell
        }
        
        cell?.todoTitle.text = "toDoTitle"
        cell?.time.text = "\(NSDate())"
        cell?.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        return cell!
    }
    
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    }
    
    
    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == UITableViewCellEditingStyle.Delete {
        
        }
    }

run 一下就可以看到如下效果:


注意:考虑到UITableView的滚动性能,Cell 的重用非常重要,通过上面的 println(cell),滚动Cell,观察打印出来的 Cell 地址,可以看到 Cell 并没有进行重用。在

override func viewDidLoad() { } 中添加下面的代码使 Cell 重用。

  1. var bundle: NSBundle = NSBundle.mainBundle() 
  2.         var nib: UINib = UINib(nibName: "Cell", bundle: bundle) 
  3.         tableView.registerNib(nib, forCellReuseIdentifier: cellIdentifier) 
var bundle: NSBundle = NSBundle.mainBundle()
        var nib: UINib = UINib(nibName: "Cell", bundle: bundle)
        tableView.registerNib(nib, forCellReuseIdentifier: cellIdentifier)

4、以上讲到的都是些静态的数据,接下来我们做一些动态数据。

  4.1、在NavigationBar 增加一个 ‘+’ 按钮,用来给用户增加待做选项

  1. self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "addItem"
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "addItem")
响应函数:

  1. func addItem() { 
  2.         let addVC: Add = Add(nibName: "Add", bundle: nil
  3.         addVC.delegate = self
  4.         self.presentViewController(addVC, animated: true, completion: nil
  5.     } 
func addItem() {
        let addVC: Add = Add(nibName: "Add", bundle: nil)
        addVC.delegate = self;
        self.presentViewController(addVC, animated: true, completion: nil)
    }

4.2、新增一个 Add.xib 和 Add.swift 让用户输入待做选项,记得绑定(同步骤1),Add.xib UI如下:


为了在Main.swift 中接收到 Add.xib 中用户输入的信息,我们在 Add.swift 定义一个协议,然后Main.swift 遵循这个协议,在Add.xib 界面消失前获取用户输入信息。

  1. protocol AddProtocal { 
  2.     func didCompleted(addObject: Add) 
protocol AddProtocal {
    func didCompleted(addObject: Add)
}
Add.swift 代码如下:

  1. // 
  2. //  Add.swift 
  3. //  ToDoApp 
  4. // 
  5. //  Created by aaron on 14-9-17. 
  6. //  Copyright (c) 2014年 The Technology Studio. All rights reserved. 
  7. // 
  8.  
  9. import UIKit 
  10.  
  11. protocol AddProtocal { 
  12.     func didCompleted(addObject: Add) 
  13.  
  14.  
  15. class Add: UIViewController { 
  16.      
  17.     @IBOutlet var todo: UITextField! 
  18.     @IBOutlet var desc: KCTextView! 
  19.     @IBOutlet var time: UIDatePicker! 
  20.     @IBOutlet var completeBtn: UIButton! 
  21.     var delegate: AddProtocal? 
  22.      
  23.     required init(coder aDecoder: NSCoder) { 
  24.         super.init(coder: aDecoder) 
  25.     } 
  26.      
  27.     override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 
  28.         super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 
  29.     } 
  30.      
  31.      
  32.     override func viewWillAppear(animated: Bool) { 
  33.         setup() 
  34.     } 
  35.      
  36.     func setup() { 
  37.         completeBtn.layer.cornerRadius = 5.0 
  38.         todo.placeholder = "请输入待做项" 
  39. //        desc.placeholder = "请输入详细描述。" 
  40.         todo.text = self.todo.text 
  41.         desc.text = self.desc.text 
  42.         time.date = self.time.date 
  43.         time.minimumDate = NSDate.date() 
  44.          
  45.         if delegate? == nil
  46.             todo.textColor = UIColor.lightGrayColor() 
  47.             todo.userInteractionEnabled = false 
  48.             desc.textColor = UIColor.lightGrayColor() 
  49.             desc.userInteractionEnabled = false 
  50.             time.userInteractionEnabled = false 
  51.             completeBtn.setTitle("好", forState: UIControlState.Normal
  52.         }else
  53.             todo.textColor = UIColor.blackColor() 
  54.             todo.userInteractionEnabled = true 
  55.             desc.textColor = UIColor.blackColor() 
  56.             desc.userInteractionEnabled = true 
  57.             time.userInteractionEnabled = true 
  58.             completeBtn.setTitle("完成", forState: UIControlState.Normal
  59.         } 
  60.          
  61.         let swipeGesture = UISwipeGestureRecognizer(target: self, action:"hideKeyboard"
  62.         swipeGesture.direction = UISwipeGestureRecognizerDirection.Down 
  63.         swipeGesture.numberOfTouchesRequired = 1 
  64.         self.view.addGestureRecognizer(swipeGesture) 
  65.          
  66.         
  67.     } 
  68.      
  69.     func hideKeyboard() { 
  70.         println("swipeGesture...."
  71.         todo.resignFirstResponder() 
  72.         desc.resignFirstResponder() 
  73.     } 
  74.      
  75.     func shakeAnimation(sender: AnyObject) { 
  76.         let animation = CAKeyframeAnimation() 
  77.         animation.keyPath = "position.x" 
  78.         animation.values = [0, 10, -10, 10, 0
  79.         animation.keyTimes = [0, 1/6.0, 3/6.0, 5/6.0, 1
  80.         animation.duration = 0.4 
  81.         animation.additive = true 
  82.         sender.layer.addAnimation(animation, forKey: "shake"
  83.     } 
  84.      
  85.      
  86.      
  87.     @IBAction func completeTouch(sender: AnyObject) { 
  88.         if (countElements(todo.text) > 0){ 
  89.             delegate?.didCompleted(self
  90.             self.dismissViewControllerAnimated(true, completion: nil
  91.         }else
  92.             shakeAnimation(todo) 
  93.         } 
  94.     } 
  95.     @IBAction func editingDidEnd(sender: UITextField) { 
  96.         if (countElements(sender.text) == 0) { 
  97.            shakeAnimation(todo) 
  98.         } 
  99.          
  100.     } 
  101.      
//
//  Add.swift
//  ToDoApp
//
//  Created by aaron on 14-9-17.
//  Copyright (c) 2014年 The Technology Studio. All rights reserved.
//

import UIKit

protocol AddProtocal {
    func didCompleted(addObject: Add)
}


class Add: UIViewController {
    
    @IBOutlet var todo: UITextField!
    @IBOutlet var desc: KCTextView!
    @IBOutlet var time: UIDatePicker!
    @IBOutlet var completeBtn: UIButton!
    var delegate: AddProtocal?
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    
    override func viewWillAppear(animated: Bool) {
        setup()
    }
    
    func setup() {
        completeBtn.layer.cornerRadius = 5.0
        todo.placeholder = "请输入待做项"
//        desc.placeholder = "请输入详细描述。"
        todo.text = self.todo.text
        desc.text = self.desc.text
        time.date = self.time.date
        time.minimumDate = NSDate.date()
        
        if delegate? == nil {
            todo.textColor = UIColor.lightGrayColor()
            todo.userInteractionEnabled = false
            desc.textColor = UIColor.lightGrayColor()
            desc.userInteractionEnabled = false
            time.userInteractionEnabled = false
            completeBtn.setTitle("好", forState: UIControlState.Normal)
        }else {
            todo.textColor = UIColor.blackColor()
            todo.userInteractionEnabled = true
            desc.textColor = UIColor.blackColor()
            desc.userInteractionEnabled = true
            time.userInteractionEnabled = true
            completeBtn.setTitle("完成", forState: UIControlState.Normal)
        }
        
        let swipeGesture = UISwipeGestureRecognizer(target: self, action:"hideKeyboard")
        swipeGesture.direction = UISwipeGestureRecognizerDirection.Down
        swipeGesture.numberOfTouchesRequired = 1
        self.view.addGestureRecognizer(swipeGesture)
        
       
    }
    
    func hideKeyboard() {
        println("swipeGesture....")
        todo.resignFirstResponder()
        desc.resignFirstResponder()
    }
    
    func shakeAnimation(sender: AnyObject) {
        let animation = CAKeyframeAnimation()
        animation.keyPath = "position.x"
        animation.values = [0, 10, -10, 10, 0]
        animation.keyTimes = [0, 1/6.0, 3/6.0, 5/6.0, 1]
        animation.duration = 0.4
        animation.additive = true
        sender.layer.addAnimation(animation, forKey: "shake")
    }
    
    
    
    @IBAction func completeTouch(sender: AnyObject) {
        if (countElements(todo.text) > 0){
            delegate?.didCompleted(self)
            self.dismissViewControllerAnimated(true, completion: nil)
        }else{
            shakeAnimation(todo)
        }
    }
    @IBAction func editingDidEnd(sender: UITextField) {
        if (countElements(sender.text) == 0) {
           shakeAnimation(todo)
        }
        
    }
    
}

ToDo项为空时会有一个小小的提示动画:


Add.swift 中的关联变量 desc 是UITextView 类型的,UITextView 不像 UITextField 有 placeHolder ,所以这里我们引入一个 OC 写的 KCTextView ,由 KCTextView 代替 UITextView,swift 中引用 OC 写的 API 容易,新建一个 .h ,把你需要用到的头文件统统写在里面,然后 Build Settings 中的 Object-C Bridging Header 写入 .h 文件的路径即可,接着就可以正常使用 OC 写的接口了。



Main.swift 实现 AddProtocal,并实现协议规定的函数:

  1. func didCompleted(addObject: Add) { 
  2.    
  3.         toDoData.append(addObject) 
  4.         tableView.reloadData() 
func didCompleted(addObject: Add) {
  
        toDoData.append(addObject)
        tableView.reloadData()
}
toDoData的是一个 Add类型的可变数组。

Main.swift 代码如下:

  1. // 
  2. //  Main.swift 
  3. //  ToDoApp 
  4. // 
  5. //  Created by aaron on 14-9-16. 
  6. //  Copyright (c) 2014年 The Technology Studio. All rights reserved. 
  7. // 
  8.  
  9. import UIKit 
  10.  
  11. class Main: UIViewController, UITableViewDataSource, UITableViewDelegate, AddProtocal { 
  12.  
  13.     @IBOutlet var tableView: UITableView! 
  14.     let cellIdentifier = "Cell" 
  15.  
  16.     var toDoData = [Add]() 
  17.      
  18.      
  19.     override func viewDidLoad() { 
  20.         super.viewDidLoad() 
  21.         setup() 
  22.         registerCell() 
  23.     } 
  24.      
  25.     func setup() { 
  26.         self.title = "To Do List" 
  27.         self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "addItem"
  28.  
  29.     } 
  30.      
  31.     func registerCell() { 
  32.         var bundle: NSBundle = NSBundle.mainBundle() 
  33.         var nib: UINib = UINib(nibName: "Cell", bundle: bundle) 
  34.         tableView.registerNib(nib, forCellReuseIdentifier: cellIdentifier) 
  35.     } 
  36.      
  37.      
  38.     func addItem() { 
  39.         let addVC: Add = Add(nibName: "Add", bundle: nil
  40.         addVC.delegate = self
  41.         self.presentViewController(addVC, animated: true, completion: nil
  42.     } 
  43.      
  44.     func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
  45.         return toDoData.count 
  46.     } 
  47.      
  48.      
  49.     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
  50.         var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? Cell 
  51.         var str: String 
  52.         if (cell == nil) { 
  53.             let nibs:NSArray = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil
  54.             cell = nibs.lastObject as? Cell 
  55.         } 
  56.          
  57.         let addObject = toDoData[indexPath.row] as Add 
  58.         cell?.todoTitle.text = addObject.todo.text 
  59.         cell?.time.text = dateFormatter(addObject.time.date
  60.         cell?.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator 
  61.         return cell! 
  62.     } 
  63.      
  64.      
  65.     func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
  66.         let addVC = toDoData[indexPath.row] as Add 
  67.         addVC.delegate = nil 
  68.         self.presentViewController(addVC, animated: true, completion: nil
  69.     } 
  70.      
  71.      
  72.     func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
  73.         if editingStyle == UITableViewCellEditingStyle.Delete
  74.             toDoData.removeAtIndex(indexPath.row
  75.             tableView.reloadData() 
  76.         } 
  77.     } 
  78.      
  79.   
  80.     func didCompleted(addObject: Add) { 
  81.    
  82.         toDoData.append(addObject) 
  83.         toDoData.sort({ self.dateFormatter($0.time.date) < self.dateFormatter($1.time.date)})//按时间排序 
  84.         tableView.reloadData() 
  85.          
  86.  
  87.     } 
  88.      
  89.      
  90.     func dateFormatter(date: NSDate) -> String { 
  91.         let formatter = NSDateFormatter() 
  92.         formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" 
  93.         formatter.locale = NSLocale(localeIdentifier: NSGregorianCalendar) 
  94.         let dateStr = formatter.stringFromDate(date) 
  95.         return dateStr 
  96.     } 
  97.  
  98.     override func didReceiveMemoryWarning() { 
  99.         super.didReceiveMemoryWarning() 
  100.         // Dispose of any resources that can be recreated. 
  101.     } 
  102.  
  103.  
//
//  Main.swift
//  ToDoApp
//
//  Created by aaron on 14-9-16.
//  Copyright (c) 2014年 The Technology Studio. All rights reserved.
//

import UIKit

class Main: UIViewController, UITableViewDataSource, UITableViewDelegate, AddProtocal {

    @IBOutlet var tableView: UITableView!
    let cellIdentifier = "Cell"

    var toDoData = [Add]()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
        registerCell()
    }
    
    func setup() {
        self.title = "To Do List"
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "addItem")

    }
    
    func registerCell() {
        var bundle: NSBundle = NSBundle.mainBundle()
        var nib: UINib = UINib(nibName: "Cell", bundle: bundle)
        tableView.registerNib(nib, forCellReuseIdentifier: cellIdentifier)
    }
    
    
    func addItem() {
        let addVC: Add = Add(nibName: "Add", bundle: nil)
        addVC.delegate = self;
        self.presentViewController(addVC, animated: true, completion: nil)
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return toDoData.count
    }
    
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? Cell
        var str: String
        if (cell == nil) {
            let nibs:NSArray = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)
            cell = nibs.lastObject as? Cell
        }
        
        let addObject = toDoData[indexPath.row] as Add
        cell?.todoTitle.text = addObject.todo.text
        cell?.time.text = dateFormatter(addObject.time.date)
        cell?.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        return cell!
    }
    
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let addVC = toDoData[indexPath.row] as Add
        addVC.delegate = nil
        self.presentViewController(addVC, animated: true, completion: nil)
    }
    
    
    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == UITableViewCellEditingStyle.Delete {
            toDoData.removeAtIndex(indexPath.row)
            tableView.reloadData()
        }
    }
    
 
    func didCompleted(addObject: Add) {
  
        toDoData.append(addObject)
        toDoData.sort({ self.dateFormatter($0.time.date) < self.dateFormatter($1.time.date)})//按时间排序
        tableView.reloadData()
        

    }
    
    
    func dateFormatter(date: NSDate) -> String {
        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        formatter.locale = NSLocale(localeIdentifier: NSGregorianCalendar)
        let dateStr = formatter.stringFromDate(date)
        return dateStr
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

最后你大概可以看到这样的效果:


5、最后一步,为待做项目添加通知功能,这一功能在之前的文章(ios8 notifacation in swift)中就讲过了,这里就不重复写了。完整的项目代码我发在github上来,需要的到这里拿。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值