20201015のiOSに関する記事は9件です。

元自衛官実務未経験から受託開発企業から内定もらうまで

今回の記事はタイトル通り実務未経験から企業から内定もらうまで私がどんなことをしたのかを紹介します。
予め言いますがこれが私個人の経験からですのであくまで参考に、、、

大まかな筋道

海軍将校になりたくて海自入る->こんな仕事もう嫌ァァァ

辞めた

なんか稼げる仕事ないかな、、、(Youtube漁る)

プログラミングって結構稼げるんだ
とりあえずエンジニア界隈でイケてたKB○Yさんを見習ってFlutterを独学で勉強

挫折

プログラミングスクール通う
なんとなくiOSコースを受講
割とできそうだった

友達の大学生は就活真っ最中で自分も仕事したいと焦る
勉強会やスクールのメンターと話たりしてどんな方法が稼ぐのに最適か調べた
エンジニアとして一番稼げるのは個人で案件を獲得するいわゆるフリーランサー
じゃあiOSの案件ってどんなのあるの
実務経験者募集がほとんど。応募してみてもやっぱダメみたい。
自分がどんなことできるのかアピールできるものが必要->ポートフォリオ
これを宣伝してアピールできないかな

ムリだった、、笑
じゃあ仕事するか。技術磨いてまた挑戦しよう。1ヶ月間だけ就活しようムリなら東京出て頭下げまくってお願いしよう

ここでも実務経験が必要なとこがほとんど。
エージェントやポートフォリオ作っても書類選考も通れない
通れても御堅い企業やSlerとか。もっと自由な働き方したい

Indeedでたまたま上にでできた企業に応募。
とりあえず面接へ。
良さげな雰囲気、後日面接。なんとその後会食がしたいと連絡。
7割受かったと喜びいざ当日。面接というか企業情報を聞いただけその後焼肉奢ってもらった。
無事内定。

実際こんな感じ

よくこの職場で働きたいからこの言語で勉強みてみようって目にしますが、実際自分の行きたい会社に入れるのなんて奇跡に近いってか奇跡w
全てタイミングと運でしかなく就活中は「本当に会社行けんのか」って不安でしかたなかった。
先が見えない違業界からの転職ってこんな大変なんだって思い知らされましたね、、、
でも絶対どっか雇ってくれるところはあるし、技術がなくてもなんとかなるって精神はほんとに大事でしたね。

毎日4通は違う企業にメールしてたしフレームはあったけどちゃんと毎回違う志望動機でした。(簡単そうに見えて4つ書くのに企業研究含め3、4時間かけてましたね?)
送っても返事は帰って来ないことがほとんどだし心折れかけましたw

こんなことしてみては、、、?

私の失敗からこれからエンジニアを目指す方に聞いて欲しいのは、なぜエンジニアを目指しているのか明確にすることですね。
まずprogateとかオンラインスクールに入る前に考えて欲しいです。
エンジニアになって何がしたいのか、どんなエンジニアになっていたいか、本当にエンジニアになりたいのか。など

私がエンジニアを目指したのは、この職業が稼げると思ったからです。
実際に稼いでいる方はいますし情報社会で職業がなくなることはほぼないです。
勉強会やエンジニアの方とお話しした中で感じたのは、エンジニアとして稼ぐにはプログラムと〇〇です。
この〇〇はマーケティングや営業、企画や人脈、、、など様々。
どんなものでもどんな人でもチャンスは巡ってます。
でもどんな才能があってめちゃくちゃプログラミングができてもコミュ障じゃ売れないんです。

何が言いたいかというと目標がないとやっていけません。
あの人になりたいとかこれがしたいからとかも大事ですが、一番大事なのは「この夢はプログラミングがないとできないわ」って明確な目標。
これめちゃくちゃ難しいです。
でもこの目標があれば面接で強いし挫けかけても立ち直れると思います。
僕はこれを考えるまで苦労しました。

最後に

これをみているみなさんがなってよかったと思えるエンジニアになれるよう願っています。
手を動かすのも大事ですが、休憩も大事です。
かのワンピースのミホークも
B-sQQnNW0AEy8kz.jpg
って言ってます。
休みながらやっていきましょう。。。。


