はじめに
簡単な図形描画アプリ「DotView」を作成する2回目です。
前回:SwiftでUIBezierPathを使い、簡単な図形を描画するアプリを作ってみた。①
今回は、TextFieldやSliderで入力した値をUIViewに反映させる部分を作成し、DotViewを完成させたいと思います。
各TextFieldに値を入力した場合の処理を作成する。
前回で、TextFieldとプログラムとの関連づけを行いました。
これから、それらのTextFieldに値が入力された場合の処理を作成していきます。
まずは、TextFieldごとにタグ付けを行います。(各TextFieldごとに処理を記述するため)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// テキストフィールド毎にタグを設定
xText.delegate = self
xText.tag = 1
yText.delegate = self
yText.tag = 2
radiusText.delegate = self
radiusText.tag = 3
vertexText.delegate = self
vertexText.tag = 4
self.view.backgroundColor = UIColor.gray // 全体背景をグレーに設定
}
TextFieldに値が入力された場合に呼び出されるデリゲートメソッドtextFieldShouldReturn
を記述し、その中でタグごとに処理を分岐させます。
// 各テキストフィールドに値が入力された場合
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// キーボードを閉じる
textField.resignFirstResponder()
// switch文により、それぞれのtextに入力した場合を分ける
switch textField.tag {
case 1: // xText
case 2: // yText
case 3: // radiusText
case 4: // vertexText
default:
print("エラー")
}
return true
}
それぞれのcase
では、以下のような処理を行います。
- TextFieldに入力された値をCGFloatやIntに変換
- 変換した値を、
TestDraw.swift
の対応する変数に格納 - 円の面積を更新(
radiusText
変更時のみ)
UIViewを管理しているTestDraw.swift
内のx,yなどの値を変更することで、その位置に円を再描画することができます。
// 各テキストフィールドに値が入力された場合
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// キーボードを閉じる
textField.resignFirstResponder()
// switch文により、それぞれのtextに入力した場合を分ける
switch textField.tag {
case 1:
// xTextに入力した値をStringからCGFloatに変換
let xDouble = Double(textField.text ?? "") ?? 0.0
let x: CGFloat = CGFloat(xDouble)
// 入力された値をTestDraw.swift内に存在する座標変数へと格納
nextView.x = x
case 2:
// 同様のことをyTextについてもやる
let yDouble = Double(textField.text ?? "") ?? 0.0
let y:CGFloat = CGFloat(yDouble)
nextView.y = y
case 3:
// radiusText
let radiusDouble = Double(textField.text ?? "") ?? 0.0
let radius: CGFloat = CGFloat(radiusDouble)
nextView.radius = radius
areaValueLabel.text = String(Double(nextView.area!))
case 4:
// vertexText
let vertex = Int(textField.text ?? "") ?? 0
nextView.vertex = vertex
default:
print("エラー")
}
return true
}
これで、TextFieldを変更した時の処理を作成することができました。
次は、Sliderの値を変更した時の処理を作成していきます。
Sliderの値変更時の処理を作成する。
Sliderの値を変更した時には、以下のような動作が行われるようにします。
- Sliderの現在の値を、対応するTextFieldに表示する。
- Sliderの現在の値を、
TestDraw.swift
の対応する変数に格納する。 - 面積の値を変更(radius変更時)
まずは、Sliderの最大値と最小値を設定します。
Sliderを選択し、Attribute Inspectorにて適当な値を入力します。
valueは、この場合はアプリを起動した際の初期値となります。
それぞれのSliderにて設定ができたら、上記の動作を記述していきます。
// radiusを設定するスライダー
@IBAction func radiusSlider(_ sender: UISlider) {
//最大値と最小値はstoryboardにて設定済み
//sliderの値が変更された場合の処理
//valueをradiusのテキストフィールドに表示
radiusText.text = String(sender.value)
//設定したradiusを円描画用のradiusに送る
nextView.radius = CGFloat(sender.value)
print(sender.value) // ログ
//面積の変更
areaValueLabel.text = String(Double(nextView.area!))
}
// vertexを設定するスライダー
@IBAction func vertexSlider(_ sender: UISlider) {
//最大値と最小値はstoryboardにて設定済み
//valueをNo.Vertのテキストフィールドに表示
vertexText.text = String(Int(sender.value))
//設定したvertexを円描画用のvertexに送る
nextView.vertex = Int(sender.value)
print(nextView.vertex) // ログ
}
これで、Sliderを動かした時、それに伴って円が描画されるようになりました。
完成
これで、簡単な図形描画アプリ「DotView」を作成することができました。
最後にもう一度、コード全体とアプリ画面を載せておきます。
//
// ViewController.swift
// DotView
//
// Created by iwai on 2018/09/14.
// Copyright © 2018年 iwai. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// テキストフィールド毎にタグを設定
xText.delegate = self
xText.tag = 1
yText.delegate = self
yText.tag = 2
radiusText.delegate = self
radiusText.tag = 3
vertexText.delegate = self
vertexText.tag = 4
self.view.backgroundColor = UIColor.gray // 全体背景をグレーに設定
}
@IBOutlet weak var nextView: TestDraw!
@IBOutlet weak var xLabel: UILabel! // 「X」
@IBOutlet weak var yLabel: UILabel! // 「Y」
@IBOutlet weak var radiusLabel: UILabel! // 「Radius」
@IBOutlet weak var areaLabel: UILabel! // 「Area」
@IBOutlet weak var vertexLabel: UILabel! // 「No.Vert」
@IBOutlet weak var radius2Label: UILabel! // UISliderの隣の「Radius」
@IBOutlet weak var vertex2Label: UILabel! // UISliderの隣の「No.Vert」
@IBOutlet weak var xText: UITextField! // 中心のX座標入力
@IBOutlet weak var yText: UITextField! // 中心のY座標入力
@IBOutlet weak var radiusText: UITextField! // 円の半径入力
@IBOutlet weak var vertexText: UITextField! // 正多角形の頂点の数入力
@IBOutlet weak var areaValueLabel: UILabel! // 計算された円の面積を表示
// 各テキストフィールドに値が入力された場合
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// キーボードを閉じる
textField.resignFirstResponder()
// switch文により、それぞれのtextに入力した場合を分ける
switch textField.tag {
case 1:
// xTextに入力した値をStringからCGFloatに変換
let xDouble = Double(textField.text ?? "") ?? 0.0
let x: CGFloat = CGFloat(xDouble)
// 入力された値をTestDraw.swift内に存在する座標変数へと格納
nextView.x = x
case 2:
// 同様のことをyTextについてもやる
let yDouble = Double(textField.text ?? "") ?? 0.0
let y:CGFloat = CGFloat(yDouble)
nextView.y = y
case 3:
// radiusText
let radiusDouble = Double(textField.text ?? "") ?? 0.0
let radius: CGFloat = CGFloat(radiusDouble)
nextView.radius = radius
areaValueLabel.text = String(Double(nextView.area!))
case 4:
// vertexText
let vertex = Int(textField.text ?? "") ?? 0
nextView.vertex = vertex
default:
print("エラー")
}
return true
}
// radiusを設定するスライダー
@IBAction func radiusSlider(_ sender: UISlider) {
//最大値と最小値はstoryboardにて設定済み
//sliderの値が変更された場合の処理
//valueをradiusのテキストフィールドに表示
radiusText.text = String(sender.value)
//設定したradiusを円描画用のradiusに送る
nextView.radius = CGFloat(sender.value)
print(sender.value)
//面積の変更
areaValueLabel.text = String(Double(nextView.area!))
}
// vertexを設定するスライダー
@IBAction func vertexSlider(_ sender: UISlider) {
//最大値と最小値はstoryboardにて設定済み
//valueをNo.Vertのテキストフィールドに表示
vertexText.text = String(Int(sender.value))
//設定したvertexを円描画用のvertexに送る
nextView.vertex = Int(sender.value)
print(nextView.vertex)
}
}
//
// TestDraw.swift
// DotView
//
// Created by iwai on 2018/09/14.
// Copyright © 2018年 iwai. All rights reserved.
//
import UIKit
class TestDraw: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
*/
// 中心のx座標。ViewControllerのXtextからの値を格納する変数
var x:CGFloat = 150 // 初期値
{
didSet {
if oldValue != x {
self.setNeedsDisplay()
}
}
}
// 中心のy座標。同じくyTextからの値を格納する変数
var y:CGFloat = 100 // 初期値
{
didSet {
if oldValue != y {
self.setNeedsDisplay()
}
}
}
//円の半径
var radius: CGFloat = 50
{
didSet {
if oldValue != radius {
self.setNeedsDisplay()
}
}
}
//正多角形の頂点の数
var vertex: Int = 3
{
didSet {
if oldValue != vertex {
self.setNeedsDisplay()
}
}
}
var area: CGFloat?
override func draw(_ rect: CGRect) {
// Drawing code
// 円の描画
let center = CGPoint(x: x,y: y) // 円の中心座標を設定
self.drawCircle(radius: radius,center: center) // 半径と中心を設定し、円を描画
// 正多角形の描画
self.drawRegularPolygon(vertex, radius: radius, center: center) // 頂点の数・外接円の半径・中心を設定し多角形を描画
}
// 円の描画関数
func drawCircle(radius: CGFloat, center: CGPoint){
let circle = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(Double.pi*2.0*0.0/360.0), endAngle: CGFloat(Double.pi*2.0*360.0/360.0), clockwise: true)
let circleColor = UIColor.red // 色を赤に設定
circleColor.setStroke() // 線の色を設定
circleColor.setFill() // 内側塗りつぶし色の設定
circle.fill() // 内側塗りつぶし
circle.lineWidth = 4
circle.stroke() // 描画
area = (radius * radius) * CGFloat(Double.pi) // 面積の計算
print(area) // ログ
print(String(Double(area!)))
}
// 正多角形の描画関数
func drawRegularPolygon(_ p:Int, radius:CGFloat, center:CGPoint){
let line = UIBezierPath()// インスタンス生成
var pt:[CGPoint]=[] // 頂点の座標を格納する配列
for i in 0 ..< p {
let rad: CGFloat = CGFloat(Double.pi * Double(i) * 2.0 / Double(p) + Double.pi / 2.0)
let point = CGPoint(x: center.x + radius * cos(rad), y: center.y - radius * sin(rad))
pt.append(point)
}
// 起点
line.move(to: pt[0])
// 帰着点
for j in 1..<p {
line.addLine(to: pt[j])
}
//ラインを結ぶ
line.close()
//色の設定
UIColor.yellow.setStroke()
//ライン幅
line.lineWidth = 4
//描画
line.stroke()
}
}