20210729のSwiftに関する記事は6件です。

RGBを用いて色を決める(UIColor)

今回の内容 アプリを作ってる時に、どうすればカスタムされた色をコードで使えるのか気になったので調べてみました。 UIColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)を用いて色を変えてみます。 RGBとは なんとなく分かりそうですが、RはRed、GはGreen、BはBlueです。 この3色の組み合わせを用いて、さまざまな色を表示することが出来ます。 コードと簡単解説 今回は、コードで作成したUISegmentedControlのselectedSegmentTintColorでカスタムした色を使いたいので、UIColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)を使用します。 今回は、この画像の赤い色を表示します uiSegmentControl.selectedSegmentTintColor = UIColor(red: 1.0, green: 0.40, blue: 0.51, alpha: 1.0) ここで、red: 1.0, green: 0.40, blue: 0.51, alpha: 1.0の値を簡単に調べる方法を書きます Main.storyboardにViewなどの色を設定できるものを作成します。 色をcustomで選択します。(今回はViewのbackgroundColorに色を設定したと仮定) viewDidLoadなどでprint(self.view.backgroundColor as Any)を使用するとデバッグエリアに下記のように表示されます。 左からRGBと一番右はalphaです。 表示された数字の部分を四捨五入して使います。(例:0.405169を0.40にして使います)  (UIExtendedSRGBColorSpace 1 0.405169 0.512318 1) 実際のコード class SegmentedControl{ var uiSegmentControl = UISegmentedControl() let realmCRUDModel = RealmCRUDModel() } extension SegmentedControl{ func createSegment(targetView:UIView){ realmCRUDModel.readRealmTag() uiSegmentControl.removeAllSegments() for segmentCount in 0...realmCRUDModel.realmTagArray.count - 1{ uiSegmentControl.insertSegment(withTitle: realmCRUDModel.realmTagArray[segmentCount], at: segmentCount, animated: true) } uiSegmentControl.frame = CGRect(x: targetView.bounds.minX + 5, y: targetView.bounds.minY + 97, width: targetView.frame.size.width - 10, height: 32) uiSegmentControl.selectedSegmentTintColor = UIColor(red: 1.0, green: 0.40, blue: 0.51, alpha: 1.0) targetView.addSubview(uiSegmentControl) } } 終わり Qiitaを書いてると無意識に書く内容を何回も呟いたり、考えたりするので いつの間にか覚えてることが最近よくある ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[iOS]試して学ぶUnitTest[XCTest]

