おはよう
今年の目標の一つがiOSアプリ作成してみること、です。
そのために、まずSwiftに入門!ということで、SwiftUIのチュートリアルをやりつつ、気になった部分も調べていきます。
教材
[Introducing SwiftUI]
(https://developer.apple.com/tutorials/swiftui)
このチュートリアルを全部やると、建物・場所について説明をみたり、好きな場所をシェアしたりできるLandmarkアプリができるみたい。
##チュートリアル1:Viewを作って、組み合わせてみよう!
Creating and Combining Views
画像やテキストといった要素を組み合わせたViewの作り方を学ぶよ。
###Section1:プロジェクトを作ってみよう!
Xcodeを立ち上げるて、新しいプロジェクトを作るよ。
Interface | 特徴 |
---|---|
SwiftUI | WWDC2019で発表された新しいUI実装方法。iOS13以上で使える。コードでUIを実装する。 |
Storyboard | SwiftUIが出てくる前のUI実装方法。GUIでUIを実装する。 |
今回はSwiftUI。 |
Life Cycle | 特徴 |
---|---|
SwiftUIApp | WWDC2020で発表。iOS14からのフレームワーク。 |
UIKitAppDelegate | SwiftUI登場以前のフレームワーク。 |
今回はSwiftUIApp。
最後に、ファイルの保存場所を決めて、完了。
するとこんな感じでファイルが作成されるよ。
チュートリアルにしたがって「Resume」をクリックしたら、しっかりHello worldされたね!
ファイルの詳細を見てみるよ。
拡張子 | |
---|---|
.swift | アプリケーションの処理を記入する。Swiftでコードが書かれる。 |
.xcassets | アプリケーションのアイコンなどすべての画像が保存される。 |
.plist | アプリケーションの設定情報を管理する。 |
LandmarksApp.swift
プロジェクト名+App.swift 形式で自動作成されたファイルだよ。
//
// LandmarksApp.swift
// Landmarks
//
// Created by XXXXX on 2021/01/24.
//
import SwiftUI
@main //point1-1
struct LandmarksApp: App { //point1-2 & point1-3
var body: some Scene { //point1-4
WindowGroup { //point1-5
ContentView()
}
}
}
point1-1 @main
属性の一つでこれをつけることで、このアプリのエントリーポイントとして指定しているよ。
point1-2 struct=構造体
プログラムを構成する要素・機能を詰んだ構造体だよ。ほぼほぼClassだけれど、違いもあるよ。
【structでもClassesでもできること】
・定数、変数、関数、Arrayやlist型で格納された値にアクセスする際のfruits['apple']のappleのような添え字の定義。
・初期値の設定
・標準機能の提供。
【Classesではできるけれど、structではできないこと】
・継承。
・型キャスト(変数やオブジェクトを別の型に変えること)
・初期化解除の定義。
・参照。(structは値渡し)
ポイントはClassesでは継承やインスタンスの作成ができるけれど、structではそれができないところかな?
参考ページ:ClassesAndStructures
point1-3 struct XXX : ZZZZ
XXXがstructの名前。ZZZがプロトコル名。
今回の場合は「LandmarksApp」は「App」というプロトコルに準拠した構造で宣言しますよー、といっている。多分。
参考ページ:app
point1-4 var body : some Scene
Appのなかのvar bodyはアプリの振る舞いや、要素を設定するところ。
Scanというプロトコルに準拠して作られているよーという宣言の仕方をしている。
Sceneはアプリのユーザーインターフェース部分と思われる。
参考ページ:Scene
ちなみにvarは変数、letは定数の定義に使います。
point1-5 windowGroup
この中でViewの階層を定義する。
今回は、ContentViewを呼び出しているので、アプリが実際に作成している画面はこのContentViewの内容になる・・と思われる。
https://developer.apple.com/documentation/swiftui/windowgroup
windowGroupのなかで呼び出されているContentViewが定義されているContentView.swiftを見てみるよ。
//
// contentView.swift
// Landmarks
//
// Created by XXXXXX on 2021/01/24.
//
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Viewというプロトコルに準拠して作られていることがわかるね。
実際の記述内容は以降のセクションで詳しく見ていくよ。
###Section2 テキストを編集してみよう!
ディスプレイに表示されている内容を変えてみるよ。
Hello Worldにフォーカスを当てると、テキストの編集メニューが表示されるよ。
このメニューを編集すると、編集した内容がコードに反映されて、ディスプレイされる文字も変わるみたい。
テキストとフォントをここから変えて、Resumeをクリックすると画像のようになったよ。
Textに対して「.font」「.padding」といった修飾を繋げていくことで、
デザインを変更することができるんだね。
要素が重なってくると順番が大切になります。
Text("Turtle Rock")
.font(.title)
.foregroundColor(.green)
.padding()
}
}
###Section3 Stackを使って要素を組み合わせてみよう。
今はテキストが中央に1つ置いてあるだけなので、並列してみるよ。
Textの上でCommandキー押しながらクリックすると、追加するアクションが出てくるので、VStackを選択するよ。
すると、VstackにTextが囲まれた状態になったね。
次は、Textを追加するよ。XCodeの画面の右上にある+ボタンから、簡単に追加ができるよ。
struct ContentView: View {
var body: some View {
VStack (alignment: .leading) { // poin3-1
Text("Turtle Rock")
.font(.title)
.foregroundColor(.green)
.padding()
HStack { // point3-2
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding() // point3-3
}
}
point3-1 VStack(alignment: .leading)
垂直方向、縦に並べたい時に要素を囲む。
今回はTurtleRockとHStackの要素を縦に並べているね。
また後ろについている(alignment〜)はVStackで囲まれた中にある要素の寄せを指定しているよ。今回はleading = 左寄せ。
point3-2 HStack
水平方向、横に並べたい時に要素を囲む。
今回はテキスト2つとその分離に使うSpacerを横並びにしているね。
point3-3 VStackに対する.padding()
paddingはVStack要素に対して付与されてるね。
paddingにかかわらず、修飾子をどこにつけるかによって、それが反映される範囲が変わるので、注意が必要だよ。
###Section4 画像を追加してみよう。
まずはチュートリアルセットでダウンロードしたファイルの中にあるjpgを
Projectの中のAssets.xcaassetの中に入れるよ。
その後、新しくファイルを作成し、画像に対して編集をしていくよ。
完成後の見た目とコードはこんな感じ。
(輪郭が白だとわかりずらかったため、グレーのままにしてあります。)
import SwiftUI
struct CircleImage: View {
var body: some View {
Image("turtlerock") //point4-1
.clipShape(Circle()) // point4-2
.overlay(Circle().stroke(Color.gray,lineWidth: 4)) // point4-3
.shadow(radius:7 )
}
}
struct CircleImage_Previews: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
point4-1 Image(XX-画像名-XX)
assetに追加したファイルと同じ名前を指定し、画像要素を作る。
point4-2 clipSharp(図形)
clipSharpは画像の切り取りの指定で、今回は円形に切り取りをしている。
point4-3 overlay
Imageに対し重ねる要素を指定している。今回は同じく円形の輪郭stroke)を重ねている。strokeの後ろには輪郭のスタイルが記載。今回はグレーの幅(lineWidth)が4mm。
Section5 ほかのフレームワークを追加してみよう。
次は、Mapをviewの中に表示するよ。
使用するのは「mapkit」というフレームワークを使用するよ。
出来上がった画面はこんな感じ。ちょっと見づらいけれど、地図だよ。
地図を動かしてみるには画像のまるをつけたところをクリックして、ライブプレビューモードにする必要があるよ。
import SwiftUI
import MapKit
struct MapView: View {
@State private var region = MKCoordinateRegion( //point5-1
center: CLLocationCoordinate2D(latitude: 34.011_286, longitude: -116.166_868),
span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2) //point5-2
)
var body: some View {
Map(coordinateRegion: $region) //point5-3
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView()
}
}
point5-1 @State
データバインディングの仕組み。これをつけることで値の更新を監視して、自動で反映してくれる。
point5-2 MKCoordinateRegion(center:XXXXX, span:YYYYY)
MKCoordinateRegionは緯度経度の情報を与えるとそれを中心に、地形情報を返します。
centerとspanの二つの引数をあり、それぞれ下記の通り。
center:領域の中心の緯度経度の指定。latitudeが緯度、longitudeが経度。
span:表示する地図の幅を指定。latitudeDeltaが南北の距離、longitudeDeltaが東西の距離を示す。
point5-3 $region
「$」をつけることで、データバインディングさせることができる。
最初に地図を表示した際は、MKCoordinateRegionをしたときの緯度経度を元に地図を描画をしたね。でも、そのあと、ユーザー側で画面を動かした時も、地図の描画を変える必要がある。そのため、バインディングして、地図に渡される緯度経度の情報が更新、それをつけとった地図側でも描画し直すようになっているよ。
Section6 全部まとめてみよう。
最後は最初に作ったテキスト画面を編集して、地図+画像+テキストの画面を作るよ。
//
// ContentView.swift
// Landmarks
//
// Created by XXXXXXX on 2021/01/24.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
MapView() //point6-1
.frame(height: 300)
.ignoresSafeArea(edges:.top) // point6-2
CircleImage() //point6-3
.offset(y: -130)
.padding(.bottom,-130)
VStack (alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
.font(.subheadline) // point6-4
.foregroundColor(.secondary)
Divider()
Text("About Turtle Rock")
.font(.title2)
Text("Descriptive text goes here.")
}
.padding()
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}
}
}
point6-1 MapView
Section5で作成したMapView.swiftで定義してある、MapViewを参照。
fram そのviewサイズを指定。本来であれは、widthとheightの両方を指定するけれど、heightだけ指定した場合には、その画面に合わせて自動で幅が決まるよ。今回は画面いっぱいに表示がされているね。
point6-2 ignoresSafeArea
セーフエリアを無視する時につける。これをつける前の表示だと、地図の上に余白が設けられていたよ。これをつけることで、その領域の確保がされなくなるよ。
https://developer.apple.com/documentation/swiftui/view/ignoressafearea(_:edges:)
point6-3 CircleImage
Section4で作成したCircleImage.swiftの中で定義した、CircleImageを参照している。
point6-4 VStackに対する修飾
Stackに対してレイアウトの変更をすると、その中に含まれる全ての要素がそれに准ずるようになるよ。
以上でチュートリアルは終わりです。
理解度テストをやっておしまい。
## まとめ
最初だったので、超丁寧に調べながら進めたよ。
記述方式だけではなく、修飾子やフレームワーク、それぞれのファイルの持ち方も含め、勉強になりました。
一方で、まだ言葉の意味が落とし込めていないものもあるので、これは実際作ってみながら「こういうことね」と納得していけたらいいな