めんどくさくて確認してないので誤字脱字や脈絡のない文章であるかと思いますが、そっとコメントで教えてあげてください。
もしくは、見て見ぬふりでお願いします( ˘ω˘)スヤァ


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ARKit + Metalで手をゆらゆらさせてみる

ARKitとMetalを使って手をゆらゆらさせる方法を紹介します。

仕上がりは、こんな感じです。
20201015_qiita用_ショート.gif

考え方

ARKitのPeople Occlusionを使用します。

People Occlusionを使用すると人型のマスクテクスチャが得られるので、そのマスクとカメラの画像を同時に歪ませて、歪んだ合成用画像を取得します。歪んだまま切り取る感じです。

こんな画像が取得できます(わかりやすくするために動画よりも強めに歪ませています)

この歪ませた手の映像と、元の映像を重ねることで上のような動画を作ることができます。

手順

1.Appleの公式サンプルを入手する

Appleの公式サンプルにPeople Occlusionを使用して人型のマスクテクスチャを得る処理が書かれているため、これをベースに書いていきます。

Effecting People Occlusion in Custom Renderers

2. シェーダーに経過時間を渡す

ゆらゆらさせるには、経過時間を変形式に与える必要があります。

シェーダーに渡すstructを宣言します。

Renderer.swift
struct Uniforms {
    var time: Float = 0
}

次に、経過時間を管理するための変数と、開始時間を宣言します。

Renderer.swift
class Renderer {
    var uniforms = Uniforms()
    private var startDate: Date = Date()
    var uniformsBuffer: MTLBuffer! // シェーダに渡すためのバッファ

そしてシェーダに情報を渡しているcompositeImagesWithEncoderメソッドの中で一緒に経過時間を渡してあげます。

Renderer.swift
uniforms.time = time
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<Uniforms>.stride, options: [])
uniformsBuffer.label = "UniformsBuffer"

シェーダー側でもSwift側と同じstructを用意しておき、関数の引数として受け取ります。
引数名はmyUniformsとしています。

Shaders.metal
struct Uniforms {
    float time;
};

fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]],
                                    texture2d<float, access::sample> capturedImageTextureY [[ texture(0) ]],
                                    texture2d<float, access::sample> capturedImageTextureCbCr [[ texture(1) ]],
                                    texture2d<float, access::sample> sceneColorTexture [[ texture(2) ]],
                                    depth2d<float, access::sample> sceneDepthTexture [[ texture(3) ]],
                                    texture2d<float, access::sample> alphaTexture [[ texture(4) ]],
                                    texture2d<float, access::sample> dilatedDepthTexture [[ texture(5) ]],
                                    constant SharedUniforms &uniforms [[ buffer(kBufferIndexSharedUniforms) ]],
                                    constant Uniforms &myUniforms [[buffer(kBufferIndexMyUniforms)]])
{

3. シェーダーを書き換える

公式サンプルのうち、Shaders.metalのcompositeImageFragmentShader関数を次のように書き換えます。

Shaders.metal
@@ -219,8 +397,9 @@ fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]
     half4 sceneColor = half4(sceneColorTexture.sample(s, sceneTexCoord));
     float sceneDepth = sceneDepthTexture.sample(s, sceneTexCoord);

+    float2 modifier = float2(sin(cameraTexCoord.y + myUniforms.time*5)*0.2, 0); // 変形の式
     half4 cameraColor = half4(rgb);
-    half alpha = half(alphaTexture.sample(s, cameraTexCoord).r);
+    half alpha = half(alphaTexture.sample(s, cameraTexCoord + modifier).r); // 人型マスクを変形させる

     half showOccluder = 1.0;

@@ -233,8 +412,11 @@ fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]
         showOccluder = (half)step(dilatedDepth, sceneDepth); // forwardZ case
     }

+    float2 displacedUV = sceneTexCoord + modifier; // 画像を変形させる

-    half4 occluderResult = mix(sceneColor, cameraColor, alpha);
+    half4 displacedCol = half4(sceneColorTexture.sample(s, displacedUV)); // 変形した人型画像の取得
+    half4 occluderResult = mix(sceneColor, displacedCol, alpha); // 変形した画像と元の画像を合成
     half4 mattingResult = mix(sceneColor, occluderResult, showOccluder);
     return mattingResult;
 }

