- 投稿日:2020-07-21T22:56:29+09:00
サーバサイド Swift フレームワーク Vapor の開発環境セットアップ方法
はじめに
私は普段iOSフロントをSwiftで書いているため、XcodeやSwift等の環境がある程度ありましたので、
Xcodeの導入部分等は省略しております。環境
- macOS Catalina 10.15.5
- Xcode 11.5
- Swift 5.2.4
Vapor インストール
なにはともあれVaporを導入
homebrewを導入をお願いします。brew tap vapor/tap brew install vapor/tap/vaporVapor プロジェクトを作成
私の場合はAPI開発がしたかったのでテンプレートオプションでAPIモードとしてプロジェクト作成しました。
vapor new Hello --template=apiいくつかイニシャライズ時の質問がありますので設定してきます。
Would you like to use Fluent?
Fluent とはモデルの作成、削除、読み取り、更新やクエリの発行などを行ってくれるDB周りの便利パッケージのようです。
y
を入力して回答していきます。
Which database would you like to use?
どのDB使うか聞かれるので
1
の Postgres を選択します。(2020/07/21 現在 MySQL、MONGO DB 等はbeta版のようでした)作成されたプロジェクトのディレクトリに移動します。
vapor new HelloXcodeプロジェクトを作成します
vapor xcode上記でXcodeが自動的に立ち上がるのでSwiftPMのインストールが終わりましたら、
Sheme
をMy Mac
に設定して(おそらく自動的に設定されている)Cmd + R
or▶︎ボタン
で実行します。
http://localhost:8080 にアクセスすると下記が表示されると思います。以上で初期の開発環境セットアップ完了です。
参考
https://docs.vapor.codes/2.0/getting-started/install-on-macos/
https://docs.vapor.codes/3.0/getting-started/hello-world/
- 投稿日:2020-07-21T19:24:52+09:00
UIViewControllerでpresentすると循環参照する?!
結論
UIViewControllerでpresentすると循環参照するんですね。
windowのrootViewControllerを差し替える時とかに注意が必要ですね。サンプル
playgroundにて下記のコードで検証
import Foundation import UIKit import PlaygroundSupport class VC: UIViewController { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) print("init") } required init?(coder: NSCoder) { super.init(coder: coder) print("init2") } deinit { print("deinitialized") } } var p: VC? = VC() PlaygroundPage.current.liveView = p var p2: VC? = VC() p?.present(p2!, animated: true, completion: nil) _ = p?.presentedViewController p = nil _ = p2 _ = p2?.presentingViewControllerinit init
- 投稿日:2020-07-21T17:51:58+09:00
Swift歴半年、初めてのアプリ公開までの道のり
はじめに
タイトルの通りです。少し大袈裟に書いたのは、自分にとってアプリを公開するということは、実務でバリバリSwift書いてる人や一部の秀才たちにのみ許された聖域のように見えていて、なかなか踏み出せなかったからです。(つまりただイモってただけ)
でも、やってみたら案外あっさり承認されたのでもっと早くやってればよかったとちょっと後悔しています。
なので、同じように悩んでいる人がいたら、とりあえずさっさとApple Developer Accountにお金払ってアプリを公開しましょう!って背中を押したいのでこの記事を書いてます。公開したアプリ 【復習サイクル】
機能的にはかなり薄っぺらいアプリです...
流れ
流れとは言ってもただ参考にしたリンクの羅列になりそう。せめて体験談を踏まえながら書いていきます。
まずはこちらの1〜4を参考に下準備。ここでは特に何も困りませんでした。丁寧でとてもわかりやすい記事です、ありがとうございます。
字を読んで理解するのが苦手なので、まずはこちらのyoutubeを見て流れを掴む。英語ですが、とてもわかりやすくしゃぺってくれてます。
そしてApp Store Connect→マイAppにて、実際に必要事項入力していきます。基本的に全ての項目を入力していく感じです。僕が一番困ったのが電話番号入力。こちらを参考にして解決。"+81"というのが抜けていてずっとエラーが消えずめっちゃイライラしてました笑 それからスクリーンショットにも苦労しました。サイズが明確に決められていて、該当のスクショを選択→ツール→サイズを調整、鍵マークを外し指定のピクセルで入力します。
初めてこれをやったら、元の画像がめちゃくちゃ拡大されてびっくりしますが、それで問題ありません。ここで無駄に試行錯誤してました...個人情報の取り扱いについてはこちらを使うと自動で取り扱いに関するリンクを作ることができます。すごい。これついて、何かトラブル等あった際の責任は一切取れませんので、ご自身でしっかり判断されてください。
アプリのアイコンはFigmaでそれっぽいの作って、それをスクショして、それをこちらのサイトに投げれば自動で全部やってくれます!
アプリの審査してくれる方々はおそらく外国人なので、審査用の機能メモ欄は英語で書きました。Thank you in advanceと最後につけてちょっといい人を演じてみたりもしました笑
最後に
自分は24時間くらいしてokのメールをいただきました!これからどんどん公開していくぞ!そして早く転職活動終わらせたい...
- 投稿日:2020-07-21T11:56:24+09:00
iOSアプリ開発で参考にしたiOSエンジニア YouTuber
はじめに
本格的にiOSアプリを開発してから約2年が経ちましたが、始めた当初から独学しています。というのもインターネット上に情報が溢れているのでネイティブアプリの構成やデバッグ方法、作りたい機能は大体検索すれば出てきます。
参考にしたサービス:
・YouTube
・StackOverflow
・Medium
・Qiita
・Teratail
・Udemy始めた当初は動画で見れるYouTubeは特に参考になりましたので、iOSエンジニアYouTuber(英語)を紹介します。
iOSエンジニアYouTuber
・ Let's build that app(私のメンター)
https://www.youtube.com/channel/UCuP2vJ6kRutQBfRmdcI92mA
アジア系アメリカ人のブライアン。この人がいなかったらiOSアプリ開発出来ていなかったと思います。
iOSプログラミングの基本、応用、デザインはほぼから彼から学びました。
このチャンネルは『このアプリを作ろう』的なシリーズ系をたくさん載せています。例えば、『Firebaseを使ってチャットアプリを作ってみよう』、『YouTubeを作ってみよう』、『Twitterを作ってみよう』などなど。
そのほかにもアルゴリズム系の動画を載せています。・Code with Chris
https://www.youtube.com/user/CodeWithChris
ビギナー用の動画がたくさんあります。
1年前に公開された『How to make an app for Beginners』は243万回も再生されています。
ほかにもサードパーティーライブラリ(SDWEBIMAGEやSVProgressHUD)の使い方も解説しています。・Sean Allen
https://www.youtube.com/channel/UCbTw29mcP12YlTt1EpUaVJw
基本的なSwift(ViewControllerの解説、ClassやStructの使い方、if文やswitch文の使い方、enumの使い方)の構造などを説明しています。・ArchetApp
https://www.youtube.com/user/Archetapp
サードパーティーサービス(Firebase, Stripe, Realm)を使ったプロジェクト作成動画を載せています。最後に
YouTubeは無料で見れる上、内容の濃いコンテンツが多いのでおすすめです。
技術的な面を解説している日本人iOSエンジニアYouTuberの方が見つからなかったため、外国人YouTuberを参考にしています。
- 投稿日:2020-07-21T06:31:52+09:00
CreateMLでイケメン分類器をつくる。かんたんモバイル・ディープラーニング。
ディープラーニングをかんたんにできるCreateML
数学などの専門知識は不要です。
AppleのツールCreateMLで、あなたも簡単にディープラーニングのモデルを学習させることができます。
そして、そのモデルはiOSアプリでつかうことができます。データをあつめましょう
トレーニング・データ
イケメンの画像100枚と、イケメンではない画像100枚をあつめました。
そして、それらをフォルダわけしました。
イケメンフォルダ
イケメンじゃないフォルダ
テスティング・データ
トレーニング・データと同じフォルダ構成で、テスティング・データのフォルダもつくります。
イケメン、イケメンじゃない、10枚ずつです。
トレーニング・データに含まれない画像を用意する必要があります。
分類の子フォルダ名(この場合、「ikemen」と「ikemennot」)はトレーニング・データと同じであることが要求されます。
CreateMLを起動
XcodeをControllキーを押しながらクリック、そしてOpenDeveloperTools、CreateMLを選択。
CreateMLのメニューからImage Classification(画像分類)を選びます。
それから、好きなプロジェクト名を入力します。CreatMLで画像分類モデルを学習させる
Training DataとTesting Dataの+ボタンをクリックして、用意したフォルダを指定します。
テスティング・データでテストした結果を表示してくれます。
イケメンのPrecision89%、Recall80%。
モデルがイケメンと予測した画像の89%が正解。
イケメン画像の80%がイケメンと予測されました。Previewを選択してオリジナル画像をドロップすると、その画像でテストできます。
99%の確信でイケメンではない、と予測されました。モデルをiOSモバイルアプリでつかう
mlmodelをゲット
Outputタブを選択すると、学習したモデルが表示されます。
これはCoreMLモデル形式です。
Getボタンを押して、モデルを保存します。
保存されたモデルを、Xcodeプロジェクトにドラッグ&ドロップします。
Visionフレームワークでモデルをつかう
Visionフレームワークでmlmodelを手軽に使えます。
VNCoreMLRequestで、CoreMLモデルの推論リクエストをつくります。ViewController.swiftfunc setupVision() -> NSError? { // Setup Vision parts let error: NSError! = nil guard let modelURL = Bundle.main.url(forResource: "ikemenclasifier 1", withExtension: "mlmodelc") else { return NSError(domain: "VisionObjectRecognitionViewController", code: -1, userInfo: [NSLocalizedDescriptionKey: "Model file is missing"]) } do { let visionModel = try VNCoreMLModel(for: MLModel(contentsOf: modelURL)) let objectRecognition = VNCoreMLRequest(model: visionModel, completionHandler: { (request, error) in DispatchQueue.main.async(execute: { // perform all the UI updates on the main queue if let results = request.results { self.mlCompletion(results) } }) }) self.mlRequest = [objectRecognition] } catch let error as NSError { print("Model loading went wrong: \(error)") } return error }VNImageRequestHandlerを使って、用意した画像でCoreMLリクエストを実行します。
ViewController.swiftlet imageRequestHandler = VNImageRequestHandler(ciImage: image, orientation: exifOrientation, options: [:]) do { try imageRequestHandler.perform(self.mlRequest) } catch { print(error) }リクエストは結果をVNClassificationObservationとして返します。
identifierは結果の分類名です。それは、データのフォルダ名と同じになります。この場合、「ikemen」か「ikemennot」です。
confidenceはパーセンテージの確信度です。ViewController.swiftfunc mlCompletion(_ results: [Any]) { guard let observation = results.first as? VNClassificationObservation else { print("its not ml observation") return } print(observation.identifier,observation.confidence) if observation.identifier == "ikemen" { resultLabel.text = "イケメン\n\(floor(observation.confidence * 100))" ikemenCount += 1 } else { resultLabel.text = "イケメンではない\n\(floor(observation.confidence * 100))" } }実際のアプリはこちら
GitHubにアプリ置いときます。
https://github.com/john-rocky/HandsomeClassifierぼくのTwitterをフォローしてください。お願いします。
https://twitter.com/JackdeS11お仕事のご依頼をこのメールにお願いします。
rockyshikoku@gmail.comあと、Looks Good For Me(わるくないね)、押してください。
ここです ↓
チャオ?!
- 投稿日:2020-07-21T04:20:44+09:00
YUV(YCbCr)のCVPixelBufferをBGRAに高速に変換する
ARKitのcapturedImageをmediapipeで利用する時など、CVPixelBufferのpixelFormatを変換する必要があることがあります。
以前の記事ではvImageを利用しましたが、vImageはCPUでの計算に最適化されており映像処理などには向かないものでした。
https://qiita.com/noppefoxwolf/items/b12d56e052664a21d8b6そこで、GPUを利用してYCbCrをBGRAに変換するライブラリを作りました。Xcode12のSwiftPMで簡単に導入することができます。
https://github.com/noppefoxwolf/BlueDress使い方
簡単に使うことができます。
import BlueDress let converter = YCbCrImageBufferConverter() let bgraBuffer = try converter.convertToBGRA(imageBuffer: imageBuffer)変換の流れ
実際は変換ではなく、新規に新しいBGRAのPixelBufferを作ってそこにYCbCrを焼いています。
YCbCrのPixelBufferは、内部に2枚の画像を持っておりそれぞれ
- Y: 輝度
- CbCr 青と赤の色差
をサイズ違いでもっています。
YCbCrは以下の計算式で変換することが出来るので、Metalシェーダを使ってこの計算を行うというわけです。R = 1.164(Y-16) + 1.596(Cr-128) G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128) B = 1.164(Y-16) + 2.018(Cb-128)実装で詰まりがちなところ
各PlaneのPixelFormat
YCbCrから2枚のPlaneを取り出す際に、最初はそれぞれをBGRAとして取り出していたのですがこれは間違いでそれぞれ
- Y: r8Unorm
- CbCr: rg8Unorm
で取り出す必要があります。
よく考えれば当然なのですが、ARKitのMetalテンプレートを読んで気がつきました。CVPixelBufferとMTLTextureの関係
MTLTextureはあくまでCVPixelBufferの参照を持つ概念なので、MTLTextureに対して行った描画処理は特に取り出す必要はなく、MTLTextureのソースとして渡したCVPixelBufferに適用されます。
MTLTextureが-6660エラーで作れない
最終描画先の空のMTLTextureを作りたくて、そのソースとなる空のCVPixelBufferを自前で作っていたのですがどうもエラーでMTLTextureが作れませんでした。
MTLTextureを作る場合は、CVPixelBufferを生成する時にkCVPixelBufferMetalCompatibilityKey:true
を与えるのを忘れないようにしましょう。Bundle.moduleが生成されない
これはXcode12が正式リリースされたら追記します。
- 投稿日:2020-07-21T01:27:44+09:00
自分でレイアウトを組んだ時の注意
UIをコードで組んだ時に
translatesAutoresizingMaskIntoConstraints = falseを入れてあげないと、自分が組んだUIレイアウトが優先されない。
自分の場合
レイアウトを組む際は、関数を定義してあげて使ってます。
func anchor(top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, paddingTop: CGFloat = 0, paddingLeft: CGFloat = 0, paddingBottom: CGFloat = 0, paddingRight: CGFloat = 0, width: CGFloat? = nil, height: CGFloat? = nil) { translatesAutoresizingMaskIntoConstraints = falseこんな風に、書いてます。
これで
anchor()
を呼び出して使ってます。使用例
let titleLabel : UILabel = { let label = UILabel() label.text = "hoge" label.font = UIFont.boldSystemFont(ofSize: 14) return label }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(titleLabel) titleLabel.anchor(top: view.safeAreaLayoutGuide.topAnchor, right: view.safeAreaLayoutGuide.rightAnchor, paddingTop: 50, paddingRight: 147, width: 100, height: 56) titleLabel.layer.cornerRadius = 56/2 }みたいな感じで書いてあげればおそらくかけるのかなと思います。
こんな感じにできます。
レイアウトのコードは
https://github.com/tiking76/chatapp/blob/master/chatApp/Utiles/Extentions.swift
に置いてあります。
もっと詳しく知りたいよ!!ってひと
↓のスライドをみてね!
- 投稿日:2020-07-21T01:27:44+09:00
Swiftで自分でレイアウトを組んだ時の注意
UIをコードで組んだ時に
translatesAutoresizingMaskIntoConstraints = falseを入れてあげないと、自分が組んだUIレイアウトが優先されない。
自分の場合
レイアウトを組む際は、関数を定義してあげて使ってます。
func anchor(top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, paddingTop: CGFloat = 0, paddingLeft: CGFloat = 0, paddingBottom: CGFloat = 0, paddingRight: CGFloat = 0, width: CGFloat? = nil, height: CGFloat? = nil) { translatesAutoresizingMaskIntoConstraints = falseこんな風に、書いてます。
これで
anchor()
を呼び出して使ってます。使用例
let titleLabel : UILabel = { let label = UILabel() label.text = "hoge" label.font = UIFont.boldSystemFont(ofSize: 14) return label }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(titleLabel) titleLabel.anchor(top: view.safeAreaLayoutGuide.topAnchor, right: view.safeAreaLayoutGuide.rightAnchor, paddingTop: 50, paddingRight: 147, width: 100, height: 56) titleLabel.layer.cornerRadius = 56/2 }みたいな感じで書いてあげればおそらくかけるのかなと思います。
こんな感じにできます。
レイアウトのコードは
https://github.com/tiking76/chatapp/blob/master/chatApp/Utiles/Extentions.swift
に置いてあります。
もっと詳しく知りたいよ!!ってひと
↓のスライドをみてね!
- 投稿日:2020-07-21T01:27:44+09:00
UIKitのレイアウトをコードで組んだ時の備忘録
UIをコードで組んだ時に
translatesAutoresizingMaskIntoConstraints = falseを入れてあげないと、自分が組んだUIレイアウトが優先されない。
自分の場合
レイアウトを組む際は、関数を定義してあげて使ってます。
func anchor(top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, paddingTop: CGFloat = 0, paddingLeft: CGFloat = 0, paddingBottom: CGFloat = 0, paddingRight: CGFloat = 0, width: CGFloat? = nil, height: CGFloat? = nil) { translatesAutoresizingMaskIntoConstraints = falseこんな風に、書いてます。
これで
anchor()
を呼び出して使ってます。使用例
let titleLabel : UILabel = { let label = UILabel() label.text = "hoge" label.font = UIFont.boldSystemFont(ofSize: 14) return label }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(titleLabel) titleLabel.anchor(top: view.safeAreaLayoutGuide.topAnchor, right: view.safeAreaLayoutGuide.rightAnchor, paddingTop: 50, paddingRight: 147, width: 100, height: 56) titleLabel.layer.cornerRadius = 56/2 }みたいな感じで書いてあげればおそらくかけるのかなと思います。
こんな感じにできます。
レイアウトのコードは
https://github.com/tiking76/chatapp/blob/master/chatApp/Utiles/Extentions.swift
に置いてあります。
もっと詳しく知りたいよ!!ってひと
↓のスライドをみてね!
- 投稿日:2020-07-21T00:47:15+09:00
Udemyのswiftコース(英語のやつ)でiOSアプリ開発を学ぶ その2
勉強するコースはこれです
https://www.udemy.com/course/ios-13-app-development-bootcamp/進捗
セクション2まで終了(全部で36セクション)
Xcodeの使い方など開発環境についてのお話がメインだった最初の感想
<Udemyのコースについて>
- 本当に手取り足取り教えてくれるので、知識ゼロからでも学べそうなレベル
- 英語のレベルは、アメリカの小学校高学年~中学校くらいのレベルな気がする(小難しい単語は出ない)
- 先生(Dr. Angela Yu)の英語は、少しイギリス英語アクセントっぽいが非常に聞き取りやすい(アジア人にとって分かりやすい英語だと思う)
- やや説明するスピードが速いが、英語字幕があるので大丈夫そう
- 先生の英語はとても勉強になるし、ちゃんとした授業形式になっているので学びにつながる
- これやっとけばセブ島留学とか行く必要ないんじゃないかとすら思う。。<iOS開発について>
- レイヤーになっているところとかPhotoshopっぽい
- やはりwindowsとは違うので、操作には慣れが必要になる
- windowsよりも開発環境が全体的にデザインがポップな印象、ちょっとテンション上がる今後の予定
特に問題ないので、この調子で進めていく。
- 投稿日:2020-07-21T00:35:53+09:00
ARKitでバーチャル背景をつくる
例の機能をつくる
バーチャル背景は、ZoomやTikTokで見かける機能です。
それは、人物の背景を画像や動画に変えます。ARKitを使うことで、かんたんにバーチャル背景をつくることができます。
(ARSCNViewを使います。)ViewController.swift@IBOutlet var sceneView: ARSCNView! var virtualBackgroundNode = SCNNode()人物だけを手前に残す(People Occlution)
背景をバーチャルにするために、人物だけを手前にのこす必要があります。
ARKitのPeople Occlutionという機能を使うことで、人物をARコンテンツの手前に表示できます。
これを設定しないと、ARコンテンツが人物をオーバーラップしてしまいます。ARSessionにPeople Occlutionを設定します。
ViewController.swiftlet config = ARFaceTrackingConfiguration() if ARFaceTrackingConfiguration.supportsFrameSemantics(.personSegmentation) { config.frameSemantics.insert(.personSegmentation) } else { presentAlert(NSLocalizedString("この端末/OSではピープルオクルージョンを利用できません", comment: "")) } sceneView.session.run(config, options: [])バーチャル背景を置く(SCNNode)
バーチャル背景をつくる
板マテリアルでSCNNodeをつくり、その表面に画像や動画をコンテンツとして貼ります。
貼り付けるコンテンツはSpriteKitのSKSceneとしてつくります。
動画を貼るためにこうしました、と思う。画像の場合
ViewController.swift//画像の縦横比が歪まないように調整しています let width = uiImage.size.width let height = uiImage.size.height let mediaAspectRatio = Double(width / height) let cgImage = uiImage.cgImage let newUiImage = UIImage(cgImage: cgImage!, scale: 1.0, orientation: .up) let skScene = SKScene(size: CGSize(width: 1000 * mediaAspectRatio, height: 1000)) let texture = SKTexture(image:newUiImage) let skNode = SKSpriteNode(texture:texture) skNode.position = CGPoint(x: skScene.size.width / 2.0, y: skScene.size.height / 2.0) skNode.size = skScene.size skNode.yScale = -1.0 skScene.addChild(skNode)動画の場合
ViewController.swiftlet avPlayer = AVPlayer(url: videoUrl) //画像の縦横比が歪まないように調整しています var mediaAspectRatio: Double! guard let track = AVURLAsset(url: url).tracks(withMediaType: AVMediaType.video).first else { return (nil,nil) } let size = track.naturalSize.applying(track.preferredTransform) let resolution = (CGSize(width: abs(size.width), height:abs(size.height)),track.preferredTransform) let width = resolution.0?.width let height = resolution.0?.height mediaAspectRatio = Double(width! / height! ) avPlayer.actionAtItemEnd = AVPlayer.ActionAtItemEnd.none; NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didPlayToEnd), name: NSNotification.Name("AVPlayerItemDidPlayToEndTimeNotification"), object: avPlayer.currentItem) let skScene = SKScene(size: CGSize(width: 1000 * mediaAspectRatio, height: 1000)) if resolution.1?.b != 0{ skScene.size = CGSize(width: 1000, height: 1000 ) skScene.zRotation = 1.5708 } else if resolution.1?.a != 1.0 { skScene.zRotation = 1.5708 * 2 } let skNode = SKVideoNode(avPlayer: avPlayer) skNode.position = CGPoint(x: skScene.size.width / 2.0, y: skScene.size.height / 2.0) skNode.size = skScene.size skNode.yScale = -1.0 if resolution.1?.b != 0{ skNode.zRotation = 1.5708 } else if resolution.1?.a != 1.0 { skNode.zRotation = 1.5708 * 2 } skNode.play() skScene.addChild(skNode)ARKit(ARSCNView)で扱えるSCNNodeにコンテンツを貼り付けます。
ViewController.swiftvirtualBackgroundNode.geometry = SCNPlane(width: size, height: size) let material = SCNMaterial() material.diffuse.contents = skScene virtualBackgroundNode.geometry?.materials = [material] virtualBackgroundNode.scale = SCNVector3(1.7 * mediaAspectRatio, 1.7, 1) sceneView.scene.rootNode.addChildNode(node)バーチャル背景をカメラの前に置く
ViewController.swiftlet cameraPosition = sceneView.pointOfView?.scale let position = SCNVector3(cameraPosition!.x, cameraPosition!.y, cameraPosition!.z - 10) virtualBackgroundNode.position = positionバーチャル背景の位置を固定する
このままだと、端末カメラを動かすと、バーチャル背景がその置かれた「場所」にステイしてしまいます。
バーチャル背景がカメラを追いかけて、ずっとその前に居続けるようにさせます。
ARSCNViewのrendererメソッドでバーチャル背景SCNNodeにカメラ前のポジションを伝え続けます。
ViewController.swiftvar frontOfCamera = SCNVector3() func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { let position = SCNVector3(x: 0, y: 0, z: -10.0) // ノードの位置は、左右:0m 上下:0m 奥に50cm if let camera = sceneView.pointOfView { virtualBackgroundNode.position = camera.convertPosition(position, to: nil) virtualBackgroundNode.eulerAngles = camera.eulerAngles } }バーチャル背景の大きさを変えられるようにする
このままだと、背景のサイズが画面のフレームにあっているかわかりません。
なので、ユーザーがピンチ・ジェスチュアで背景の大きさをちょうど良いサイズに変えられるようにします。ViewController.swiftvar lastGestureScale:Float = 1 @objc func scenePinchGesture(_ recognizer: UIPinchGestureRecognizer) { switch recognizer.state { case .began: let logation = recognizer.location(in: sceneView) let hitResults = sceneView.hitTest(logation, options: [SCNHitTestOption.ignoreHiddenNodes:true]) if hitResults.count > 0 { guard let node = hitResults.first?.node else {return} materialNode = node } lastGestureScale = 1 case .changed: let newGestureScale: Float = Float(recognizer.scale) let diff = newGestureScale - lastGestureScale let currentScale = virtualBackgroundNode.scale virtualBackgroundNode.scale = SCNVector3Make( currentScale.x * (1 + diff), currentScale.y * (1 + diff), currentScale.z * (1 + diff) ) lastGestureScale = newGestureScale default :break } }ViewController.swiftlet pinch = UIPinchGestureRecognizer( target: self, action: #selector(type(of: self).scenePinchGesture(_:)) ) pinch.delegate = self sceneView.addGestureRecognizer(pinch)ピンチ・ジェスチュアでSCNNodeを操作する方法は、天才プログラマーK-Boyさんのコードをお借りしました。ありがとうございます。
実際のアプリはこちら
ARCamera.
AppStore:https://apps.apple.com/us/app/id1488699740GitHub:https://github.com/john-rocky/ARCamera
ぼくのTwitterをフォローしてください。お願いします。
https://twitter.com/JackdeS11お仕事のご依頼をこのメールにお願いします。
rockyshikoku@gmail.comあと、Looks Good For Me(わるくないね)、押してください。
ここです ↓
チャオ?!
- 投稿日:2020-07-21T00:18:35+09:00
viewWithTagで簡単に対象オブジェクトを呼び出して処理できる。
Swift初心者です。
こういうケースを想定してみてください
- ボタン(UIButton)がmain.storyboardにボタンA〜ボタンHまで8個配置されている
- ボタンAを押されたらボタンC,E,Gに対する動作を指定する
- ボタンBを押されたらボタンD,F,Hに対する動作を指定する
Swift初心者の私はこう書きました。
どうも、UIButton型の配列を作るのがうまくできなかったので、まずはボタンC〜Hを操作できるよう、ViewController.swift上で変数を宣言しました。
@IBOutlet weak var btnC: UIButton!
@IBOutlet weak var btnD: UIButton!
@IBOutlet weak var btnE: UIButton!
@IBOutlet weak var btnF: UIButton!
@IBOutlet weak var btnG: UIButton!
@IBOutlet weak var btnH: UIButton!
そのうえで、
@IBAction func play(sender :UIButton){ switch sender.tag { case 1: btnC.imageView?.startAnimating() btnE.imageView?.startAnimating() btnG.imageView?.startAnimating() default: btnD.imageView?.startAnimating() btnF.imageView?.startAnimating() btnH.imageView?.startAnimating()といったコードを書いていきました・・・
もっといい方法があるんだろうな、と思いながら書いていましたが、もちろんありました。
viewクラスの中にあるviewWithTagというメソッド。let button = self.view.viewWithTag(tag) as! UIButtonmain.storyboard上に、Viewというエリアがあり、ここにタグを入れられることは知ってました。
このタグの番号を持つボタンを取得してくれるというメソッドが、viewWithTagメソッド。
これを使えば、掲題の課題は下記のようにして記述ができる@IBAction func play(sender :UIButton){ play(tag: sender.tag) } @IBAction func playThreeOdd(sender: UIButton) { play(tag: 1) play(tag: 3) play(tag: 5) } @IBAction func playThreeEven(sender: UIButton) { play(tag: 2) play(tag: 4) play(tag: 6) }としてあげれば、あとはplayメソッドの引数をtag番号にして、viewWithTagメソッドでそのボタンを取得し、操作を書いてあげるだけ。
func play(tag: Int){ let button = self.view.viewWithTag(tag) as! UIButton button.imageView?.startAnimating() }