- 投稿日:2021-03-02T23:30:52+09:00
【Xcode12】Libraryを常時表示させる方法
■はじめに
・この記事ではXcode12.4を使用しています。■方法
Libraryを常時表示するには、
『optionキーを押しながらLibraryボタンクリック』です。連続してObjectsを追加する際などに有用です。
- 投稿日:2021-03-02T17:44:38+09:00
【WidgetKit】WidgetKitのSwiftUIでURLから画像を表示する方法
WidgetKitでは独特なライフサイクルから描写のタイミングに制限があり、
従来の方法である非同期では画像を表示することができません。解決方法
Data(ContentsOf: url)
を使って予め画像データを読み込んでから描画することでこれを解決することができます。サンプル実装
struct SimpleEntry: TimelineEntry { let date: Date let configuration: ConfigurationIntent let url: String func getImageData() -> UIImage { if let imageUrl = URL(string: self.url), let imageData = try? Data(contentsOf: imageUrl), let image = UIImage(data: imageData) { return image } // 読み込めない時の画像とか return .init() } } struct widgetEntryView : View { var entry: Provider.Entry var body: some View { Image(uiImage: entry.getImageData()) .resizable() .aspectRatio(contentMode: .fill) } }この実装でこのように表示することができました。
最後に
非同期が使えないのは結構な罠だと思うので気をつけてくださいねー?
- 投稿日:2021-03-02T13:14:42+09:00
【SwiftUI】sheetメソッドを使ってビューをモーダル表示にする
先日リリースした私のアプリに使用した技術の解説です。
私のアプリはこちら。
sheetメソッドとは
ビューをモーダル表示させるメソッド。下から出てきて画面の一番手前に表示される。
実際の動作
「わかった!」ボタンを押すと下から答え合わせのビューが出てきて、画面の一番手前に表示されているのがわかるかと思います。
また、このシートは上下に動かすことができ、一定の位置まで下げて指を離すと閉じるようになっています。基本の書き方
sheetメソッド.sheet(isPresented: ブール値, content: { 表示させたいビュー })sheetメソッドはさまざまな引数を取りますが、一番シンプルな書き方はこのようになります。
isPresented
がtrueになったとき、content
の{ }内のビューが表示されます。ソースコード
上のサンプルアプリのコードの一部です。
ContentView.swiftimport SwiftUI struct ContentView: View { @State var answer = "" @State var moveAnswer = false //シートを出すためのブール型の変数 var body: some View { VStack{ Text("なぞなぞ") .font(.title) .padding() Text("パンはパンでも白黒のかわいいパンは\nぱ〜んだ?") TextField("こたえを書いてね", text: $answer) .frame(width: 200) .padding() .border(Color.black) // シートを出すトリガーになるボタン Button(action: { moveAnswer = true //シートを出すためのアクション }, label: { Text("わかった!") .padding() .background(Color.green) .foregroundColor(.white) .cornerRadius(10) }) //moveAnswerがtrueになったときに出てくるシート .sheet(isPresented: $moveAnswer, content: { Answer(answer: answer, moveAnswer: $moveAnswer) }) } } }こちらのコードを部分ごとにわけて解説したいと思います。
シートを出すための仕組み
まず、ContentViewのプロパティとしてブール型の変数を用意します。
@State var moveAnswer = false //シートを出すためのブール型の変数アプリ起動時はシートが出ていない状態にしたいため、初期値にfalseを入れています。逆に言えば、初期値をtrueにすればアプリ起動時にシートを出すことができます。
次は、シートを出すトリガーになるボタンです。
// シートを出すトリガーになるボタン Button(action: { moveAnswer = true //シートを出すためのアクション }, label: { Text("わかった!") .padding() .background(Color.green) .foregroundColor(.white) .cornerRadius(10) })ボタンをタップするとmoveAnswerにtrueが代入されます。
そして、sheetメソッドを見ていきます。
.sheet(isPresented: $moveAnswer, content: { Answer(answer: answer, moveAnswer: $moveAnswer) })ボタンのアクションによってmoveAnswerにtrueが入ると
isPresented
がtrueになり、content
のAnswerビューが表示されます。今回、AnswerビューはAnswer.swiftという別のファイルを作って書きました。そちらのビューも見てみましょう。
今回シートに表示したビュー
Answer.swiftimport SwiftUI struct Answer: View { let answer: String //前の画面のなぞなぞの答え @Binding var moveAnswer: Bool //前の画面のmoveAnswerを反映させるための変数 var body: some View { VStack{ //なぞなぞの答えが正解かどうかで表示を変える if answer == "パンダ" { Text("せいかい!!\nすごい!天才だ!") .font(.title) Image("correct") }else{ Text("ちがうよ。もういちどもんだいをよく読んでみよう。") .font(.title) Image("fault") } //シートを閉じるためのトリガーになるボタン Button(action: { moveAnswer = false //シートを閉じるためのアクション }, label: { Text("もどる") .font(.title) .padding() }) } } }動画内でもやっていたように、わざわざボタンを作らなくてもシートを閉じる操作はできますが、ボタンがあった方が便利な場面もあるかと思います。このボタンの作り方について解説したいと思います。
シートを閉じるためのボタンの作り方
シートを閉じるためには、ContentViewのmoveAnswerがfalseになる必要があります。そのため、まずはContentViewのmoveAnswerをAnswerビューに反映させます。
@Binding var moveAnswer: Bool //前の画面のmoveAnswerを反映させるための変数
@Binding
をつけることで、このmoveAnswerに入れたブール値の状態を共有しています。つまり、AnswerのmoveAnswerがfalseになると、ContentViewのmoveAnswerもfalseに変わるようにしています。そしてこちらがシートを閉じるためのトリガーとなるボタンです。
//シートを閉じるためのトリガーになるボタン Button(action: { moveAnswer = false //シートを閉じるためのアクション }, label: { Text("もどる") .font(.title) .padding() })このボタンを押すことでmoveAnswerにfalseが入り、シートを閉じることができます。
- 投稿日:2021-03-02T12:17:03+09:00
UnityでiOSのUIColorPickerViewControllerを使うPlugin
はじめに
iOS14から導入されたUIColorPickerViewControllerをUnityから使いたかったのでPluginを書きました。
レポジトリ
Unitypackage
UIColorPickerManager.unitypackage
Sample
public void Show(){ Color currentColor = Color.white; UIColorPickerManager.Show(currentColor, OnSelectColor, OnFinish); } // call when color selected. void OnSelectColor(Color selectedColor){ // ... } // call UIColorPickerViewController finished. void OnFinish(){ }UIColorPickerManager.Show
UIColorPickerManager.Show
にはいくつかのオーバーライドがあります。選択された色をColorオブジェクトで受け取る
void Show ( Color currentColor, OnColorSelectedCallback onColorSelectedCallback, // Colorオブジェクトを受け取るコールバック関数 OnFinishCallback onFinishCallback)選択された色をRGBAで受け取る場合
void Show ( Color currentColor, OnRGBColorSelectedCallback onRGBColorSelectedCallback, // RGBAを受け取るコールバック関数 OnFinishCallback onFinishCallback)選択された色をColorオブジェクトで受け取り、iOS14未満の時の処理を必要とする場合
void Show ( Color currentColor, OnColorSelectedCallback onColorSelectedCallback, OnFinishCallback onFinishCallback, OnEarlierIOSVersionsCallback onEarlierIOSVersionsCallback)選択された色をRGBAで受け取り、iOS14未満の時の処理を必要とする場合
void Show ( Color currentColor, OnRGBColorSelectedCallback onRGBColorSelectedCallback, OnFinishCallback onFinishCallback, OnEarlierIOSVersionsCallback onEarlierIOSVersionsCallback)参考:上記のコードで使われているdelegateの定義
// - colorPickerViewControllerDidSelectColor: 用コールバック public delegate void OnColorSelectedCallback(Color color); public delegate void OnRGBColorSelectedCallback (float r, float g, float b, float a); // - colorPickerViewControllerDidFinish: 用コールバック public delegate void OnFinishCallback(); // @available(iOS 14.0, *) がfalseの時用コールバック public delegate void OnEarlierIOSVersionsCallback();ライセンス
ライセンスはMITです。
補足
いないかもしれませんが、ソースコードを読みたいという方がいれば、
先に、 [Unity]ネイティブプラグインからコールバック関数を呼ぶ[iOS]
という記事を読むことをお勧めします。このプラグインは、その記事の応用になっています。
- 投稿日:2021-03-02T11:13:36+09:00
[Swift5]UITextViewのキーボードをタップで閉じる方法(シンプル)
- 投稿日:2021-03-02T10:09:38+09:00
iOS 14 / watchOS 7 HealthKit 変更点
iOS 14 / watchOS 7 から HealthKit に症状を記録するデータタイプや、歩行に関するより詳細なデータタイプが追加されるなどの変更がありました。
ECG 関連のアップデートが中心な感じですが、2021.1 の watchOS 7.3 アップデートで日本でも ECG が使えるようになったのでまとめてみました。
心拍に関するデータタイプ HKElectrocardiogramType の追加
wathOS 7.3 (iOS 14.4) より、日本でも Apple Watch で心電図(ECG)が使えるようになりました。アメリカので二年遅れてついに日本で使えるようになりました。Apple Watch S4,5,6 で使用可能です。
不規則な心拍(心房細動(AFib)の兆候がある不規則な心拍リズム)の通知を受け取ることができるようになり、心電図 Apple Watch アプリを使うと、心房細動、洞調律、低心拍数、高心拍数、判定不能のいずれかに分類することができるようになっています。
HKElectrocardiogramType
この有無が記録されている HKElectrocardiogram をチェックすることが iOS14/watchOS7 SDK からできるようになりました。
let healthStore = HKHealthStore() let healthTypes = Set([ HKCategoryType.electrocardiogramType() ]) healthStore.requestAuthorization(toShare: nil, read: healthTypes) { (success, error) in // ... }https://developer.apple.com/documentation/healthkit/hkelectrocardiogram?changes=latest_major
HKElectrocardiogram を取得するには HKSampleQuery で取得します。
let ecgType = HKObjectType.electrocardiogramType() let ecgQuery = HKSampleQuery(sampleType: ecgType, predicate: nil, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, samples, error) in if let error = error { fatalError(error.localizedDescription) } guard let ecgSamples = samples as? [HKElectrocardiogram] else { fatalError(String(describing: samples)) } for sample in ecgSamples { print(sample) } } healthStore.execute(ecgQuery)HKElectrocardiogramQuery に HKElectrocardiogram オブジェクトを渡して詳細な測定値を取得できます。
let voltageQuery = HKElectrocardiogramQuery(ecgSample) { (query, result) in switch(result) { case .measurement(let measurement): if let voltageQuantity = measurement.quantity(for: .appleWatchSimilarToLeadI) { print(voltageQuantity) } case .done: print("done") case .error(let error): fatalError(error.localizedDescription) } } healthStore.execute(voltageQuery)-4.39537 mcV 1.91129 mcV 8.0672 mcV 14.0773 mcV ... 省略HealthKit で症状を記録することができるデータタイプの追加
iOS 13.6 / watchOS 7 以降から症状についての記録のためのデータタイプが追加されています。
iOS 14 でもさらに追加され、「寒気」「鼻水が出る」「咳」「腰の痛み」「物忘れ」「頭痛」「胸の痛み」「ニキビ」など、ほか含め合計 39 種類の症状が発生したことを記録する HealthKit 対応のログアプリなどが作れるようになりました。
全て HKCategoryTypeIdentifier のデータタイプになっているので、他の HKCategoryType のサンプルのように取り扱うことができるようになっています。
https://developer.apple.com/documentation/healthkit/data_types/symptom_type_identifiers
歩行速度や歩幅、階段の昇降速度のサンプルデータ型が追加
歩くことに関するいくつかのサンプルデータが追加されました。全て HKQuantityType 型のサンプルデータになります。
6 分間歩行の推定データが取得できるようになりました。
static let sixMinuteWalkTestDistance: HKQuantityTypeIdentifier6 分間歩行とは何か、近畿中央呼吸器センターさんのホームページに記載されている内容を引用します。
6 分間歩行試験とは、6 分間平地を歩いていただくことによって、肺や心臓の病気が日常生活の労作にどの程度障害を及ぼしているのか調べるための検査です。https://kcmc.hosp.go.jp/shinryo/hokou.html
歩行の速度や歩幅を示すデータ、さらに歩幅が左右で違う割合だとか、歩いている時に両足が地面についている瞬間の割合だとか、歩くことに関する複雑なデータが取得できるようになりました。
static let walkingSpeed: HKQuantityTypeIdentifier static let walkingStepLength: HKQuantityTypeIdentifier static let walkingAsymmetryPercentage: HKQuantityTypeIdentifier static let walkingDoubleSupportPercentage: HKQuantityTypeIdentifier階段登り下りの速度のデータが取得できるようになりました。
static let stairAscentSpeed: HKQuantityTypeIdentifier static let stairDescentSpeed: HKQuantityTypeIdentifier「手洗いした」データタイプが追加
watchOS 7 / Apple Watch S4,5,6 で、手洗いをマイクとモーションセンサーを使って自動で検知するようになりました。そのログデータを取り出すことができるようになります。
static let handwashingEvent: HKCategoryTypeIdentifierHKSampleQuery で他のデータと同じようにサンプルを取り出すことができます。
SwiftUI で昨日今日の handwashingEvent を取得する例。他の HKCategoryType のデータタイプも同様の書き方で取得することができます。
import SwiftUI import HealthKit var healthStore: HKHealthStore! struct ContentView: View { var body: some View { Button(action: { checkHealthKit() }, label: { Text("Button") }) } func checkHealthKit() { healthStore = HKHealthStore() let healthTypes = Set([ HKCategoryType.categoryType(forIdentifier: .handwashingEvent)! ]) healthStore.requestAuthorization(toShare: nil, read: healthTypes) { (success, error) in fetchHandWashing() } } func fetchHandWashing() { let now = Date() let calendar = Calendar.current let yesterday = calendar.date(byAdding: .day, value: -1, to: calendar.startOfDay(for: now)) let predicate = HKQuery.predicateForSamples(withStart: yesterday, end: now, options: []) let sortDescriptor = [NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true)] let washingEvent = HKCategoryType.categoryType(forIdentifier: .handwashingEvent)! let query = HKSampleQuery(sampleType: washingEvent, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: sortDescriptor) { (query, results, error) in guard error == nil else { print("error"); return } let format = DateFormatter() format.dateFormat = "yyyy-MM-dd HH:mm:ss" format.timeZone = TimeZone(identifier: "Asia/Tokyo") print("\(format.string(from: yesterday!)) - \(format.string(from: now)) result ?:") if let tmpResults = results as? [HKCategorySample] { tmpResults.forEach { (sample) in print(sample) } } } healthStore.execute(query) } }ヘッドホンから有害とされる音量を受けた時の記録のデータタイプの追加
ヘッドホンからの音、うるさすぎるよ!っていうものです。
static let headphoneAudioExposureEvent: HKCategoryTypeIdentifierこれに合わせて、環境音がうるさすぎるの時のデータタイプ名はカテゴリを正しく表記する名称に変更になりました。
~~static let audioExposureEvent: HKCategoryTypeIdentifier~~ ↓ static let environmentalAudioExposureEvent: HKCategoryTypeIdentifierワークアウトタイプの追加
HKWorkoutActivityTypeCardioDance HKWorkoutActivityTypeSocialDance HKWorkoutActivityTypePickleball HKWorkoutActivityTypeCooldownCardio Dance は YouTube とかで検索するといっぱい出てきますね。
Social Dance はフォークダンスなどパートナーとか何人かでやるダンス。
Pickle Ball っていう新しいアメリカで流行り始めている?スポーツが追加されたようです。歴史的には 50 年ぐらいあるらしい。 https://www.playpickleball.com
Cooldown は運動前後のクールダウン的な運動やストレッチを明示的にするための定数ですね。Apple Fitness+ サービス(日本では提供されていませんが)のメニューに対応した定数が今後も増えそうな気がします。
(iOS 14.3 / watchOS 7.3 以降)妊娠出産に関するヘルスケアデータタイプの追加
妊娠出産関連のカテゴリタイプが追加されたので、それに対応するデータタイプが追加されています。
static let contraceptive: HKCategoryTypeIdentifier // 避妊薬 static let lactation: HKCategoryTypeIdentifier // 授乳 static let pregnancy: HKCategoryTypeIdentifier // 妊娠(iOS 14.3/watchOS 7.2 以降) HKSample.hashUndeterminedDuration の追加
var hasUndeterminedDuration: Bool { get }サンプルの endDate プロパティが distantFuture の場合 true になります。
distantFuture とは「遠い未来の日付」で、イベントの終了待ちをするまでのテンポラリ値として入れておくなどの使い方をしたりします。
print(Date.distantFuture) // 4001-01-01 00:00:00 +0000おわり
HealthKit を解説している拙著「HealthKit Book for Beginners」にも本記事を追加しましてアップデート(v3.0)しましたので、購入していただいた方は PDF 版再ダウンロードおねがいしますー。(製本版は v1.0 のままです)
- 投稿日:2021-03-02T10:07:56+09:00
TodoAPPでRxSwift入門[part2]
概要
最近RxSwiftを勉強し始めて現在理解していることを備忘録として残せたらいいなと思い記事にします。
そもそもRxSwiftのRxとはRx(Reactive X)とは、「オブザーバパターン」「イテレータパターン」「関数型プログラミング」の概念を実装している拡張ライブラリです。
Rxを導入するメリットは、「値の変化を検知できる」「非同期の処理を簡潔に書ける」ということに尽きると思います。 値の変化というのは変数値の変化やUIの変化も含まれます。 例えばボタンをタッチする、という動作もボタンのステータスが変わったと捉えることができRxを使って記述することができます。とのことです。
詳しくは以下のサイトを参照してください。
入門!RxSwift
RxSwiftについてようやく理解できてきたのでまとめることにした(1)今回はPart2になります。
前回の記事はこちら
TodoAPPでRxSwift入門[part1]画面構成
画面はこんな感じにします。
タイトルを入力するためのUITextField
と詳細を入力するためのUITextView
とTodoを登録するためのUIButton
をスタックビューに入れてあげてます。画面上部の
Welcome to Simple Todo App
はただのデザインで入れてみただけなのでなくても大丈夫です。
下部のShow Todo List
は登録したTodoを見るためのボタンになっています。UIの配置が面倒な人はこの記事が完結した時にgithubにあげるのでそこのStoryboardからコピペしてください。
AddTodoViewModel
前回の記事の最後に予告した
ViewModel
の作成に移ります。
そもそもViewModel
とは、なんでもかんでもViewControllerに書いちゃったらViewControllerがめっちゃ長くなって見にくいしあまりよろしくないよねということからMVVMというアーキテクチャが編み出されてそれのVM(ViewModel)の部分に当たるものです。
詳しいことはググってください。では早速コードのほうを書いていきましょう。
AddTodoViewModel.swiftimport Foundation import RxCocoa import RxSwift protocol AddTodoViewPresentable { typealias Input = ( titleText: Driver<String>, detailText: Driver<String> ) typealias Output = ( isValid: Driver<Bool>, () ) var input: AddTodoViewPresentable.Input { get } var output: AddTodoViewPresentable.Output { get } }これで全部ではないですがとりあえずここまでで一旦解説を挟みます。
まずprotocol
?と思われた方もいるかもしれないですがこれはプログラムを疎結合にするためです。疎結合とは?の方はを参照してください。
typealiasで
Input
(入力を受けとる)とOutput
(受け取った値を変換したりして返す)を作っています。ちなみにtapple
は要素が一つだけだとエラーになるのでOutput
にはisValid
と()
にしています。
次にDriver
の説明をします。
Driverとは
・エラーを流さない
・メインスレッドでの通知が保証される
・shareReplayLatestWhileConnectedを使ったCold-Hot 変換
の特徴を持ったRxSwift(RxCocoa)独自のものらしいです。今度はAddViewModelの中身です。
AddTodoViewModel.swiftclass AddTodoViewModel: AddTodoViewPresentable { var input: AddTodoViewPresentable.Input var output: AddTodoViewPresentable.Output var storeManager: StoreManager init(input: AddTodoViewPresentable.Input, storeManager: StoreManager) { self.input = input self.output = AddTodoViewModel.output(input: self.input) self.storeManager = storeManager } } private extension AddTodoViewModel { static func output(input: AddTodoViewPresentable.Input) -> AddTodoViewPresentable.Output { let titleObservable = input.titleText.asObservable() let detailObservable = input.detailText.asObservable() let isValid = Observable.combineLatest(titleObservable, detailObservable) { (title, detail) -> Bool in return !title.isEmpty && !Validator.removeSpaceAndNewLine(text: detail).isEmpty }.asDriver(onErrorJustReturn: false) return ( isValid: isValid, () ) } } extension AddTodoViewModel { func insertTodoToFireStore(title: String, detail: String) { storeManager.insertTodoToFireStore(title: title, detail: detail) } }ここはそこまで説明いらないかなと思いますが、 ViewModelを先程のPresentableに準拠させていないとエラーになるので
fix
でもおしておいてください。
output
を初期化するためのoutput関数ですが外部から利用されないようにするためと読みやすくするためにprivate extension
で拡張します。
また、static
がついているのは、ついていないと変数のoutput
が初期化されていないのにそんなの使えないよと怒られるのでこうしています。
init
でクロージャでもいいとは思いますがそれだとinit
が長くなってしまうので今のところこれがベストかと思いこうしています。
output関数
の中を少し解説します。
inputで受け取った値をasObservable()
でObservableに変えています。そして
combineLatest(observable1, observable2)
は(違う型でも可の)直近の最新値同士を組み合わせたイベントを作ります。
引数に指定した値のどちらかがが変化すれば{}ないの処理を実行する感じですかね?
あと、さらっと
Validator
というのが出ていますがこれはdetail
が空白や改行のみだとfalse
を返します。
コードはこちらです。Validator.swiftimport Foundation class Validator { static func removeSpaceAndNewLine(text: String) -> String { var removeText = text.trimmingCharacters(in: .init(charactersIn: " ")) removeText = removeText.trimmingCharacters(in: .init(charactersIn: " ")) removeText = removeText.trimmingCharacters(in: .init(charactersIn: "\n")) return removeText } }Stringを返していますがBoolを返せばよかったと思います。
まとめ
正直あまり理解できていないところもあり、まだまだ勉強しないといけないことだらけで泣きそうです。
疎結合なプログラムも連鎖的なバグを防ぐためなのはなんとなく理解できていますが、その恩恵を得られるほどのプログラムを書いた経験がないのでパッとしないです。
もっと勉強して就職して恩恵を感じたいですね。
次回はViewControllerになります。
- 投稿日:2021-03-02T06:22:12+09:00
【iOS】LiDARセンサーを用いたサンプルコード集を公開しました!
iOSのLiDARセンサーを用いたサンプルコード集をGitHubに公開したので紹介します。
本記事の執筆時点でGitHubで91スターを頂いています!TokyoYoshida/ExampleOfiOSLiDAR
?よさそうだと思った方はスターをお願いします⭐例えば、こんなサンプルが入っています。
The GitHub repository of sample code using iOS LiDAR sensors, including 3D scanning, got 40 stars in a day!
— TokyoYoshida (@jugemjugemjugem) February 19, 2021
iOSのLiDARセンサーを用いたサンプルコードのGitHubリポジトリが1日で40スターも取った!
The repository is here.https://t.co/FHASFV4Zfs#iOS #LiDAR #AR #ARKit pic.twitter.com/lfCq1T9yBgiPad Pro/iPhone 12 ProにLiDARが搭載されたとき、いつかは現実世界をスキャンしてみたいと思っていたかたもいらっしゃると思いますが、このサンプルを使えば簡単に実現できてしまいます。
ビルド方法
XCodeでExampleOfiOSLiDAR.xcodeprojを開いてビルドして、iPhone 12 Pro/Pro MAXかLiDARセンサーを搭載したiPad Proにインストールします。
サンプル一覧
Depth Map
深度情報を画像にしたものです。スクリーンショットは静止画ですがリアルタイムに動作します。
Confidence Map
深度情報の信頼度を画像にしたものです。リアルタイムに動作します。
Collision
現実世界に、仮想的なオブジェクトがぶつかったときの判定をします。
Export
現実世界のオブジェクトをスキャンして、.objファイルにエクスポートします。
エクスポートしたファイルはXcode,Macのプレビューなどで閲覧したり、Blenderで編集できます。Scan with Texture
現実世界のオブジェクトをカラースキャンします。こちらは、サンプルアプリ内でのみ閲覧できます。
最後に
LiDARセンサーはなかなかおもしろい技術なので、これからも追っていきたいと思っています。作品やサンプルができたら、Twitterで発信していきますのでフォローをお願いします?
https://twitter.com/jugemjugemjugemNote こちらはiOS開発、AR、機械学習などについては発信しています。
https://note.com/tokyoyoshida
- 投稿日:2021-03-02T00:16:41+09:00
Swiftでカメラキャプチャーするための最小コード
準備
Info.plist
に以下の設定を追加。<key>NSCameraUsageDescription</key> <string>[カメラ使用に関する説明]</string>コード
import UIKit import AVFoundation class CaptureViewController: UIViewController { private let previewLayer: AVCaptureVideoPreviewLayer = { let previewLayer = AVCaptureVideoPreviewLayer() previewLayer.videoGravity = .resizeAspectFill return previewLayer }() init() { super.init(nibName: nil, bundle: nil) let session = AVCaptureSession() previewLayer.session = session if let device = AVCaptureDevice.default(for: .video), let input = try? AVCaptureDeviceInput(device: device), session.canAddInput(input) { session.addInput(input) } let output = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: .global()) if session.canAddOutput(output) { session.addOutput(output) output.connection(with: .video)?.videoOrientation = .portrait } session.startRunning() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.layer.addSublayer(previewLayer) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() previewLayer.frame = CGRect(origin: .zero, size: view.bounds.size) } } extension CaptureViewController: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { // sampleBufferを処理する } }環境
Xcode 12.2
Apple Swift version 5.3.1 (swiftlang-1200.0.41 clang-1200.0.32.8) Target: x86_64-apple-darwin19.6.0