重要なのはここです。

Shaders.metal
float2 modifier = float2(sin(cameraTexCoord.y + myUniforms.time*5)*0.2, 0); // 変形の式

sin関数に入力画像のy座標と、経過時間を足したものを与え、これをmodifyerに代入しています。
modifierはカメラや人型マスクに加算するための変数で、今回はxだけに式が入っているので、x軸方向だけがゆらめくことになります。

なお、実際の動画は縦方向にゆらいでいるので、上の式と矛盾しますがこれは、iPhoneをランドスケープの状態で録画したものを、画像編集ソフトで縦に変換したためです。

図形の変形については、こちらの記事に書きましたので、こちらもご覧ください。

ARKitやSceneKitの図形をMetalシェーダーで変形させる方法

仕上がり

Youtubeにも動画をアップしています。
仕上がりの動画(Youtube)

ソースコードはこちらです。

最後に

NoteではiOS開発について定期的に発信していますので、フォローしていただけますと幸いです。
https://note.com/tokyoyoshida

Twitterでは簡単なtipsを発信しています。
https://twitter.com/jugemjugemjugem

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityでAR Foundationを使ってiOS向けARアプリを開発する(備忘録)

はじめに

iOS向けARアプリケーションをUnityを用いて開発したときに、詰まったり調べたことを自分への備忘録として残しておきます。
現在進行形で勉強しているので、随時変更していきます。

開発環境

  • Windows 10 Home
    • Unity (2019.4.1f)
    • AR Foundation (4.0.2)
    • AR Subsystems (4.0.1)
    • ARKit XR Plugin (4.0.2)
  • MacBook Pro (macOS Catalina)
    • XCode (12.0.1)
  • iPhone7 (iOS 14.0.1)

導入

  1. ここからAR Foundation samplesをダウンロード
  2. Unityでプロジェクトファイルを開く
  3. File -> Build Settings から PlatformをiOSに変更
  4. Buildした後、XCodeでUnity-Phone.xcodeprojを開き、実行

必須オブジェクト

  • ARSessionオブジェクト

    • AR Session スクリプト
      • AR Foundationの機能を使うために。ARシーンで1つ必要。
    • AR Input Manager スクリプト
      • World Trackingのために必要。
  • ARSessionOriginオブジェクト

    • AR座標とUnity Spaceの座標変換。ARアプリ起動時の座標が(0, 0, 0)になる。
    • ARSessionOriginオブジェクトの子要素にAR Cameraを設定。
    • 検出面はARSessionOriginクラスのtrackablesParentプロパティで取得可能

平面検出

  1. GameObject → XR → ARDefaultPlaneからARDefaultPlaneオブジェクトをシーンに追加
  2. Prefab化して、ARSessionOriginオブジェクト→ ARPlaneManagerコンポーネントPlane PrefabARDefaultPlaneオブジェクトを追加
  3. HierarchyからARDefaultPlaneオブジェクトを削除

PlaneオブジェクトにはARPlaneVisualizerコンポーネントを追加
MeshRendererコンポーネントのMaterialを変更することで好きな柄にすることが出来る(参考)

IMG_2062.jpg IMG_2064.PNG

AR Foundation Sampleについて

AR Foundation Menu

AR Foundationに含まれているSample Sceneを一覧で表示してくれる。助かる。
IMG_2063.PNG

Meshing

SimpleAR

  • 平面の検出、オブジェクトの設置、ARSessionの操作ができる簡単なサンプルシーン

Interaction

  • 検知した平面上にオブジェクトを設置できる。ジェスチャで移動、拡大、回転が可能

Face Tracking

  • TrueDepth front-facing Cameraが必要なため、iPhoneX以降またはiPad Proが必須。

Segmentation

Light Estimation

  • カメラから光情報を推定し、明るさ・色温度・色補正・光源の方向・光強度・光の色・Spherical Harmonicsを表示
  • 上記の環境では全てUnavailableでした

Image Tracking

Plane Detection

  • Feathered Plane
    • Planeがドット柄になる。
    • ARPlaneManagerコンポーネントのPlane PrefabARFeatheredPlaneオブジェクトを設定
  • Plane Classification
    • iPhone XS, iPhone XS Max, and iPhone XRで実行可能
    • 平面を「ドア(door)」「座席(seat)」「窓(window)」「床(floor)」などのカテゴリに分類
  • Toggle Plane Detection
    • Plane Detectionのオンオフを切り替える
    • ボタンが押されるとARSessionOriginオブジェクトのPlaneDetectionController.ToggulePlaneaDetection()を実行

Env Probes

Anchors

Object Tracking

CPU Images

AR World Map

  • iOS12が必要
  • ARWorldMapはNSSecureCodingに準拠しているので、NSKeyedArchiverを使ってシリアライズ
    • リロードはNSKeyedUnarchiver
  • 既存のARWorldMapからセッションを開始するには、ワールドトラッキング設定の initialWorldMap プロパティを設定してrunメソッドを実行する

Scale

  • 表示したオブジェクトの見かけのスケールを変更
    • AR Foundationではcontentのスケールを変えずに、ARSessionOriginTransformを変更する

AR Collaboration

Point Cloud

Plane Occulusion

Coaching Overlay

Check Support

  • デバイスがARに対応しているか表示

Sample UX

エラーまとめ

Unity

error CS0117: 'Collab' does not contain a definition for 'ShowChangesWindow'

nity CollaboratePackageのバージョンが合っていません。

Xcode

MapFileParser.sh: Permission denied

MapFileParser.shに実行権限がありません。ターミナルで以下のコードを実行して権限を付与します。

chmod +x MapFileParser.sh

Code signing is required for product type 'Application' in SDK 'iOS 14.0'

Xcode上でTeamが設定されていません。プロジェクトからSigning & Capabilitiesタブを開いてTeamを設定したら直りました。
Teamが変更できない場合は、Automatically manage signingがONにします。

"Unity-iPhone" requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor.

上に同じ。

Your maximum App ID limit has been reached. You may create up to 10 App IDs every 7 days

Apple Developper Programの無料版ではAppIDは10個/週しか作れません。なので以下のどれかの手順を踏む必要があります。(参考)
1. 新たなAppleIDをXcodeに登録する
2. 今まで使っていたAppID(BundleID)を使う
3. Apple Developer Programの有料バージョンに登録する

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【iOS】シミュレーターでソフトウェアキーボードを使う

ソフトウェアキーボード が表示されない場合の対処方法

メニュー から ソフトウェアキーボード と ハードウェアキーボード を切り替えることができます。
i/O > Keyboard > Connect Hardware Keyboard
switch_keyboard.png
ショートカットは Shift + ⌘ + K です。 switch_keyboard.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[iOS]Google Mobile ADs(バナー広告)の導入

作業

Firebase を iOS プロジェクトに追加する

  • 後から行う作業としてApp Store ID追加あり。App Store IDとは、iOSアプリのApp Store上でのID。App Store ConnectのMy Appのところから確認できる他、公開済みのアプリの場合、App Store上でのURLの末尾がApp Store IDとなっている。

複数のプロジェクトを構成する場合の注意点
使ってみる - Google Mobile ADs SDK
バナー広告

  • アプリ公開後にApp Store ID追加あり

テスト

テストは基本的にテスト専用の広告IDを使うこと。本番用の広告IDを使い、しかもそれをクリックしてしまうとライセンス違反となりアカウントが凍結される恐れがある。

テスト方法

トラブルシューティング

テスト用で広告が出たが、本番用で広告が出なかった。アプリ公開から二週間ほど経っているが・・・

Admob: adView:didFailToReceiveAdWithError: Publisher data not found. https://support.google.com/admob/answer/9905175#9
とのエラーが。google ad mob に支払い方法を追加してなかったのが原因??

しかしそもそも収益が出るまでは支払い方法追加できない??
https://teratail.com/questions/174802

とりあえず放置するしかない??

一応、端末を登録することで本番用の広告をテストできるそうなので、一応そちらを試してみる予定。試したら追記する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

play.jsとWorking Copyで、iPad上にNode.js実行環境を構築する。

iPad miniでNode.js実行環境を構築できたので、まとめてみました。

この記事でできること

  • iPadでNode.jsをローカル実行する。
  • iPadからGitHub上のリポジトリに対してpush / pullする。

注意事項

これから紹介するNode.js実行アプリは、エミュレータであり、
本家Node.js / npmの一部しかサポートしていないので、
PCでできることがそのままできたりはしないことに注意してください。

筆者のハードウェア環境

  • iPad mini 第5世代
  • Ewin Bluetooth Keyboard (Amazon)
  • ロジクール ワイヤレスマウス Pebble SE-M350OW (Amazon)

Node.js実行環境の構築手順

アプリをインストールする

play.js - JavaScript IDE
Node.js実行アプリ。npmやnodeを実行できますが、あくまでエミュレータ。
PCみたいにnpmやnodeを自由に実行する事はできません。
しかし、expressとReactでWebアプリを作成して実行できたりしますので、
かなり遊べます。

Working Copy - Git client
Gitクライアント。簡単な手順でGitHubにSSH接続できたりします。
pushを行うには、課金してProにグレードアップする必要があるものの、
play.jsのGit機能でpushできますので、課金する必要はありません。

GitHubにリポジトリを作成する

先にブラウザで、GitHubに空のリポジトリを作成した方が簡単です。

Working Copyでリポジトリをcloneする

Working Copyを起動して、作成したリポジトリをcloneします。
接続はSSHで行いますが、アプリが自動でキーを作成・登録してくれます。

cloneするには、左ペインの上にあるプラス (+) アイコンをタップして、
"Clone repository" を選択します。

iOSアプリ「ファイル」でWorking Copyを閲覧可能にする

iOSアプリ「ファイル」を起動して、
左ペインの上にあるミートボール(…)アイコンをタップし、「編集」を選択します。

Working Copyの項目がありますので、スイッチをオンにしてください。

play.jsでプロジェクトを作成する

play.jsを起動して、プラス (+) アイコンをタップし、新規プロジェクトを作成します。

Name、Typeを入力して、Directoryに "Select directory" を選択します。

表示されたダイアログに、先ほど閲覧可能にしたWorking Copyがありますので、
その中からリポジトリを選択します。

後はplay.jsでプログラミングをするだけです。
.gitignoreを作成してnode_modulesを含めることを忘れずに。

なお、Gitの操作は、基本的にplay.jsで行います。
Working Copyでpushを行うには課金が必要ですが、
play.jsからpushできますので、課金しなくても大丈夫です。

サンプルの紹介

Satomaru/mosaic-tile
これは、私が習作としてパクっ作ってみたパズルゲームです。
プログラミングを参考にされるのは恥ずかしいので、
play.jsの使い方を参考にする程度に見て、いじめないでください……。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS14で動画再生中、バックグラウンド移行時に一時停止されてしまう問題への対応

対応

  • playerView.player = nil
  • playerView.player = player

の実行タイミングを変更する

@objc func applicationWillResignActive(_ notification: NSNotification?) {
   playerView.player = nil
}

@objc func applicationDidBecomeActive(_ notification: NSNotification?) {
   playerView.player = player
}

経緯

  • ユーザー「iOS14にアップデートしたらバックグラウンド再生がおかしい。なんとかしろ:rage::bangbang:
  • ワタクシ「:sob:

対応前

  • applicationDidEnterBackgroundplayerView.player = nil していた ※Appleさんの公開しているドキュメントの記載内容に従ったもの

調査

  • 何もしてないのに動かなくなった ⇒ OSの仕様変わったな?
  • バックグラウンドに行ったら一時停止 ⇒ layerにplayer設定したままの動作と同じだな?

検証

  1. 動画再生中、バックグラウンド移行前に、手動で playerView.player = nil する
  2. バックグラウンドへ移行する

「再生が継続された!」

導き出される結論は…
「layer に player があるかどうかチェックしているタイミング変わったんじゃね?」

再検証

  1. applicationDidEnterBackground より前に実行される applicationWillResignActiveplayerView.player = nil するよう変更
  2. applicationWillResignActiveに対となるのが applicationDidBecomeActive となるため、そこで playerView.player = player するよう変更

