1.制作新增界面UI
进入Main界面,选中当前页面,点击右下角,选择Navigation Controller.Navigation Controller是一个容器,用于控制页面跳转.
新建一个Table View Controller,作为跳转之后的页面.
选中Table View,将他的Content改为Static Cells.
选中Table View Section,将Rows改为1.
将Table View的Style改为Inset Grouped.
选中首页的Navigation Otem,将Title改为待办事项.
2.制作主界面新增按钮
要在Navigetion Item中新增按钮,需要使用Bar Button Item.拉到待办事项的右侧,作为新增待办事项的加号➕.
将Item的Tint和Image改成相应的样式.
3.跳转
将加号按钮Ctrl加拖拽到右边的Table View Controller页面.
拖拽并选择后呈现效果如下.
4.将"待办事项"修改为大标题.
选中Navigation Controller的Navigation Bar,勾选Prefers Large Titles.启动运行即可发现,"待办事项已经成为了大标题.
5.将新增页面上的"<待办事项"这个返回按钮修改成一个返回图标.
新增一个Bar Butten Item,拖拽覆盖掉"<待办事项".在界面右上角也添加一个Bar Butten Item作为完成图标.
将返回键的图标修改成对应样式.
为完成键添加对应样式.
6.新增一个CocoaTouch Class类型的class,类型选择为UITableViewController,取名为TodoTableViewController.
在新增页中连接Class:TodoTableViewController.
创建返回按钮的IBAction:back.
创建完成按钮的IBAction:done.
为back和done编写代码使点击他们能够返回首页.
TodoTableViewController:
import UIKit
class TodoTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func back(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
@IBAction func done(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
}
7.将新增图标,返回图标,完成图标变大.
Constants:
import Foundation
import UIKit
let kTodoCellID = "TodoCellID"
//将图标变大的方法
func pointIcon(_ iconName: String, _ pointSize: CGFloat = 22) -> UIImage{
let config = UIImage.SymbolConfiguration(pointSize: pointSize)
return UIImage(systemName:iconName, withConfiguration: config)!
}
TodosViewController:
import UIKit
class TodosViewController: UITableViewController {
var todos = [
Todo(name: "学习iOS课程的基础课", checked: false),
Todo(name: "学习iOS课程的零基础赏月App开发", checked: true),
Todo(name: "学习iOS课程的零基础木琴App开发", checked: false),
Todo(name: "学习iOS课程的零基础和风天气App开发", checked: false),
Todo(name: "学习iOS课程的零基础待办事项App开发", checked: false),
Todo(name: "学习iOS课程的小红书App开发", checked: false)
]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem?.image = pointIcon("plus.circle.fill")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
//配置TableView的一些数据
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1 //总共有1个分类
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return todos.count //总共有10个待办事项
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //此函数会根据上面两个函数(总共分类数和总共待办事项数)返回的内容多次执行
let cell = tableView.dequeueReusableCell(withIdentifier: kTodoCellID , for: indexPath) as! TodoCell
let checkBoxBtn = cell.checkBoxBtn!
let todoLabel = cell.todoLable!
let initSelected = todos[indexPath.row].checked
// // Configure the cell...
// //配置主标题的文本
// var contentConfiguration = cell.defaultContentConfiguration()
// contentConfiguration.text = "昵称" //主标题
// contentConfiguration.secondaryText = "个性签名" //副标题
// contentConfiguration.image = UIImage(systemName: "star") //图片
// cell.contentConfiguration = contentConfiguration
checkBoxBtn.isSelected = initSelected //将cell的是否被选中属性改为todos的当前行的checked属性
todoLabel.text = todos[indexPath.row].name
todoLabel.textColor = initSelected ? .tertiaryLabel : .label //三元运算符.根据是否被选中进行判断,如果被选中的话变成浅色,未被选中就是原来的Lable Color.
cell.checkBoxBtn.addAction(UIAction(handler: { action in
self.todos[indexPath.row].checked.toggle() //如果check原来是true,被点击之后就进行取反,变成false.
let checked = self.todos[indexPath.row].checked
checkBoxBtn.isSelected = checked
todoLabel.textColor = checked ? .tertiaryLabel : .label
}), for: .touchUpInside)
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
//事件函数
//当对每一行进行排序时需要调用的方法
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
}
TodoTableViewController:
import UIKit
class TodoTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem?.image = pointIcon("chevron.left.circle.fill")
navigationItem.rightBarButtonItem?.image = pointIcon("checkmark.circle.fill")
}
@IBAction func back(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
@IBAction func done(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
}
8.使新增框可以输入多行文本
将多行文本控件text view拖入Table view中.
修改Text View中Text的文本,将可滚动Scrolling Enable以及上面的上下滚动和左右滚动取消勾选.
设置TextView的上下左右约束.
将TextView作为Outlet拖拽到TodoTableViewController中.
9.将输入的Text反向传值到首页.
指定identifier为AddTodoID.
Constants:
import Foundation
import UIKit
let kTodoCellID = "TodoCellID"
let kAddTodoID = "AddTodoID"
//将图标变大的方法
func pointIcon(_ iconName: String, _ pointSize: CGFloat = 22) -> UIImage{
let config = UIImage.SymbolConfiguration(pointSize: pointSize)
return UIImage(systemName:iconName, withConfiguration: config)!
}
TodosViewController:
import UIKit
class TodosViewController: UITableViewController {
var todos = [
Todo(name: "学习iOS课程的基础课", checked: false),
Todo(name: "学习iOS课程的零基础赏月App开发", checked: true),
Todo(name: "学习iOS课程的零基础木琴App开发", checked: false),
Todo(name: "学习iOS课程的零基础和风天气App开发", checked: false),
Todo(name: "学习iOS课程的零基础待办事项App开发", checked: false),
Todo(name: "学习iOS课程的小红书App开发", checked: false)
]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem?.image = pointIcon("plus.circle.fill")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
//配置TableView的一些数据
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1 //总共有1个分类
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return todos.count //总共有10个待办事项
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //此函数会根据上面两个函数(总共分类数和总共待办事项数)返回的内容多次执行
let cell = tableView.dequeueReusableCell(withIdentifier: kTodoCellID , for: indexPath) as! TodoCell
let checkBoxBtn = cell.checkBoxBtn!
let todoLabel = cell.todoLable!
let initSelected = todos[indexPath.row].checked
// // Configure the cell...
// //配置主标题的文本
// var contentConfiguration = cell.defaultContentConfiguration()
// contentConfiguration.text = "昵称" //主标题
// contentConfiguration.secondaryText = "个性签名" //副标题
// contentConfiguration.image = UIImage(systemName: "star") //图片
// cell.contentConfiguration = contentConfiguration
checkBoxBtn.isSelected = initSelected //将cell的是否被选中属性改为todos的当前行的checked属性
todoLabel.text = todos[indexPath.row].name
todoLabel.textColor = initSelected ? .tertiaryLabel : .label //三元运算符.根据是否被选中进行判断,如果被选中的话变成浅色,未被选中就是原来的Lable Color.
cell.checkBoxBtn.addAction(UIAction(handler: { action in
self.todos[indexPath.row].checked.toggle() //如果check原来是true,被点击之后就进行取反,变成false.
let checked = self.todos[indexPath.row].checked
checkBoxBtn.isSelected = checked
todoLabel.textColor = checked ? .tertiaryLabel : .label
}), for: .touchUpInside)
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
//事件函数
//当对每一行进行排序时需要调用的方法
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == kAddTodoID{
let vc = segue.destination as! TodoTableViewController
vc.delegate = self
}
}
}
extension TodosViewController: TodoTableViewControllerDelegate{
func didAdd(name: String){
print(name)
}
}
TodoTableViewController:
import UIKit
protocol TodoTableViewControllerDelegate{
func didAdd(name: String)
}
class TodoTableViewController: UITableViewController {
var delegate: TodoTableViewControllerDelegate?
@IBOutlet weak var todoTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem?.image = pointIcon("chevron.left.circle.fill")
navigationItem.rightBarButtonItem?.image = pointIcon("checkmark.circle.fill")
}
@IBAction func back(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
@IBAction func done(_ sender: Any) {
if !todoTextView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty{
delegate?.didAdd(name: todoTextView.text)
}
navigationController?.popViewController(animated: true)
}
}
测试一下:
10.传值后在首页显示已新增的待办事项.
TodosViewController:
import UIKit
class TodosViewController: UITableViewController {
var todos = [
Todo(name: "学习iOS课程的基础课", checked: false),
Todo(name: "学习iOS课程的零基础赏月App开发", checked: true),
Todo(name: "学习iOS课程的零基础木琴App开发", checked: false),
Todo(name: "学习iOS课程的零基础和风天气App开发", checked: false),
Todo(name: "学习iOS课程的零基础待办事项App开发", checked: false),
Todo(name: "学习iOS课程的小红书App开发", checked: false)
]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem?.image = pointIcon("plus.circle.fill")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
//配置TableView的一些数据
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1 //总共有1个分类
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return todos.count //总共有10个待办事项
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //此函数会根据上面两个函数(总共分类数和总共待办事项数)返回的内容多次执行
let cell = tableView.dequeueReusableCell(withIdentifier: kTodoCellID , for: indexPath) as! TodoCell
let checkBoxBtn = cell.checkBoxBtn!
let todoLabel = cell.todoLable!
let initSelected = todos[indexPath.row].checked
// // Configure the cell...
// //配置主标题的文本
// var contentConfiguration = cell.defaultContentConfiguration()
// contentConfiguration.text = "昵称" //主标题
// contentConfiguration.secondaryText = "个性签名" //副标题
// contentConfiguration.image = UIImage(systemName: "star") //图片
// cell.contentConfiguration = contentConfiguration
checkBoxBtn.isSelected = initSelected //将cell的是否被选中属性改为todos的当前行的checked属性
todoLabel.text = todos[indexPath.row].name
todoLabel.textColor = initSelected ? .tertiaryLabel : .label //三元运算符.根据是否被选中进行判断,如果被选中的话变成浅色,未被选中就是原来的Lable Color.
cell.checkBoxBtn.addAction(UIAction(handler: { action in
self.todos[indexPath.row].checked.toggle() //如果check原来是true,被点击之后就进行取反,变成false.
let checked = self.todos[indexPath.row].checked
checkBoxBtn.isSelected = checked
todoLabel.textColor = checked ? .tertiaryLabel : .label
}), for: .touchUpInside)
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
//事件函数
//当对每一行进行排序时需要调用的方法
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == kAddTodoID{
let vc = segue.destination as! TodoTableViewController
vc.delegate = self
}
}
}
extension TodosViewController: TodoTableViewControllerDelegate{
func didAdd(name: String){
todos.append(Todo(name: name, checked: false))
tableView.insertRows(at: [IndexPath(row: todos.count - 1, section: 0)], with: .automatic)
}
}
启动测试:
11.实现用户输入新增待办事项时实时换行.
将Todo Text View Ctrl拖拽到添加待办事项这里,选择delegate.
TodoTableViewController:
import UIKit
protocol TodoTableViewControllerDelegate{
func didAdd(name: String)
}
class TodoTableViewController: UITableViewController {
var delegate: TodoTableViewControllerDelegate?
@IBOutlet weak var todoTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem?.image = pointIcon("chevron.left.circle.fill")
navigationItem.rightBarButtonItem?.image = pointIcon("checkmark.circle.fill")
}
@IBAction func back(_ sender: Any) {
navigationController?.popViewController(animated: true)
}
@IBAction func done(_ sender: Any) {
if !todoTextView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty{
delegate?.didAdd(name: todoTextView.text)
}
navigationController?.popViewController(animated: true)
}
}
extension TodoTableViewController: UITextViewDelegate{
func textViewDidChange(_ textView: UITextView) {
//将Table View重新布局
tableView.performBatchUpdates {
//不需要放任何东西就可以自动刷新布局
}
}
}
测试: