#入力値がグラフに反映される実装をしてみました
流れとしてはこんな感じ
初期画面で体重と体脂肪率を入力⇨登録ボタンで画面遷移、その日の情報が登録されてグラフに表示、グラフタップでその日の情報が表示されるって感じです。
コードメインになります。
メイン画面の方はこんな感じです。
main
import UIKit
class HomeViewController: UIViewController,UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var weightLabel: UITextField!
@IBOutlet weak var fatLabel: UITextField!
@IBOutlet weak var datePicker: UIButton!
@IBOutlet weak var trainingView: UITableView!
//UserDefaultsのインスタンス
let userDefaults = UserDefaults.standard
//日付表示変更用
var changeDate : Date = Date()
//テーブル表示用
var trainList = [String]()
//日付の取得
let today: Date = Date()
let dateFormatter = DateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
//datePickerからの日付を判定し、帰ってきた値をセットする
dateFormatter.dateFormat = "yyyy/MM/dd"
if changeDate == today {
datePicker.setTitle(dateFormatter.string(from: today), for: .normal)
} else {
datePicker.setTitle(dateFormatter.string(from: changeDate), for: .normal)
}
//トレーニングリストの保存&呼び出し
if userDefaults.array(forKey: "training") != nil {
trainList = userDefaults.array(forKey: "training") as! [String]
userDefaults.set(trainList, forKey: "training")
userDefaults.synchronize()
}
//Delegate&DataSourceの呼び出し
trainingView.delegate = self
trainingView.dataSource = self
trainingView.allowsMultipleSelection = true
weightLabel.delegate = self
fatLabel.delegate = self
}
//キーボード以外の箇所のタッチでキーボードを閉じる処理
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
//キーボードを閉じる処理
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//tableDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at:indexPath)
cell?.accessoryType = .none
}
//TableDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return trainList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel!.text = trainList[indexPath.row]
cell.selectionStyle = .none
let selectedIndexPaths = tableView.indexPathsForSelectedRows
if selectedIndexPaths != nil && (selectedIndexPaths?.contains(indexPath))! {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
@IBAction func saveMemory(_ sender: UIButton) {
performSegue(withIdentifier: "saveMemory", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//入力値に空があればエラーを出す
if segue.identifier == "saveMemory" {
let nextView = segue.destination as! ViewController
// 空の場合は何もせず結果の画面へ遷移
if weightLabel.text! != "" || fatLabel.text! != "" {
let xs = self.trainingView.indexPathsForSelectedRows
if xs != nil {
for x in xs! {
nextView.trainList.append(trainList[x.row])
}
}
nextView.weightText = Double(weightLabel.text!)!
nextView.fatText = Double(fatLabel.text!)!
nextView.dateText = datePicker.titleLabel!.text!
}
}
}
}
下記がチャート画面です。
charts
import UIKit
import Charts
class ViewController: UIViewController,ChartViewDelegate,UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var chartsView: LineChartView!
@IBOutlet weak var dateLabel: UILabel!
@IBOutlet weak var weightLabel: UILabel!
@IBOutlet weak var fatLabel: UILabel!
@IBOutlet var trainedList: UITableView!
let userDefaults = UserDefaults.standard
let weightString = "Weight"
let fatString = "Fat"
var weightDic = [String:Double]()
var fatDic = [String:Double]()
var trainDic = [String:[String]]()
var weightList = [Double]()
var fatList = [Double]()
var weightText = 0.0
var fatText = 0.0
var dateText = ""
var chartDataCount = 0
var daysList = [String]()
var trainList = [String]()
override func viewDidLoad() {
super.viewDidLoad()
chartsView.delegate = self
let weightKey = weightString + dateText
let fatKey = fatString + dateText
loadData()
if weightKey != "Weight" || fatKey != "Fat" {
saveData(weightKey : weightKey, fatKey: fatKey, daysText:dateText)
} else if dateText == "" {
let weightSort = weightDic.keys.sorted()
let fatSort = fatDic.keys.sorted()
for key in weightSort {
weightList.append(weightDic[key]!)
daysList.append(String(key.suffix(5)))
}
for key in fatSort {
fatList.append(fatDic[key]!)
}
}
setChart(days:daysList)
trainList = [String]()
}
@IBAction func clearUserDefault(_ sender: Any) {
print("Clear")
let alert: UIAlertController = UIAlertController(title: "データ消去", message: "これまでのデータを消去しますか?", preferredStyle: UIAlertController.Style.actionSheet)
let comit = UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler:{
(action: UIAlertAction!) -> Void in
self.userDefaults.removeObject(forKey: "weight")
self.userDefaults.removeObject(forKey: "fat")
self.daysList = [""]
self.weightList = [Double]()
self.fatList = [Double]()
self.dateLabel.text! = ""
self.weightLabel.text! = ""
self.fatLabel.text! = ""
self.trainList = [String]()
self.setChart(days: self.daysList)
self.trainedList.reloadData()
super.viewDidLoad()
})
let cancel = UIAlertAction(title: "戻る", style: UIAlertAction.Style.cancel, handler: nil)
alert.addAction(comit)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
}
//userDefaultsからデータをDictionaryに代入
//データがなければスルー(1回目とクリア後)
func loadData() {
if userDefaults.dictionary(forKey: "weight") != nil {
weightDic = userDefaults.dictionary(forKey: "weight") as! [String : Double]
}
if userDefaults.dictionary(forKey: "fat") != nil {
fatDic = userDefaults.dictionary(forKey: "fat") as! [String : Double]
}
if userDefaults.dictionary(forKey: "train") != nil {
trainDic = userDefaults.dictionary(forKey: "train") as! [String:[String]]
}
}
//渡ってきた値をuserDefaultsへセットし、リストへDictionaryのValueをset
func saveData(weightKey : String,fatKey : String, daysText: String) {
weightDic[weightKey] = weightText
fatDic[fatKey] = fatText
trainDic[daysText] = trainList
userDefaults.set(weightDic, forKey: "weight")
userDefaults.set(fatDic, forKey: "fat")
userDefaults.set(trainDic, forKey: "train")
userDefaults.synchronize()
let weightSort = weightDic.keys.sorted()
let fatSort = fatDic.keys.sorted()
for key in weightSort {
weightList.append(weightDic[key]!)
daysList.append(String(key.suffix(5)))
}
for key in fatSort {
fatList.append(fatDic[key]!)
}
setChart(days:daysList)
trainList = [String]()
}
func setChart(days:[String]){
let lineDefault = UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)
let data = LineChartData()
var lineChartEntry1 = [ChartDataEntry]()
for i in 0..<weightList.count {
lineChartEntry1.append(ChartDataEntry(x: Double(i), y: Double(weightList[i])))
}
let line1 = LineChartDataSet(entries: lineChartEntry1, label: "体重")
line1.drawCirclesEnabled = false
line1.drawValuesEnabled = true
line1.valueTextColor = UIColor.white
line1.lineWidth = 2
line1.setColor(UIColor.red)
data.addDataSet(line1)
if (fatList.count > 0) {
var lineChartEntry2 = [ChartDataEntry]()
for i in 0..<fatList.count {
lineChartEntry2.append(ChartDataEntry(x: Double(i), y: Double(fatList[i])))
}
let line2 = LineChartDataSet(entries: lineChartEntry2, label: "体脂肪")
line2.drawCirclesEnabled = false
line2.drawValuesEnabled = true
line2.valueTextColor = UIColor.white
line2.lineWidth = 2
line2.setColor(UIColor.blue)
data.addDataSet(line2)
}
let chartFormatter = LineChartFormatter(labels: days)
let xAxis = chartsView.xAxis
xAxis.valueFormatter = chartFormatter
xAxis.labelFont = UIFont(name: "HelveticaNeue-Light", size: 12.0)!
xAxis.labelTextColor = UIColor.white
chartsView.xAxis.granularityEnabled = true
chartsView.xAxis.granularity = 1.0
chartsView.xAxis.decimals = 0
chartsView.xAxis.valueFormatter = xAxis.valueFormatter
chartsView.data = data
}
private class LineChartFormatter: NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if labels.count == 1 {
return labels[0]
} else {
return labels[Int(value)]
}
}
init(labels: [String]) {
super.init()
self.labels = labels
}
}
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
let weightSort = weightDic.keys.sorted()
let fatSort = fatDic.keys.sorted()
var weightKey :String
var fatKey : String
var dateString : String
if highlight.dataSetIndex == 0 {
weightKey = weightSort[NSInteger(entry.x)]
fatKey = "Fat" + weightSort[NSInteger(entry.x)].suffix(10)
dateString = String(weightSort[NSInteger(entry.x)].suffix(10))
} else {
weightKey = "Weight" + fatSort[NSInteger(entry.x)].suffix(10)
fatKey = fatSort[NSInteger(entry.x)]
dateString = String(fatSort[NSInteger(entry.x)].suffix(10))
}
let weightString = weightDic[weightKey]
let fatString = fatDic[fatKey]
trainDic = userDefaults.dictionary(forKey: "train") as! [String : [String]]
print(trainDic)
if trainDic[dateString] != nil {
trainList = trainDic[dateString]!
} else {
trainList = [String]()
}
dateLabel.text = dateString
dateLabel.textColor = UIColor.white
weightLabel.text = String(weightString!) + "kg"
weightLabel.textColor = UIColor.white
fatLabel.text = String(fatString!) + "%"
fatLabel.textColor = UIColor.white
trainedList.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return trainList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel!.text = trainList[indexPath.row]
return cell
}
}
もっと綺麗なやり方があるんだろうなあ。。。
一応画面です。
恥ずかしながらまだSEなんですがw
参考になればいいし、もっとこうした方がってのがあれば教えてください!
#profile
生まれも育ちも大阪の浪速中の浪速っ子が30才未経験からITエンジニアとして生きるブログもやってます。
よかったらみてください