「再生が継続された!」

※iOS11-14、iPadOS13,14で動作することも確認しました

まとめ

  • Appleさんのドキュメントのままに書いても動作しないため、OS不具合の可能性が高いです
    • iOS 14.2 beta2 で、この不具合が修正されているとの噂です

その他

  • iOS14がリリースされてしばらく経ちましたが、この対応方法を見かけなかったため記事を投稿します

参考文献

  1. Apple : Playing media while in the background using AV Foundation on iOS
  2. Apple : Playing Audio from a Video Asset in the Background
  3. @KenNagami : iOSアプリのライフサイクル
  4. @bosteri_bon : iOS14で「バックグラウンド再生」が出来ない不具合への対処
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS14のSwiftUIではリストのスクロール処理をコードで制御できるようになった

はじめに

iOS13のSwiftUIではできなかったコードによるリストのスクロール処理が、iOS14ではできるようになりました。
本記事でその実装方法をまとめています。

iOS13でのスクロール処理

iOSアプリを開発しているとよくある「○番目のセルに自動でスクロールする」という処理ですが、
これをiOS13のSwiftUIでは実現する方法がありませんでした。

struct ContentView: View {
    var body: some View {
        List(0..<100) {
            Text("\($0)")
        }
    }
}

UIKitでは以下のような形で、scrollToRow, scrollToItemなどのメソッドを呼び出す形で該当の要件を簡単に実装できるので、
この機能のためだけにUIViewRepresentable, UIViewControllerRepresentableなどを利用することもしばしばありました。

// UITableView
tableView.scrollToRow(at: IndexPath(row: 10, section: 0),
                      at: .top,
                      animated: true)

// UICollectionView
collectionView.scrollToItem(at: .init(item: 10, section: 0), 
                            at: .top,
                            animated: true)

iOS14でのスクロール処理

iOS14では ScrollViewReader というスクロール状態を制御できる新しいViewが追加されており、
これを利用すると任意の地点に自動でスクロールさせる処理の実装が可能になります。

以下にサンプルコードを示します。

準備

まずは、準備としてスクロール地点を指定するためのTextFieldを設置します。

struct ContentView: View {
    @State private var text: String = ""

    var body: some View {
        VStack {
            HStack {
                TextField("input row number", text: $text)
                Button("Scroll") {
                    guard let row = Int(text) else { return }
                    print(row)
                }
            }.padding()

            List(0..<100) {
                Text("\($0)")
            }
        }
    }
}

これにより、ボタンをタップするとユーザーがTextFieldに入力した値を取得できるようになります。

スクロール制御

それでは実際にスクロールさせる処理の実装部分です。

まずはスクロール制御をしたい箇所を ScrollViewReader で囲います。
これによりスクロール制御が可能な ScrollViewProxy インスタンスの取得ができるようになります。

struct ContentView: View {
    @State private var text: String = ""

    var body: some View {
        VStack {
+           ScrollViewReader { (proxy: ScrollViewProxy) in
                HStack {
                    TextField("input row number", text: $text)
                    Button("Scroll") {
                        guard let row = Int(text) else { return }
                    }
                }.padding()
                List(0..<100) {
                    Text("\($0)")
                }
+           }
        }
    }
}

さらに、スクロール位置を特定するためのIDを対象のViewに対して付与しておき、
制御を開始したい部分で ScrollViewProxyscrollTo メソッドにそのIDを指定するだけでスクロール処理を実現することができます。

struct ContentView: View {
    @State private var text: String = ""

    var body: some View {
        VStack {
            ScrollViewReader { (proxy: ScrollViewProxy) in
                HStack {
                    TextField("input row number", text: $text)
                    Button("Scroll") {
                        guard let row = Int(text) else { return }
+                       withAnimation {
+                           proxy.scrollTo(row, anchor: .top)
+                       }
                    }
                }.padding()

                List(0..<100) {
                    Text("\($0)")
+                       .id($0)
                }
            }
        }
    }
}

これでやりたいことが実現できるようになりました。

ちなみに withAnimation を付与しなければ、スクロールのアニメーションは行われなくなります。
また、第二引数の anchor でスクロール後の位置を細かく指定できます。