はじめに 今回は初めてUnitTestを学びたい、試してみたい方向けの内容となっています。 よってUnitTestとは直接関係ない用語に対しても、できる限り疑問に思われそうな内容にも触れています。(筆者がそうであったので) よって、早々に試したいと言う方は"UnitTestを試してみる"からお読み下さい。 予備知識 UnitTestを勉強し始めると必ずTDDやCI/CDといった用語ができてきます。 ここでは予備知識として紹介させて頂きます。 TDDとは TDDとはTest Driven Developmentの略で直訳は"テスト駆動開発"です。 テスト駆動開発とは、レッド→グリーン→リファクタリングの3工程を行い開発する手法です。以下それぞれの工程の解説です。 ・[レッド]機能、要件を元に失敗するテストコードを書く →機能を実装するコード(プロダクトコード)を書く前にテストコードを書きます。つまりテストは失敗しエラーとなります。 ・[グリーン]テストが成功するコードを書く →ここで初めて機能を実装するコードを書いていきます。"テストコードが成功するように書く"事によりゴールを明確にする事ができます。 ・[リファクタリング]プロダクトコードが可読性の高いコードとなるように書き換える →"テストが成功している=可読性が高い"とは言い辛いので、テストが成功している状態を維持しつつリファクタリングをする事でより可読性を上げ、保守生の高いコードが担保できます。 つまりTDDとは設計手法の一つと言えます。 CI/CDとは CIとはContinuous Integrationの略で直訳は継続的インティグレーションです。 Integration(統合)とはテストを含む一連の作業の事を指します。 CDとはContinuous Deliveryの略で直訳は継続的デリバリーです。 Delivery(配達)はリリースプロセス全体の事を指します。 つまり、テストを含め、機能の追加や変更などが加わる度にビルドを行い、リリースのプロセスまでを自動化させる事で継続的に、効率良く作業を行う事ができる、設計手法の一つと言えます。 以上のように、TDD、CI/CD共に設計手法の一つですので適時、テームや会社で判断され、使用される事が想像できます。どちらも、様々な記事や本にも記載されていますが、"如何なる状況でも有効"というものではなく、常に有効な手段とは限らないのでその時、その環境に適した技術選定をしていく事が重要かと思います。 UnitTestとは UnitTestそのものは最小単位のコンポーネント(クラス、構造体、関数など)に対して行うテストの事で、ここでは最小単位のコンポーネントに対して自動化され、繰り返し実行可能で統一的な仕組みに支えられたテストの事を指します。 今回は公式からXCTestが用意されているので今回はXCTestを使用していくものとします。 UnitTestを試してみる 今回使用するサンプル 今回は数値を2つ入力すると掛け算をして出力すると言うサンプルを作ってUnitTestを試して行きます。 環境 ・ macOS Big Sur 11.5 ・ Xcode : 12.5 作成方法 プロジェクトを作成する際にInclude Testsにチェックを入れます。(後から入れる事もできます→参考記事) 後から新規作成する場合 unitで検索 これでUnitTestのファイルを作成する事が出来ます。 初期の関数について ファイルを作成した時点で初期に様々な関数が入っています。 下記はそれぞれの関数を直訳したものになります。 ・setUpWithError ここにセットアップコードを入力します。このメソッドは、クラス内の各テストメソッドを呼び出す前に呼び出されます。 ・tearDownWithError ここに分解コードを入れてください。このメソッドは、クラス内の各テストメソッドの呼び出し後に呼び出されます。 ・testExample これは機能テストケースの例です。 XCTAssertおよび関連する関数を使用して、テストで正しい結果が得られることを確認します。 ・testPerformanceExample これは、パフォーマンステストケースの例です。 ・self.measure ここに時間を測定したいコードを入れてください。 テストをしてみる 上記で紹介した様にプロジェクト初期から様々な関数が入っていますが、関数は一旦削除してテストコードを書いてみます。 テストコードは"何のテストをしているか"を分かりやすくしておく事が非常に重要です。 その為には ・テストケース名を分かりやすくする ・テストコードの中身を分かりやすくする ・テストが失敗した時の情報を用意する の3点を重視する事は様々な良書で語られていますが、ここでは特に"テストコードの中身を分かりやすくする"について解説を交えながらテストを行います。 サンプルコード 今回は数値を2つ入力すると掛け算をして出力すると言うサンプルを作ってUnitTestを試していきます。 まずは以下のModel(ロジック)を用意します。 import Foundation protocol MultiplyInterface { func multiply(num1: Int, num2: Int) -> Int } class MultiplyModel: MultiplyInterface { private var num1: Int = 0 private var num2: Int = 0 // num1とnum2を乗算した値を返す func multiply(num1: Int , num2: Int) -> Int { let multiplication = num1 * num2 return multiplication } } 上記のModelを対象に"テストコードの中身を分かりやすく"テストを書いきます。 コードは以下の様にXCTestCaseの中に書きます。 import XCTest @testable import UnitTestSampler_Multiply class UnitTestSampler_MultiplyTests: XCTestCase { func test_num1とnum2の引数が掛け算されていれば成功() { // 前処理 let multiplyModel = MultiplyModel() // 実行 let result = multiplyModel.multiply(num1: 10, num2: 5) // 検証 XCTAssertEqual(50, result) // 後処理 } } シンプルなサンプルなので、テストもシンプルです。 コードについては上から順に、以下解説します。 import XCTest XCTestフレームワークをインポートします。このフレームワークが無いと以下にあるXCTestCaseクラスやXCTAssertなどの関数を使用する事ができないので必須です。 @testable import UnitTestSampler_Multiply 今回テストを行うプロジェクトをテスト用にインポートします。つまり今回はUnitTestSampler_Multiplyと言う名前のプロジェクト内にあるコンポーネントに対してテストを行いますのでテスト用にインポートする必要があります。こちらもXCtestを用いてUnitTestする際は必須です。 class UnitTestSampler_MultiplyTests: XCTestCase { } テストクラスを宣言します。その際XCTestCaseに準拠させる必要があります。 テストコードはこのクラス内に書きます。 func test_num1とnum2の引数が掛け算されていれば成功() { } テストを行うための関数です。関数名はこのテストがなんのテストをしているか、関数名で分かるように書く事が良いとされています。これには明確な理由があります。テストは失敗すると、どのテストが失敗したか"メソッド名"が記載されます。コメントとして残しておく事も良いとは思いますが、失敗した際にどのテストが失敗したのか、素早く特定する為にも分かりやすい命名をしておく事はマストと言えます。命名に関してはチームや会社で取り決めがある、もしくは共通の取り決めをしておく必要がありますが、基本的に"分かりやすく"が最重要となりますので、日本語を含ませるケースもよくあります。(筆者が知る限り) また頭にはtestをつける事でtestメソッドの対象になりますので(左側にひし形のマークが付きます)必ず頭にtestをつける必要があります。 // 前処理 let multiplyModel = MultiplyModel() // 実行 let result = multiplyModel.multiply(num1: 10, num2: 5) // 検証 XCTAssertEqual(50, result) // 後処理 テストではいかにテストコードの中身が分かりやすく書かれているかは重要です。 分かりやすく書く為には ・前処理 ・実行 ・検証 ・後処理 の4つにテストコードを分けて書きます。 前処理や後処理は ・setUpWithError(前処理) ・tearDownWithError(後処理) に書く事もあります。今回はシンプルなサンプルな為使用はしませんでしたが、APIを利用したアプリで、スタブやスパイなどを使用する際や、ローカルDB(UserDefaultsやCoreData)を使用する際はテスト後に元に戻す必要がありますので、後処理に記載して元に戻す作業を行なったりします。 実行では実際にテストを行いたいメソッドなどを実行します。 そして検証ではその実行結果を元に検証していきます。 検証で使用されるメソッドをAssert(アサート)と言います。XCTestで検証をする際は必須になりますので是非いろんなAssertがある事を覚えておくと良いかと思います。 以下Assertメソッドを一覧にしてまとめている記事がありますので是非ご活用下さい。(私も非常に活用させて頂いています。) 何をテストするか選択する方法 ここまで読んで頂きありがとうございます。この辺りでUnitTestについて大まかに理解が進んできたのでは無いでしょうか?ここからは筆者がテストを学び始めて少し経った頃に非常に困った内容を中心に解決した方法も併せてご紹介したいと思います。 何をテストすればいいかわからない テストの書き方が少し分かってきて、嬉しく、今まで作ってきたサンプルを引っ張り出してテストを書いていると"あれ?こんなテストもあった方がいいような、、、"とか"全ての関数に対してテスト書いた方がいいのか?"とか"入力の値に対してどこまでテスト書けばいいんだ、、、"などに直面するケースがあると思います。 そもそもテストに時間やコストをかける事あまり良くないとされています。様々な理由がありますが特に多く謳われているのが、時間やコストが高いと継続的にテストがされなくなる点です。UnitTestはあくまで機能を担保するものであるので必要な部分だけあれば良いと思っています。 ではその"必要"というものは何を基準にすれば良いのか? もちろん主要なコンポーネントに対してテストを行う事は重要ですが(今回の場合掛け算をするメソッドが重要なコンポーネントとなるので引数を2つ渡す事で掛け算がされるかテストを行なった)それ以外にもテストをしようとなった際、役立つのが以下の3つの手法です。 ・同値分割 例えば点数を入力しその点数によって"優"、"良"、"可"、"不"と判断するメソッドがあったとします。 80点以上は優である場合、80〜100点の21個の数字全てをテストするべきかと考えた場合、そうではなく、代表の点数を一つ選択し、その点数をテストの値として用いれば良いとされています。 ・境界値 先程の同値分割で記載した例のような場合で以下の様な条件であると仮定します。 ・80点以上は優 ・60点以上79点以下は良 ・30点以上59点以下は可 ・29点以下は不 この場合、優の境界値は80,良の境界値は79と60になります。 優の場合は score >= 80 だと80以上となりますが、万が一 score > 80 となっていた場合81からとなります。この様に判定の境界に当たる値のみをテストするだけで、境界値がしっかり機能しているかテストする事ができます。 ・単項目チェック 例えば上記の条件に ・18歳未満はそれぞれに5点足した値を基準とする とした場合、また+5点した基準のテストを全て行いそうですが、上記の同値分割と境界値テストによって ・点数によって出力が変更されている ・境界値でも機能している 事が担保されているので、18歳未満が70点の時、良になる事が担保されるテストを書けば18歳未満も機能していると言えます。 この様にケースバイケースではありますが、単項目チェックをする事で無闇にテストを増やす事を回避するができます。 依存コンポーネントを差し替える 色々とテストを試していると次に直面するのは依存が強いクラスに対するテストが書けないという問題です。 例えばMVVMを採用して開発した場合ViewModelとModelは依存しがちです。 MVVMの詳細はここでは避けますが、ViewModelはViewとModelの架け橋となる為です。 ではどうしたら良いか。DIを注入する事です。(依存性注入) DIについてはこちらの記事で非常にわかりやすくまとめられていますのでご覧下さい。 DIを注入したらテストにも細工をしていきます。色々と手法がある様ですが主な手法としては以下2つです。 ※以下テスト対象とするコンポーネントに対してstubと差し替えられる様、共通のプロトコルを宣言し、準拠させる必要がありますのでDIは必須となります。 ・stub(スタブ) 例えばGitHubやQiitaなどのAPIを利用して値を取得するclassがあったとします。 このコンポーネントをそのままテストしようとすると、おもっきりサーバー側に依存して不安定なテストとなります。(筆者はこれで思いっきり大事な場面でミスした事があります) ではサーバーに依存なくテストを書くにはどうしたら良いのか?そこでstubの出番です。 stubはテスト検証をする際、テストの都合に良い値を返すテスト用のコンポーネントに差し替えて使用するものです。 例えば上記のようにサーバーに依存する様なテストではstubを差し込み、予めサーバーからの返答が成功か失敗か決めておく事ができます。すると、テストも成功のケースと失敗のケースが安定した状態で書ける状態になります。stubに関してはまた事例を用いて書きたいと思いますが、今回は入門記事なのでサンプルコードは割愛させて頂きます。 ・mock(モック) 外部APIを利用して値を取得する場合サーバーに格納されている情報は時間の経過と共に変化する事が多いと思います。その様な状態でXCTAssertEqualでテストを行うとどうなるでしょうか。時間と共に結果が変化するので、ある時は成功するかもしれませんが、ある時は失敗するかもしれません。これでは安定したテストとは言えません。そんな時はmockの出番です。メソッドなどで外部サーバーから値を取得する代わりに事前にmockを用意しておくことで差し替えて、安定した内容を検証する事ができます。こちらもstub同様、また事例を用いて書きたいと思いますが、今回は割愛させて頂きます。 まとめ いかがでしたでしょうか?テストについて今まで何となく聞いたことあると言う認識から少しでも理解して頂けたでしょうか?もし、"この辺りが分かりにくい"とか"この辺りもっと詳細に知りたい"と思われた方は是非下記の参考記事や本の購入をおすすめします!!(私のTwitterにDMして頂いても構いません) テストはとにかく書いてみると非常に面白く感じる部分もありますので是非簡単なものから書くことをおすすめします!! 以上です。最後まで読んで頂きありがとうございました!! 参考文献+オススメ記事(本)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift]構造体のメンバーごとの初期化子(initializer)はいつ使用できるのか。

※この記事はSwift by Sundellの内容を日本語に翻訳したものです。 Swiftでは、構造体として定義された型は、コンパイラーによって合成されたデフォルトの初期化子(いわゆる「メンバーごとの初期化子」)を自動的に取得します。これは、コンパイラーが指定された構造体のメンバー(つまり、その格納されたプロパティ)に基づいて生成するためです。 たとえば、 nameプロパティとpreferencesプロパティを持つ User構造体を定義した場合、メンバーごとの初期化を使用して、これら2つのプロパティの値を渡すだけでインスタンスを作成できます。 struct User { var name: String var preferences: Preferences } let user = User(name: "John", preferences: Preferences()) 一方、計算されたプロパティは、コンパイラがメンバーごとの初期化子を合成するときに完全に無視されます。したがって、初期化子を追加しても、以前と同じように上記の初期化子を使用し続けることができます。 struct User { var name: String var preferences: Preferences var icon: Icon { .user } } let user = User(name: "John", preferences: Preferences()) Swift 5.1以降、メンバーごとの初期化子はデフォルトのプロパティ値も考慮に入れます。つまり、preferencesプロパティにデフォルト値を指定すると、nameを渡すだけでUserインスタンスを作成できるようになります。 struct User { var name: String var preferences = Preferences() } let user = User(name: "John") クールな点の1つは、型にprivateプロパティがある場合でも、それらのプロパティに次のようなデフォルト値がある限り、型のメンバーごとの初期化子を使用し続けることができることです。 struct User { var name: String private var preferences = Preferences() } let user = User(name: "John") ただし、privateプロパティにデフォルト値がない場合は、そのタイプのイニシャライザを手動で作成する必要があります。これにより、そのプロパティの値を外部から挿入できるようになります。 struct User { var name: String private var preferences: Preferences init(name: String, preferences: Preferences = .init()) { self.name = name self.preferences = preferences } } let user = User(name: "John") // ↓でもOK let user = User.init(name: "John") ただし、メンバーごとのイニシャライザーのアクセスレベルがinternalより高くなることはありません。つまり、タイプが定義されているモジュール内でのみ内部的に使用できます。 これは最初は奇妙な制限のように思えるかもしれませんが、データの内部構造に縛られることなく、常にパブリック消費用の明示的なAPIを設計する必要があるため、メリットがあります。 したがって、要約すると、次の場合に構造体のメンバーごとの初期化子を使用できます。 そのすべてのメンバーが表示されるか、デフォルト値がある場合。 構造体が定義されているのと同じモジュール内にインスタンスを作成している場合。 他のすべてのケースでは、少なくとも今のところ、初期化子を手動で実装する必要があります。 元の記事 When can a struct’s memberwise initializer be used? Swift by Sundell
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

omise-iosを利用して、決済機能を導入する方法

omise-iosを利用して、決済機能を導入する方法 個人開発で決済機能があるアプリを開発していました。 その開発しているアプリには、決済機能があったため、、さまざまなサービスを見て、最も導入しやすそうなOmiseというサービスを選びました。 最初はstripeを利用するつもりでしたが、導入方法を模索しているうちに時間がかかりすぎていたため、今回は導入しやすいOmiseにしました。 Omiseを導入するメリット 導入が簡単 GitHubに公開されているOmise iOS SDKと、HPにあるドキュメントを見て、真似するだけで導入できます。 ドキュメントに関しては日本語版もあります。 また、GitHubのSDKに関しては、翻訳ツールを使えば大丈夫なほど簡単に書かれています。 僕自身、READMEやドキュメントを読んだことがありませんでしたが、いけました。 対応が早い Swiftが初めてのプログラミング言語で、まだ半年も学んでいない人はつまづくかもしれません。 しかし、そのときは運営に問い合わせることで疑問を解決してくれます。 営業時間内であれば、1~2時間あれば返信をくれることが多いです。 実際に僕はつまづいたり、疑問が出てきたときに何回も問い合わせましたが、丁寧にすぐに返信してくれました。 上記より、学び始めて半年も経たない人で、決済機能を導入したい人はOmiseがおすすめです。 omise-iosを利用して、決済機能を導入する方法 今回は、決済を行う部分だけを紹介します。 その他の機能のほとんどは、以下で紹介する方法でいけます。 アカウントを作る まずは、OmiseのHPに飛んで、アカウントを作ってください。 OmiseSDKをインストールする Xcode12以上なら、Omise iOS SDK をSwift Package Managerでインストールできます。 ついでに、CurlDSLをインストールしておいてください。 これは通信するときに利用します。 他のライブラリーで対応するという方は必要ありません。 シークレットキーとパブリックキーを書く ダッシュボードの左のメニューから「キー」を選ぶと、シークレットキーとパブリックキーを見れます。 最初は、テスト用のダッシュボードで試すことをおすすめします。 僕は、以下のように書くと、どのファイルからでも取り出せます。 ドキュメントを見ると、本番用を使うときは、暗号化することをおすすめされています。 import OmiseSDK class Omise { private init() {} static let shared = Omise() let publicKey = "自分のパブリックキーを打つ" let secretKey = "自分のシークレットキーを打つ" let client = OmiseSDK.Client.init(publicKey: "自分のパブリックキーを打つ") } クレジットカード情報を書くフォームを準備する クレジットカード情報を書くフォームは自身で準備しても大丈夫ですが、運営から提供されているものを使うと簡単です。 import OmiseSDK // at the top of the file class ViewController: UIViewController { private let publicKey = "自分のパブリックキーを持ってくる" @IBAction func displayCreditCardForm() { let creditCardView = CreditCardFormViewController.makeCreditCardFormViewController(withPublicKey: publicKey) creditCardView.delegate = self creditCardView.handleErrors = true present(creditCardView, animated: true, completion: nil) } } extension ViewController: CreditCardFormViewControllerDelegate { func creditCardFormViewController(_ controller: CreditCardFormViewController, didSucceedWithToken token: Token) { dismissCreditCardForm() // Sends `Token` to your server to create a charge, or a customer object. } func creditCardFormViewController(_ controller: CreditCardFormViewController, didFailWithError error: Error) { dismissCreditCardForm() // Only important if we set `handleErrors = false`. // You can send errors to a logging service, or display them to the user here. } } このコードにあるCreditCardFormViewControllerがECサイトなどで見る、クレジットカード情報を書くフォームになります。 キーボードタイプの設定やバリデーションなどを既に設定してくれているので、簡単にフォームを実装できます。 実際のフォームの写真は以下に貼っておきます。 extensionを書く extension には、 Payボタンの処理が失敗したときと成功したときにどうするかを書く必要があります。 しかし、ここで注意点があります。 ・Payを押されたときには、まだ決済が完了していないこと Payを押されて、successが返ってきたら決済が成功したと勘違いするかもしれません。 しかし、実際にPayボタンを押されたときに行われることは、以下の通りです。 1. クレジットカード情報をOmise側のサーバーに送る 2. Omise側のサーバーでクレジットカード情報をトークン化する 3. そのトークン化されたものを受け取る(success) そのため、successがきたということはトークンを受け取れたという意味です。 このときに、自分のサーバー(FirebaseやAWS)にクレジットカード情報を送信しないでください。 自分のサーバーに送ると、それを管理するコストが発生するため、運営も禁止しています。 そして、その受け取ったトークンを使い、決済を行います。 決済を行うコードは以下の通りです。 import OmiseSDK import CurlDSL func creditCardFormViewController(_ controller: CreditCardFormViewController, didSucceedWithToken token: Token) { // 最低でもこの3つのパラメーターは必要です。 let parameters = ["amount": 100000, //金額は自由です。 "currency": "jpy", //日本円 "card": token.id] as [String : Any] let session = URLSession.shared var request = try? CURL("curl -X POST -u \(シークレットキーを書く): https://api.omise.co/charges").buildRequest() do { request?.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) } catch let error { print(error.localizedDescription) } request?.addValue("application/json", forHTTPHeaderField: "Content-Type") request?.addValue("application/json", forHTTPHeaderField: "Accept") let task = session.dataTask(with: (request ?? URLRequest(url: url)) as URLRequest, completionHandler: { data, response, error in // この辺の処理は自由に do { if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { // この辺の処理は自由に } } catch {                  // この辺の処理は自由に } }) task.resume() } CurlDSLをインストールしてもらった理由は、requestを作成するときに、-u \(シークレットキーを書く):を再現する方法がわからなかったからです。 ここはドキュメントを見ても、書かれておらず、運営に問い合わせても期待した答えは返ってきませんでした(聞き方が悪かったかもしれません)。 そのため、できる方はご自身のやり方で通信してみてください。 *ぜひ他の方法がわかる方はコメントで教えてください。 これでダッシュボードでシュミレーターや実機で試してみると、ダッシュボードに反映されています。 また、試すときにはテストカードを使ってください。 var request = try? CURL("curl -X POST -u \(シークレットキーを書く): https://api.omise.co/charges").buildRequest() このPOSTやURLを変えることで他の機能も使えます。 最後に 間違えていたり、簡単に書けたりするところあれば、教えていただきたいです。 また、誰かの参考になれば、幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コードによる制約の付け方(備忘録)

コードによる制約の付け方 ・今回はStackViewで2つのViewを配置する import UIKit final class CodeLayoutViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //Viewを2つ生成 let view1 = UIView() view1.backgroundColor = .red let view2 = UIView() view2.backgroundColor = .blue let stackView = UIStackView(arrangedSubviews: [view1,view2]) //縦に並べる stackView.axis = .vertical //2つのViewを均等に配置 stackView.distribution = .fillEqually //これをfalseにしないといけない stackView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stackView) //StackViewを親のViewの四辺に合わせる制約 [stackView.topAnchor.constraint(equalTo: view.topAnchor), stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor), stackView.leftAnchor.constraint(equalTo: view.leftAnchor), stackView.rightAnchor.constraint(equalTo: view.rightAnchor)].forEach { $0.isActive = true} } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUI で Slack の様なサイドバーを作る

こんな感じです。 import SwiftUI struct ContentView: View { @State private var offset = CGFloat.zero @State private var initialOffset = CGFloat.zero @State private var isCoverPresent = false @State private var isSidebarPresent = false @State private var displayWidth = CGFloat.zero private var sidebarWidth:CGFloat { displayWidth * 0.85 } @State private var animation = Animation.linear(duration: 0.1) func openSidebar() { offset = .zero initialOffset = offset isSidebarPresent = true } func closeSidebar() { offset = -sidebarWidth initialOffset = offset isSidebarPresent = false } var body: some View { GeometryReader { geometry in HStack(spacing: 0) { SidebarView() .frame(width: sidebarWidth) ZStack { Text("右にスワイプでサイドバーを開く") .frame(width: displayWidth, height: geometry.size.height) // VStack の高さを画面いっぱいにして onTapGesture するようにする .background(Color.orange) if isCoverPresent { Color.black .opacity(Double((1 + self.offset / sidebarWidth) * 0.6)) .onTapGesture { withAnimation(animation) { closeSidebar() } } } } } .offset(x: offset) .onAppear { displayWidth = geometry.size.width closeSidebar() } .gesture(DragGesture(minimumDistance: 1) // minumumDistance: 0 にすると、サイドバーやメイン画面の Button が反応しなくなるので 1 を設定 .onChanged{ value in // サイドバーが右に行きすぎていないなら if (self.offset <= CGFloat.zero) { offset = initialOffset + value.translation.width isCoverPresent = true } } .onEnded { value in withAnimation(animation) { if isSidebarPresent { // 左にスワイプしたら if value.location.x < value.startLocation.x - displayWidth * 0.1 { closeSidebar() } else { openSidebar() } } else { // 右にスワイプしたら if value.location.x > value.startLocation.x + displayWidth * 0.2 { openSidebar() } else { closeSidebar() } } } } ) } } } fileprivate struct SidebarView: View { var body: some View { Text("サイドバー") .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .background(Color.blue) .foregroundColor(.white) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む