- 投稿日:2020-04-09T21:59:11+09:00
iPhoneのショートカットAppを使って、ヘルスケアに体温を楽々で記録する
みなさんこんばんは、スズキです。コロナ流行ってますね。怖いです。
求められる検温
さて、世の中的にはリモートが広まりつつありますが、友人の会社は作業開始時の日報に検温の記録が求められ始めたそうです。いやまぁ確かに学校と保育園は既にそうではあった。
そして、「検温記録で検索したらルナルナしか出ない、そうじゃないんだ」という声が飛び込んできました。検温の記録自体は、iOS標準のヘルスケアアプリに記録することが出来ます。ですが、辿り着くまでのUIUXがちょっと分かりにくいんですよね。ご婦人系のカテゴリの中に入ってしまっていて…。(あんまり言うのも野暮なので各自確認してくれ)。
結論として、iPhone標準のヘルスケアアプリで体温の記録の蓄積は行なえます。
ちょっと調べてみたところ、ショートカットAppのAPIがあったので、気不味い画面を開くこと無くスムーズに健康を管理出来るよう、レシピを作ってみたので公開します。尚、本件は以下のサイトを大いに参考にさせて頂きました。
ありがとうございます。何となく風は爽やか / conyline 様
ヘルスケアに現在の体温を記録するショートカットを作成する。(iOS13 ショートカット)
「if文」と「繰り返し」を使ってショートカットレシピを作成する。(iOS13 ショートカット)ショートカットAppとは
iOS12だか13で追加された機能です。
コードの書かないプログラミングというか、IFTTTの凄いやつというか、起動して値を入れたらBに変換されてCに収まっていく、ということを、アプリを跨いでやってくれる機能です。詳しくは以下。iPhone や iPad でショートカット App を使う - Apple サポート
手順
1. アプリの準備
「ショートカット」をApp Storeで
まずこの「ショートカット」アプリを入れて下さい。
気付いてないだけで、放置されている可能性もある。2. ショートカットレシピのダウンロード
ショートカット
今回作成したのはこちらになります。
iPhoneから接続するとダウンロードして、諸々聞いてくるので差し支えなければYESで進めて下さい。
諸々とは、ショートカットアプリがヘルスケアデータの書き込みと読み込みの許可を求めているよ、とか、インターネ
ットで公開されているレシピだから気をつけてね、とかそういう話です。また、オフィシャルではない公開アプリは予め許可設定を入れておかないと弾かれます。
こちらだけ、どうか自己責任ということでご承知おき下さい。
3. 実行する
数値を入れる、記録される、直近の記録も見たければ、ヘルスケアに飛ばすのでご確認下さい。
4. 実は他にもある起動方法
詳細は割愛しますが、大きく分けて3つ、起動する方法があります。
- オートメーション(=指定した時間や目覚ましと同時に起動する)
- ホームボタン化ショートカット内のアプリそのものをホーム画面に配置して、タップ一つで起動出来ます
- 画面左のウィジェットに配置。フリックしてボタンぽちーで完結
ちょっと弄れば、「検温を開始して下さい」(3分待機)「入力してください〜移行続く」みたいな動きにも出来るので、遊べて楽しいです
動作の内容について
慌てて作ったのですごい見にくくてすいません。
その他
ざっくり以上です。
体温のパラメータを基礎体温とかに変えれば、そのまま流用出来たりすると思うので、自由度高いと思います。
- 投稿日:2020-04-09T18:03:06+09:00
swiftの基礎的な書き方
Xcodeの基礎的なことを書いていきます。
変数と定数
変数は数学で習う、χみたいなもので数字を何回でも入れ替えることができる。
変数では、先頭にvarをつける。
var 変数名: 型名
定数は一度決めたら変えられないもの。
例えば円の直径を計算するときのπ=3.14みたいな、変えたらおかしくなってしまうもの。
定数は先頭にletをつける。
let 変数名: 型名
Swiftのデータ型
Swiftのデータ型を書いていきます。
Int型
正と負のデータを扱うときに使う。
Double型
小数点を扱うときに使う。
小数点を扱うものにFloat型もあるがこれは扱える範囲が狭いため基本的にはDouble型を使う。String型
文字列を扱うときに使う。
Bool型
論理演算でtrueかfalseを扱うときに使う。
条件分岐処理
条件分岐をするときは大体if文を使う。
こんな感じvar num = 10 if (num > 5) { print("true") } else { print("false") }結果は
trueとなるここにelse ifを使うことでどんどん条件を増やしていく。
文字列の結合
文字列の結合はこんな感じに書く
var test1 = tarou var test2 = maru print(test1 + test2) 結果 taroumaru文字と数字はそのままだと結合できないので、文字に合わせる場合は
String(test1)
というような感じで結合する。出力
swiftには
dump
という出力方法がある。
基本的に使うのはprintで、細かななところまで出力できるのがdumpdeです。
- 投稿日:2020-04-09T12:59:08+09:00
【SwiftUI】EmptyStateを作って理解するPreferenceKey
この記事は、SwiftUIで以下のような「子孫Viewの情報をコンテナViewで読み取るデザインのカスタムViewを作りたい」というiOSエンジニアへの知見共有を目的としており、調べた情報をなるべく素直に伝えていけるように書いていきます。
NavigationView { Text("Hello World") .navigationTitle("MyApp") }自分が
EmptyState
をSwiftUIで作ってみたいと思って調べ始めたので、その流れに沿って進めていきます。APIデザイン設計
冒頭にも挙げましたが、SwiftUIとのAPI一貫性を保つコンポーネントを作るために以下のNavigationViewようなAPIを目指しました。
参考にしたデザイン
NavigationView { Text("Hello World") .navigationTitle("MyApp") }ゴール
これまでのUIKit製のライブラリではDelegateを使ったEmptyStateの設定が多かったですが、SwiftUIでは@ViewBuilderを利用してカスタマイズ製が高く簡潔なEmptyStateのAPIを目指します。
EmptyStateView(empty: $empty) { Text("Hello World") .emptyStateItems { VStack(spacing: 15) { Image("EmptyImage") Text("EmptyTitle") Text("EmptyDescription") } } }調べて分かった事
上記のAPIを構築するために調べる必要があったのは以下の2つです。
.navigationTitle(text:)
適応後のViewの具体型がどのようになっているのか?- コンテナViewがどのようにして内部Viewの属性を知るのか?
以降はこの2つについて解説していきます。
NavigationViewが構築する具体型
構築された具体型を知るために、以下のようなコードをPlaygroundで書いて検証しました。
struct SampleView : View { var body : some View { NavigationView { Text("Hello world") .navigationBarItems(leading: Text("Leading")) } } } let sampleView = SampleView() print(type(of: sampleView.body))このViewの具体型は
NavigationView<EnvironmentReaderView<ModifiedContent<Text, _PreferenceWritingModifier<NavigationBarItemsKey>>>>になります。ModifiedContent以外は見慣れない型だと思うので、解説していきます。
EnvironmentReaderView
Appleの非公開APIのViewです。これについては全く情報がありません。
_PreferenceWritingModifier
こちらのAppleの非公開APIのModifierですが、iOS13以降のSwiftUIのswiftinterfaceを見る事で存在を確認できます。
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @frozen public struct _PreferenceWritingModifier<Key> : SwiftUI.ViewModifier where Key : SwiftUI.PreferenceKey { public var value: Key.Value @inlinable public init(key _: Key.Type = Key.self, value: Key.Value) { self.value = value } public static func _makeView(modifier: SwiftUI._GraphValue<SwiftUI._PreferenceWritingModifier<Key>>, inputs: SwiftUI._ViewInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs) -> SwiftUI._ViewOutputs public typealias Body = Swift.Never }そして、
func preference()
というModifierの具体型として返却されているのが分かります。(some Viewで隠蔽されているので、通常知ることはできませんが)@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension View { @inlinable public func preference<K>(key _: K.Type = K.self, value: K.Value) -> some SwiftUI.View where K : SwiftUI.PreferenceKey { return modifier(_PreferenceWritingModifier<K>(value: value)) } }
_PreferenceWritingModifier
は、実際には上記のModifierを呼ぶ事で返されているので自作する必要がなさそうです。NavigationBarItemsKey
Appleの非公開APIです。ただ、外側の
_PreferenceWritingModifier
が、Key:SwiftUI.PreferenceKey
を利用しているので、これがPreferenceKey
に適合した具体型であることは分かります。
PreferenceKey
はコンテナView側から内部のViewが保持する情報を読み出すための機構です。公式ドキュメントは記述が少ないので、チュートリアルから一歩踏み出したSwiftUIのCustom Viewの作り方ーその2(PreferenceKey編)という記事が分かりやすかったです。コンテナViewで内部Viewの保持する情報を読み出す
PreferenceKey
を利用する事で内部Viewの情報が読める事がわかりました。なので方針としてはこのようになります。
- 内側のViewで与えられる@ViewBuilderのViewを保持しておくために、
PreferenceKey
に適合したEmptyStateContentsKey
を自作する。extension View
で以下のような関数を用意し、emptyStateItems
を注入する。func emptyStateItems<Items>(@ViewBuilder items: () -> (Items)) -> some View where Items : View { }
EmptyStateView
において、bodyで以下のようにうまくpreferenceの値を読み出してemptyContent
として返したい。struct EmptyStateView : View { @Binding var empty: Bool var body: some View { if empty { return emptyContent } else { return filledContent } } }調べて分からなかった事
方針は立てましたが、
EnvironmentReaderView
についてはまるっきり分かりません。名前からしてなんらかのEnvironmentValue
の読み出しに関連しているような事だけは分かります。しかし、今回の実装にはこのView
は必要ありません。実装
それでは調べた事を踏まえて実装した
EmptyStateView
について解説していきます。
PreferenceKey
の自作struct EmptyStatePreferenceKey : PreferenceKey { static var defaultValue: Value = .init(view: EmptyView().eraseToAnyView()) static func reduce(value: inout Value, nextValue: () -> Value) { value = nextValue() } struct Value : Equatable { var view: AnyView var uuid = UUID() static func == (lhs: EmptyStatePreferenceKey.Value, rhs: EmptyStatePreferenceKey.Value) -> Bool { lhs.uuid == rhs.uuid } } }
Value
の自作
PreferenceKey
はassociatedvalue Value
としてEquatable
に適合した型を要求します。
EmptyStatePreferenceKey
では、クライアント側で渡されたViewを保持しておきコンテンツが空の時に表示する必要があるため、Value
ではview:AnyView
をプロパティとして保持させています。等価性を実装しないといけないのですが、AnyView
には上手く利用できそうな情報はないのでここではUUID
を利用します。加えて
static var defaultValue: Value
を返す必要があるので、ここではEmptyView
を返しておきます。
reduce(value:, nextValue:)
の実装こちらは必須実装のメソッドになります。
.preference(key: PreferenceKey, value: PreferenceKey.Value)
が呼ばれて値を渡されると、このreduce
が呼ばれます。この関数では新しく渡されたpreference
の値をどのように保持するかを決めます。基本的な実装方針として、inout
で渡された構造体の参照に対してnext()
の値を加える、もしくは代入する形になります。例えば
NavigationView
だと以下のようにnavigationTitle
を利用する事で複数のPreference
を設定する事ができますが、最後に設定した値だけが利用されます。上記のEmptyStatePreferenceKey
の実装でも、常に最後に設定された値だけが使われるようにvalue = nextValue()
としています。NavigationView { Text("") .navigationTitle("A") .navigationTitle("B") .navigationTitle("C") }これで子孫Viewで保持している値を親に流す仕組みは作れました。
EmptyStateViewの自作
特筆して複雑な事はしていませんが、注意すべき箇所は2つです。
onPreferenceChange
を利用して@State private var emptyStateItems: AnyView
を更新し、コンテンツが空の場合に表示するようにしています。extension View
でpublic func emptyStateItems<Items>
という関数を用意して、任意の箇所でpreference
を注入できるようにしています。/// A view for presenting empty state items when inner content is empty. public struct EmptyStateView<Content> : View where Content : View { private var content: Content @State private var emptyStateItems: AnyView @Binding private var empty: Bool public init(empty: Binding<Bool>, @ViewBuilder content: () -> Content) { self.content = content() // Initialized emptyContent from content, Implementation can be simple for several reasons. self._emptyStateItems = .init(initialValue: self.content.eraseToAnyView()) self._empty = empty } public var body: some View { // I don't know the reason but it goes well with using VStack. It doesn't go well with Group. VStack<AnyView> { if empty { return emptyStateItems .onPreferenceChange(EmptyStatePreferenceKey.self) { (preference) in self.emptyStateItems = preference.view } .eraseToAnyView() } else { return content .onPreferenceChange(EmptyStatePreferenceKey.self) { (preference) in self.emptyStateItems = preference.view } .eraseToAnyView() } } } } extension View { /// Configures the empty state items for the view. /// /// This modifier only takes effect when this view is inside of and visible within a `EmptyStateView`. /// /// - Parameter items: A view that appears when the content is empty. public func emptyStateItems<Items>(@ViewBuilder items: () -> Items) -> some View where Items : View { self.preference(key: EmptyStatePreferenceKey.self, value: .init(view: items().eraseToAnyView())) } }このようにして、子孫Viewの保持する情報を親Viewで読み取って利用する事が出来ました。
ソースコードの完成版はこちらで公開しています。
https://github.com/yosshi4486/EmptyState/tree/master/Sources/EmptyStateおわりに
ここまでで
NavigationView
はNavigationView<EnvironmentReaderView<ModifiedContent<Text, _PreferenceWritingModifier<NavigationBarItemsKey>>>>
という具体型を構築しているPreferenceKey
のシステムを利用して内部Viewの保持する値にアクセスする事で実現可能。EnvironmentReaderView
については一切わからない。EmptyStateの実現のために、
PreferenceKeyの具体型の自作と
EmptyStateView`の実装という解説を行いました。
SwiftUI
は深入りしようと思うと
- まだ情報が十分ではない
- 仕組みが難しい
- iOSのバグで奇妙な挙動をする事がある
など大変なため、少しでも情報を公開して知見がネットに貯まれば良いと思い記事化しています。
ここまでお読みいただきありがとうございました。
改定履歴
2020/04/13 PreferenceKeyを利用した実装が実現できたため、関連する部分を差し替えてタイトルを変更しました。
- 投稿日:2020-04-09T12:59:08+09:00
【SwiftUI】NavigationViewのようなカスタムViewを自作しようとして分かった事と分からなかった事
この記事は、SwiftUIで以下のような「内部のViewの情報をコンテナViewで読み取るデザインのカスタムViewを作りたい」というiOSエンジニアへの知見共有を目的としています。
NavigationView { Text("Hello World") .navigationTitle("MyApp") }iOSでもAndroidでもよく見かけるEmptyState(iOSでは昔DZNEmptyDataSetがよく使われてた)をPureSwiftUIで実装しようと思ったときに、分かった事とわからなかった事があったので紹介していきます。
この記事は現状では代替案を最後に解説していますが、正しい解決法が分かり次第タイトルを含む記事の内容を更新します。
APIデザイン設計
冒頭にも挙げましたが、SwiftUIとのAPI一貫性を保つコンポーネントを作るために以下のNavigationViewようなAPIを目指しました。
参考にしたデザイン
NavigationView { Text("Hello World") .navigationTitle("MyApp") }ゴール
これまでのUIKit製のライブラリではDelegateを使ったEmptyStateの設定が多かったですが、SwiftUIでは@ViewBuilderを利用してカスタマイズ製が高く簡潔なEmptyStateのAPIを目指しました。
EmptyStateView(empty: $empty) { Text("Hello World") .emptyStateItems { VStack(spacing: 15) { Image("EmptyImage") Text("EmptyTitle") Text("EmptyDescription") } } }分かった事
上記のAPIを構築するために知らなければいけなかったことは下の2つです。
.navigationTitle(text:)
適応後のViewの具体型がどのようになっているのか?- コンテナViewがどのようにして内部Viewの属性を知るのか?
以降はこの2つについて解説していきます。
NavigationViewが構築する具体型
構築された具体型を知るために、以下のようなコードをPlaygroundで書いて検証しました。
struct SampleView : View { var body : some View { NavigationView { Text("Hello world") .navigationBarItems(leading: Text("Leading")) } } } let sampleView = SampleView() print(type(of: sampleView.body))このViewの具体型は
NavigationView<EnvironmentReaderView<ModifiedContent<Text, _PreferenceWritingModifier<NavigationBarItemsKey>>>>になります。ModifiedContent以外は見慣れない型だと思うので、解説していきます。
EnvironmentReaderView
Appleの非公開APIのViewです。これについては全く情報がありません。
_PreferenceWritingModifier
こちらのAppleの非公開APIのModifierですが、iOS13以降のSwiftUIのswiftinterfaceを見る事で存在を確認できます。
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @frozen public struct _PreferenceWritingModifier<Key> : SwiftUI.ViewModifier where Key : SwiftUI.PreferenceKey { public var value: Key.Value @inlinable public init(key _: Key.Type = Key.self, value: Key.Value) { self.value = value } public static func _makeView(modifier: SwiftUI._GraphValue<SwiftUI._PreferenceWritingModifier<Key>>, inputs: SwiftUI._ViewInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs) -> SwiftUI._ViewOutputs public typealias Body = Swift.Never }そして、
func preference()
というModifierの具体型として返却されているのが分かります。(some Viewで隠蔽されているので、通常知ることはできませんが)@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension View { @inlinable public func preference<K>(key _: K.Type = K.self, value: K.Value) -> some SwiftUI.View where K : SwiftUI.PreferenceKey { return modifier(_PreferenceWritingModifier<K>(value: value)) } }
_PreferenceWritingModifier
は、実際には上記のModifierを呼ぶ事で返されているので自作する必要がなさそうです。NavigationBarItemsKey
Appleの非公開APIです。ただ、外側の
_PreferenceWritingModifier
が、Key:SwiftUI.PreferenceKey
を利用しているので、これがPreferenceKey
に適合した具体型であることは分かります。
PreferenceKey
はコンテナView側から内部のViewが保持する情報を読み出すための機構です。公式ドキュメントは記述が少ないので、チュートリアルから一歩踏み出したSwiftUIのCustom Viewの作り方ーその2(PreferenceKey編)という記事が分かりやすかったです。コンテナViewで内部Viewの保持する情報を読み出す
PreferenceKey
を利用する事で内部Viewの情報が読める事がわかりました。なので方針としてはこのようになります。
- 内側のViewで与えられる@ViewBuilderのViewを保持しておくために、
PreferenceKey
に適合したEmptyStateContentsKey
を自作する。extension View
で以下のような関数でEnvironmentReaderView
に包まれたModifiedContent
を返すようにするfunc emptyStateItems<Items>(@ViewBuilder items: () -> (Items)) -> some View where Items : View { }
EmptyStateView
において、bodyで以下のようにうまくpreferenceの値を読み出してemptyContent
として返したい。struct EmptyStateView : View { @Binding var empty: Bool var body: some View { if empty { return emptyContent } else { return filledContent } } }分からなかった事
方針は立てましたが、
EnvironmentReaderView
についてはまるっきり分かりません。名前からしてなんらかのEnvironmentValue
の読み出しに関連しているような事だけは分かります。しかし、今回の実装にはこのView
は必要ありません。実装
それでは実装を解説していきます。
PreferenceKey
の自作struct EmptyStatePreferenceKey : PreferenceKey { static var defaultValue: Value = .init(view: EmptyView().eraseToAnyView()) static func reduce(value: inout Value, nextValue: () -> Value) { value = nextValue() } struct Value : Equatable { var view: AnyView var uuid = UUID() static func == (lhs: EmptyStatePreferenceKey.Value, rhs: EmptyStatePreferenceKey.Value) -> Bool { lhs.uuid == rhs.uuid } } }
Value
の自作
PreferenceKey
はassociatedvalue Value
としてEquatable
に適合した型を要求します。
EmptyStatePreferenceKey
では、クライアント側で渡されたViewを保持しておきコンテンツが空の時に表示する必要があるため、Value
ではview:AnyView
をプロパティとして保持させています。等価性を実装しないといけないのですが、AnyView
には上手く利用できそうな情報はないのでここではUUID
を利用します。加えて
static var defaultValue: Value
を返す必要があるので、ここではEmptyView
を返しておきます。
reduce(value:, nextValue:)
の実装こちらは必須実装のメソッドになります。
.preference(key: PreferenceKey, value: PreferenceKey.Value)
が呼ばれて値を渡されると、このreduce
が呼ばれます。inout
で渡された構造体の参照に対して、next
の値を加えていくような形が基本になります。例えば
NavigationView
だと以下のように複数のPreference
を設定する事ができますが、最後に設定した値が利用されます。上記のEmptyStatePreferenceKey
の実装でも、常に最後に設定された値だけが使われるようにvalue = nextValue()
としています。NavigationView { Text("") .navigationTitle("A") .navigationTitle("B") .navigationTitle("C") }これで子孫Viewで保持する値を親に流す仕組みは作れました。
EmptyStateViewの自作
特筆して複雑な事はしていませんが、注意すべき箇所は2つです。
onPreferenceChange
を利用して@State private var emptyStateItems: AnyView
を更新しています。extension View
でpublic func emptyStateItems<Items>
という関数を用意して、任意の箇所でpreference
を注入できるようにしています。/// A view for presenting empty state items when inner content is empty. public struct EmptyStateView<Content> : View where Content : View { private var content: Content @State private var emptyStateItems: AnyView @Binding private var empty: Bool public init(empty: Binding<Bool>, @ViewBuilder content: () -> Content) { self.content = content() // Initialized emptyContent from content, Implementation can be simple for several reasons. self._emptyStateItems = .init(initialValue: self.content.eraseToAnyView()) self._empty = empty } public var body: some View { // I don't know the reason but it goes well with using VStack. It doesn't go well with Group. VStack<AnyView> { if empty { return emptyStateItems .onPreferenceChange(EmptyStatePreferenceKey.self) { (preference) in self.emptyStateItems = preference.view } .eraseToAnyView() } else { return content .onPreferenceChange(EmptyStatePreferenceKey.self) { (preference) in self.emptyStateItems = preference.view } .eraseToAnyView() } } } } extension View { /// Configures the empty state items for the view. /// /// This modifier only takes effect when this view is inside of and visible within a `EmptyStateView`. /// /// - Parameter items: A view that appears when the content is empty. public func emptyStateItems<Items>(@ViewBuilder items: () -> Items) -> some View where Items : View { self.preference(key: EmptyStatePreferenceKey.self, value: .init(view: items().eraseToAnyView())) } }このようにして、子孫Viewの保持する情報を親Viewで読み取って利用する事が出来ました。
ソースコードの完成版はこちらで公開しています。
https://github.com/yosshi4486/EmptyState/tree/master/Sources/EmptyStateおわりに
ここまででNavigationViewのようなカスタムViewの自作において
NavigationView
はNavigationView<EnvironmentReaderView<ModifiedContent<Text, _PreferenceWritingModifier<NavigationBarItemsKey>>>>
という具体型を構築しているPreferenceKey
のシステムを利用して内部Viewの保持する値にアクセスする事で実現可能。EnvironmentReaderView
については一切わからない。- EmptyStateViewの自作
という解説を行いました。
もし何か知見をお持ちの方いらっしゃいましたら、お助け頂けると助かります。
改定履歴
2020/04/13 PreferenceKeyを利用した実装が実現できたため、関連する部分を差し替えました。
- 投稿日:2020-04-09T01:51:30+09:00
FlutterがiPhoneの実機ではビルドできない人へ
iOS13.3ではビルドできないよ!!!13.4にアップデートしましょう!!
僕の伝えたいことはこれだけです。
謎のエラーにflutterでアプリ開発し始めた瞬間思いっきり出鼻を挫かれましたが、久々に触ってみて、iOSをアップデートしたら直りました。
しっかりstackoverflowか何かでアップデートに伴うバグはチェックしましょう、、、(自戒)
その他注意点
Xcodeの設定を忘れずにしましょう。
- Signing & CapabilityでTeamを設定すること
- BundleIDの設定
など。・BundleIDの設定についてのメモ
アプリのBundleIDとそれが含めるbundleのBundleIDが一致しているよ(?)みたいなエラーが出た時はそれらのBundleIDを異なるものにしたら直りました。(雑すぎてすみません)リクエストがあればできるかぎり詳しく書いていこうと思います!!
- 投稿日:2020-04-09T00:28:41+09:00
"001 UILabelで文字を表示" iOS app開発 習得日記 (5)
UIkitを覚えるために
こちらの写経がいいときいたので始めた
(http://docs.fabo.io/swift/uikit/001_uilabel.html)001 UILabelで文字を表示
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let bWidth: CGFloat = 200 let bHeight: CGFloat = 50 let posX: CGFloat = self.view.bounds.width/2 - bWidth/2 let posY: CGFloat = self.view.bounds.height/2 - bHeight/2 let label: UILabel = UILabel(frame: CGRect(x: posX, y: posY, width: bWidth, height: bHeight)) label.backgroundColor = UIColor.orange label.layer.masksToBounds = true label.layer.cornerRadius = 20.0 label.shadowColor = UIColor.gray label.textAlignment = NSTextAlignment.center self.view.backgroundColor = UIColor.cyan self.view.addSubview(label) } }selfは、ViewControllerのインスタンスを表しているのでよいのか?
また、label.layer.masksToBoundsとドットを続けて書いているところがわからない。
labelインスタンスの layerプロパティのmasksToboundsプロパティということ?
プロパティのプロパティ?
どういうこと?