おまけ

Gridに対しても問題なく動作しました。

struct ContentView: View {
    @State private var text: String = ""

    var body: some View {
        VStack {
            ScrollViewReader { (proxy: ScrollViewProxy) in
                HStack {
                    TextField("input row number", text: $text)
                    Button("Scroll") {
                        guard let row = Int(text) else { return }
                        withAnimation {
                            proxy.scrollTo(row, anchor: .top)
                        }
                    }
                }.padding()

                ScrollView {
                    LazyVGrid(
                        columns: [
                            GridItem(.flexible(minimum: 0, maximum: .infinity)),
                            GridItem(.flexible(minimum: 0, maximum: .infinity)),
                        ],
                        alignment: .center,
                        spacing: nil
                    ) {
                        ForEach(0..<100) {
                            Text("\($0)")
                                .frame(height: 100)
                        }
                    }
                }
            }
        }
    }
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cookiecutterを使って爆速でiOSプロジェクトを作成する

cookiecutter_medium.png

はじめに

あなたは開発スタート時に毎回新しいXcodeプロジェクトを作っていませんか?
過去のプロジェクトから使ってもいいヤツらを 「Add Files to」していませんか?
xcconfigやcarthageの設定を毎回行っていませんか?

そうです、まさに私のことです。

というわけで、開発初期のスピードを加速させるべく
Cookiecutter というPythonのツールを利用して コマンド一発
iOSプロジェクトを作成している例があったので真似してみることにしました。

クイックスタート

サンプルとしてCleanArchitectureでの開発用テンプレートを作成してみました。
https://github.com/SatoshiN303/iOS-Blueprints-CleanArchitecture

$ brew install cookiecutter
$ cookiecutter https://github.com/SatoshiN303/iOS-Blueprints-CleanArchitecture.git

上記のコマンドを叩くと 「アプリ名」 「会社名」 「バンドルID」が聞かれます。
それぞれを入力するとプロジェクト作成完了です。
スクリーンショット 2020-10-14 18.35.49.png

生成されるサンプルプロジェクトについて

  • bootstrap.sh
  • .xcconfig (debug/adhoc/release)
  • CocoaPods Settings
  • Carthage Setting
  • no Main.storyboard
  • DependencyInjection SampleCode
  • Github's Repositry search process SampleCode

テンプレートの基本的な内容として上記を設定してみました。
普段通りに実装したものをCookiecutterテンプレートとして転用できるのは便利です。

ちなみに開発時には削除することになりますが
GitHubAPIを叩いて画面に表示するサンプルコードを追加しています。
理由としてCleanArchitectureで誰が何の責務を持っているか把握する為になります。
スクリーンショット 2020-10-15 0.03.10.png

Cookiecutterについて

主に機械学習向けのPythonパッケージやDjango等の
プロジェクトテンプレートを作成することができるツールです。

ドキュメントはこちらです。

cookiecutter-template を確認すると様々なテンプレートが公開されています。
まずは Forkして カスタマイズするのも有かなと思います。

Android向けiOS向けもそれなりにありました。
ちなみにローカルでも利用可能でした。

# Create project in the current working directory, from the local
# cookiecutter-pypackage/ template
$ cookiecutter cookiecutter-pypackage/

補足: Xcodeのプロジェクトテンプレートを使わなかった理由

Xcodeのオレオレプロジェクトテンプレート作成も試みたのですが
以下の理由で色々と面倒だったので cookiecutter を使う感じになりました。

  • TemplateInfo.plist をガッツリ弄るのが億劫
  • xcconfig とか BuildSettingsも設定したい

Xcodeの自作プロジェクトテンプレートに詳しい方などいらっしゃいましたら
コメント頂けると幸いでございます?‍♂️

今後やりたいこと

  • 再利用できるものはEmbedded Framework化した上でテンプレートに含める
  • 他のアーキテクチャも作りたい
  • テンプレートプロジェクト自体をCIで回してテンプレートの形骸化を防ぎたい
  • シェルスクリプト使ってAWS Amplifyも合わせて設定する

まとめ

Cookiecutter向けに自分好みのテンプレートを作って開発初期スピードを加速させよう

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む