SAP FIORI

SAP Fiori For iOS - 任务管理应用 - 开发

2017-04-12  本文已影响107人  46b61a5f089d

前言

上文中我们介绍了这个任务管理应用的设计,在本文中将开始开发工作.开发会使用 swift 语言,所以如果对 iOS 开发不是很熟悉的,可是先看看 swift 语言的相关资料.

需要使用到的控件一览

创建项目

在 xcode 中新建一个项目:



创建 model

新建一个 model 的 swift 文件,用来放置我们的测试数据,在真实的应用中,这些数据应该是从其他系统的 service 中读取,在本例中,我们直接使用固定的数据,代码如下:

import Foundation
import UIKit
struct TasksData {
    enum TaskStatus {
        case low
        case medium
        case high
    }
    struct Task {
        let title: String
        let desciption: String
        let dueDate: String
        let favorateImage: UIImage?
        let priorityImage: UIImage?
        let priorityValue: Int
        let timeFrame: String
        let timeFrameValue: Int
        let status: UIImage?
    }
    static let tasks: [Task] = [Task(title: "任务1 - 收集资料", desciption: "收集关于SAP FIORI for iOS的开发资料", dueDate:"4月7日",favorateImage: #imageLiteral(resourceName: "favorate"), priorityImage: #imageLiteral(resourceName: "highPrio"),priorityValue: 2,timeFrame: ">1 H",timeFrameValue: 2, status: #imageLiteral(resourceName: "complete")),
                                Task(title: "任务2 - 整理资料", desciption: "整理关于SAP FIORI for iOS的开发资料", dueDate:"4月8日",favorateImage: #imageLiteral(resourceName: "favorate"), priorityImage: #imageLiteral(resourceName: "mediumPrio"),priorityValue: 1, timeFrame: "<1 H",timeFrameValue: 1, status: #imageLiteral(resourceName: "complete")),
                                Task(title: "任务3 - 研究开发框架", desciption: "SAP Cloud Platform SDK的框架研究", dueDate:"4月9日",favorateImage: #imageLiteral(resourceName: "nonFav"), priorityImage: #imageLiteral(resourceName: "highPrio"),priorityValue: 2, timeFrame: "<0.5 H",timeFrameValue: 0, status: #imageLiteral(resourceName: "open")),
                                Task(title: "任务4 - 撰写初步文章", desciption: "写一篇关于SAP FIORI for iOS的文章草稿部分", dueDate:"4月10日",favorateImage: #imageLiteral(resourceName: "nonFav"), priorityImage: #imageLiteral(resourceName: "lowPrio"),priorityValue: 0, timeFrame: ">1 H",timeFrameValue: 2, status: #imageLiteral(resourceName: "open")),
                                Task(title: "任务5 - 收集文章需要的素材", desciption: "官网,开发手册,SDK 文档,图标", dueDate:"4月11日",favorateImage: #imageLiteral(resourceName: "nonFav"), priorityImage: #imageLiteral(resourceName: "mediumPrio"),priorityValue: 1, timeFrame: "<1 H",timeFrameValue: 1, status: #imageLiteral(resourceName: "open")),
                                Task(title: "任务6 - 完成最终文章", desciption: "草稿和素材结合,完成最终稿文章", dueDate:"4月12日",favorateImage: #imageLiteral(resourceName: "favorate"), priorityImage: #imageLiteral(resourceName: "highPrio"),priorityValue: 2, timeFrame: ">1 H",timeFrameValue: 2, status: #imageLiteral(resourceName: "complete")),
                                Task(title: "任务7 - 发布文章", desciption: "发布文章到微信,微博,简书", dueDate:"4月13日",favorateImage: #imageLiteral(resourceName: "nonFav"), priorityImage: #imageLiteral(resourceName: "lowPrio"),priorityValue: 0, timeFrame: "<0.5 H",timeFrameValue: 0, status: #imageLiteral(resourceName: "open"))]
    
}

屏幕开发

第一个屏幕的 controller

新建一个 controller, 关联到任务清单的 TableView.该 controller 主要用于显示任务的清单,在使用 SAPFiori 的地方主要是 cell 的操作.
let cell = tableView.dequeueReusableCell(withIdentifier: FUITimelineCell.reuseIdentifier,for: indexPath) as! FUITimelineCell,然后把数据赋值到 cell 中,显示出来.
全部代码如下:

import UIKit
import SAPFiori

class TaskListTableViewController: UITableViewController {

    var tasks: [TasksData.Task] = TasksData.tasks
    var selectedTask = TasksData.Task(title: "", desciption: "", dueDate:"",favorateImage: nil, priorityImage: nil,priorityValue: 0, timeFrame: "",timeFrameValue: 0, status: nil)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.estimatedRowHeight = 120
        self.tableView.rowHeight = UITableViewAutomaticDimension

    }

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

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return tasks.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let task = tasks[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: FUITimelineCell.reuseIdentifier,
                                                 for: indexPath) as! FUITimelineCell
        cell.headlineText = task.title
        cell.subheadlineText = task.desciption
        cell.eventText = task.dueDate
        cell.subStatusText = task.timeFrame
        cell.nodeImage = task.status
        cell.eventImage = task.favorateImage
        cell.statusImage = task.priorityImage
        return cell

    }
    
    override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        selectedTask = tasks[indexPath.row]
        return indexPath
    }


    // 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.destinationViewController.
        // Pass the selected object to the new view controller.
        if segue.identifier == "showDetail" {
            if let detailVC = segue.destination as? TaskDetailTableViewController {
                detailVC.taskDetail = selectedTask
            }
        }
    }

}

第二个屏幕的conroller

在第二个屏幕中,主要使用到了 objectHeader 以及一些简单的 table cell, 在屏幕加载的过程中,把上一个屏幕选择的 item 中的详细信息显示出来.

let objectHeader = FUIObjectHeader()
        objectHeader.detailImageView.image = #imageLiteral(resourceName: "favorate")
        objectHeader.headlineLabel.text = taskDetail.title
        objectHeader.subheadlineLabel.text = taskDetail.desciption
        objectHeader.footnoteLabel.text = taskDetail.dueDate
        objectHeader.substatusImageView.image = taskDetail.priorityImage

这个详细显示使用的是静态 table, 并且已经放好 section 以及 cell, 只要把我们需要使用的 SAPFiori 的 cell 类型放进去即可.
SegmentControl:
let cell = tableView.dequeueReusableCell(withIdentifier: "prioritySegment", for: indexPath) as! FUISegmentedControlFormCell
SimpleProperty:
let cell = tableView.dequeueReusableCell(withIdentifier: FUISimplePropertyFormCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyFormCell

全部代码如下:

import UIKit
import SAPFiori
import SAPCommon

class TaskDetailTableViewController: UITableViewController {
    let buttonTitles: [[String: String]] = [["LO": "Low"], ["MED": "Medium"], ["HI": "High"]]
    let needTimeTitles: [[String: String]] = [["LO": "< 0.5 H"], ["MED": "< 1 H"], ["HI": "> 1 H"]]
    var taskDetail = TasksData.Task(title: "", desciption: "", dueDate:"",favorateImage: nil, priorityImage: nil,priorityValue: 2, timeFrame: ">1 H",timeFrameValue: 2, status: nil)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let objectHeader = FUIObjectHeader()
        objectHeader.detailImageView.image = #imageLiteral(resourceName: "favorate")
        objectHeader.headlineLabel.text = taskDetail.title
        objectHeader.subheadlineLabel.text = taskDetail.desciption
        objectHeader.footnoteLabel.text = taskDetail.dueDate
        objectHeader.substatusImageView.image = taskDetail.priorityImage
        self.tableView.tableHeaderView = objectHeader
        self.tableView.register(FUISegmentedControlFormCell.self, forCellReuseIdentifier: "prioritySegment")
        self.tableView.register(FUISegmentedControlFormCell.self, forCellReuseIdentifier: "needTime")
        self.tableView.register(FUISimplePropertyFormCell.self, forCellReuseIdentifier: FUISimplePropertyFormCell.reuseIdentifier)
        self.tableView.register(FUISimplePropertyFormCell.self, forCellReuseIdentifier: "executionPeople")
    }

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

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 2
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        if section == 0{
            return 3
        }else{
            return 1
        }
    }
    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0{
            if indexPath.row == 0{
                let cell = tableView.dequeueReusableCell(withIdentifier: "prioritySegment", for: indexPath) as! FUISegmentedControlFormCell
                cell.valueOptions = buttonTitles.flatMap { $0.map { $0.value } }
                cell.keyName = "优先级"
                cell.value = taskDetail.priorityValue
                cell.isUserInteractionEnabled = false
                return cell
            }else if indexPath.row == 1{
                let cell = tableView.dequeueReusableCell(withIdentifier: FUISimplePropertyFormCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyFormCell
                cell.keyName = "截止日期"
                cell.value = taskDetail.dueDate
                return cell
            }else{
                let cell = tableView.dequeueReusableCell(withIdentifier: "needTime", for: indexPath) as! FUISegmentedControlFormCell
                cell.valueOptions = needTimeTitles.flatMap { $0.map { $0.value } }
                cell.keyName = "需要时间"
                cell.value = taskDetail.timeFrameValue
                cell.isUserInteractionEnabled = false
                return cell
            }
        }else{
            let cell = tableView.dequeueReusableCell(withIdentifier: "executionPeople", for: indexPath) as! FUISimplePropertyFormCell
            cell.keyName = "执行者"
            cell.value = "张三"
            cell.accessoryType = .disclosureIndicator
            return cell
        }
    }
}

屏幕间流转以及传递参数

在清单到详细信息的屏幕流转中,我们需要把选择的任务传递到详细屏幕,在 segue 的时候,把详细信息 controller 中的变量赋值:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
        if segue.identifier == "showDetail" {
            if let detailVC = segue.destination as? TaskDetailTableViewController {
                detailVC.taskDetail = selectedTask
            }
        }
    }

真机测试

结语

整体来说,该应用十分的简单,因为目前只做到显示固定数据,没有任何添加删除或者修改的功能,在后续的文章中,我会慢慢的把这些功能添加上去.

代码下载
Github 代码下载

上一篇下一篇

猜你喜欢

热点阅读