20190530のiOSに関する記事は7件です。

UnityでARKit2 - 第二回 -

UnityでARアプリ開発をやってみたい 第二回

1. この記事でやること

前回の記事で、BitBucketから拝借してきたunity-arkit-pluginのREADMEをちゃんと読んでおこうという回です。記事にするほどのことでもないかもしれませんが、論文を読むときもまずはAbstractから読みますし、きっと大切なことが書いてあると思います。

2. READMEを読む

概要

  • Unity-ARKit-PluginはiOSのARKitSDKをUnityで利用できるようにしたものです
  • ARKitのいろんな機能がちゃんと使えます
  • 多くのアプリがすでにこのプラグインを使ってAppStoreに公開されています
  • Unity2017.4以降のバージョンで使ってね
  • 細かい使い方はTUTORIAL読んでね
  • Licenseも読んでね(まぁ、MITライセンスだし変なことしなければ自由にしてね)
  • プルリク遠慮なく

動作要件

  • Unity v.2017.4 以降
  • XCode 10.0 と ARKit SDK
  • ARKit対応のiOSデバイス
    • iPhoneなら6S以降
    • iPadなら2017年発売モデル以降
    • iOS12 以降

ビルドしてみよう

これは第一回: UnityでARKit2でやったので割愛しますが、いろんなサンプルが用意されているので、ひととおり試してみるのもいいかもしれないですね。
ここでポイントはUnityARBuildPostprocessor.cs(Unity-Technologies-unity-arkit-plugin/Assets/UnityARKitPlugin/Plugins/iOS/UnityARKit/Editor/UnityARBuildPostprocessor.cs)がビルド時にもろもろのXCodeプロジェクトへの変換処理をしてくれているということ。このファイル、とても大事。正直言って中身見てもなんのことやらさっぱりなので、なんかすごいありがたいなーという気持ちだけ持っておけば大丈夫だと思います。大事なのは感謝の気持ち。

API

なんかいっぱい書いてるー :D

DelegateとEventのメジャーどころのリストですね。
これは手を動かし始めないとなんとも言えないやつです。

あとがき

第二回はREADMEを読んでみました。
読んでみてわかったことは、ちゃっちゃとTUTORIALやれってことです。
あとはまぁ、動作環境のチェックは必須ですよね。

はい、では次回はTUTORIALやります。

今回はこのくらいで。

ではでは。

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

UIKitの基本について

初めまして!きゅうすけと申します!
iOSエンジニア卵の私が、自社の定例イベントの勉強会で学んだ基礎の部分をまとめたものです!
メモ感覚ではありますが、これ違うぞってことがあったらぜひ教えてくださいー!(● ˃̶͈̀ロ˂̶͈́)੭ꠥ⁾⁾

UIKitの基本

UIkit
iOSで必要なライブラリを用意してくれる
iOSアプリの画面をレイアウトをするには必要不可欠

import: UIkit
UIkitをViewControllerを使えるようにする
これをしないとやらないとBottunとかが使えない

よく使う基本的なUIKit
UILabel:テキストを表示する
UIButton :ボタンのUIを提供する
UITextField:テキストを入力するフィールド
UIImageView:画像を表示する
UITableView:リスト表示などに使用
UICollectionView:タイル貼りのように複数列表示することができる
UIScrollView:画面のスクロールを管理する
UITextView:複数行、スクロール可能なテキストを表示する
UISwitch :ON/OFFすることができるUI
UIDatePicke:年月日を選択する

メモ
書いてあるソースコードをcommand押しながらクリック
→ 定義している場所に飛ぶ

今回の勉強会ではUITableView、UICollectionView、UIScrollViewについて説明があったので、
この3つについても書いていきます。

UITableView、UICollectionView、UIScrollView

TableView
└iPhoneの設定画面
・縦方向でしか表示できない List表示
 AndroidはrecycleView (ListViewは非推奨)

・「Plain」と「Grouped」の二種類がある
 Grouped → iPhoneの設定画面
 └セクションがグレーになる
 Plain
 └セクションはあるけど見えてない?

・セクションヘッダーとセクションフッターがある

CollectionView
└ iPhoneのMUSIC、メルカリ

・縦方向に加えて横方向にも表示することができる
・AndroidはConstraint Layout? (ListViewは非推奨らしい)
・セクションヘッダーとセクションフッターがある

ScrollView
・電子書籍のように複数のページを送って表示させたい場合などに使用する

講師の人からのアドバイス

「この画面はTableViewをを使って実装した方が良いな」
「こっちの画面はTableViewではなくCollectionViewを使って実装だな」
みたいなことが、アプリのデザインを見た時に判断・イメージができるようになると、アプリ開発をする際にとても役に立つらしい!

TableViewとCollectionViewはどう判断して作っているか

TableView:cellのデザインが一緒 一覧の表示の場合
CollectionView:カード的なデザイン

まとめ

UIKitがどんなものかちゃんと知らない状態でswiftに触っていたので、
今回学べたことによりなぜ毎回一番上に書かれているかということがわかりました。
知らないで書くより知って書くのとでは大違いだなと実感しました!
TablwViewも、自分でサンプル作ってもっと仲良くなっていこうと思います!

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

iPhone、iPadで複雑な形状をした図形内のタッチイベントを簡単に取得する方法 〜CAShapeLayer編〜

現在開発中のアプリで矩形以外の複雑な形をした画像をのタッチイベントを取得する必要があり日本語、英語で軽く検索してみたが、”これだ!”という文献が探せなかったので共有しておきます。Playgroud環境下ですぐにお試しできます。
ezgif-5-9653f8f1f6ea.gif

下準備 〜画像作成〜

最終的にCAShapeLayerのPath(CGPath)に代入するので、Illustrator, Sketch, Figmaなどでベクター画像を作り、PaintCodeなどでUIBezierPathに変換します。
またPocketSVGというライブラリを使えば、SVGファイルCGPathとして取得できます。
Screen Shot 2019-05-30 at 12.15.53 AM.png

今回はその生成物(UIBezierPath)を解りやすいようにコード内にハードコーディングしていますが、図形の形状が複雑になると長くなってコードの可読性が悪くなるので別ファイル化した方が良いでしょう。
下記はUIBezierPath(上記の生成物をコピー)をCGPathで返す単純なfunctionです。

UIBezierPath
    func getPath()  -> CGPath {
        //Start: Created by PaintCode
        let bezierPath = UIBezierPath()
        bezierPath.move(to: CGPoint(x: 13.08, y: 129.49))
        bezierPath.addLine(to: CGPoint(x: 1.58, y: 117.99))
        bezierPath.addLine(to: CGPoint(x: 14.58, y: 104.99))
        bezierPath.addLine(to: CGPoint(x: 0.71, y: 91.11))
        bezierPath.addLine(to: CGPoint(x: 27.71, y: 64.1))
        bezierPath.addLine(to: CGPoint(x: 27.71, y: 53.7))
        bezierPath.addLine(to: CGPoint(x: 49.97, y: 31.45))
        bezierPath.addLine(to: CGPoint(x: 49.97, y: 23.61))
        bezierPath.addLine(to: CGPoint(x: 73.08, y: 0.5))
        bezierPath.addLine(to: CGPoint(x: 101.97, y: 0.5))
        bezierPath.addLine(to: CGPoint(x: 110.6, y: 9.13))
        bezierPath.addLine(to: CGPoint(x: 125.95, y: 9.13))
        bezierPath.addLine(to: CGPoint(x: 155.8, y: 39.71))
        bezierPath.addLine(to: CGPoint(x: 155.8, y: 52.35))
        bezierPath.addLine(to: CGPoint(x: 138.37, y: 69.78))
        bezierPath.addLine(to: CGPoint(x: 97.72, y: 29.13))
        bezierPath.addLine(to: CGPoint(x: 61.51, y: 65.34))
        bezierPath.addLine(to: CGPoint(x: 68.66, y: 72.49))
        bezierPath.addLine(to: CGPoint(x: 33.66, y: 107.49))
        bezierPath.addLine(to: CGPoint(x: 47.91, y: 121.74))
        bezierPath.addLine(to: CGPoint(x: 40.16, y: 129.49))
        bezierPath.addLine(to: CGPoint(x: 13.08, y: 129.49))
        bezierPath.close()
        //END
        return bezierPath.cgPath
    }

CAShapeLayerとは?

CAShapeLayerは名前からわかるようにCALayerのサブクラスで、UIBezierPathなどで作ったベクター画像を表示します。ベクター画像は通常のイメージと異なり拡大縮小してもボケたりジャギーが出たりすることがないので、@2x@3xの画像を作成する必要がありません。またCAShapeLayerのプロパティでパスの線の形状、色、パス内の色などを変更することが可能で、その多くがアニメーション可能です。そのため、簡単にタップしたらアニメーション付きで、色が変わる、大きさが変わるなどの仕掛けを作ることができます。

CALayerCAShapeLayerの他にも、CATextLayerCAGradientLayerCATiledLayer など数々の表示に関するサブクラスがあります。下記記事は英語ですが、それらがよくまとまっているので、一読をお勧めします。
CALayer Tutorial for iOS: Getting Started

ベクター画像の表示

CAShapeLayerを使った画像の表示手順は、
1. CAShapeLayerのインスタンスを生成
2. そのインスタンスのpathプロパティに上記で作成したパス(CGPath)を代入。
 shapeLayer.path = getPath()
3. インスタンスのプロパティで線種、線色、色などを設定(任意)
4. UIViewlayeraddSublayerメソッドを使って、上記のCAShapeLayerのインスタンスを追加
 self.layer.addSublayer(shapeLayer)
今回は上記手順をfunction(setupView())にまとめ、UIViewのカスタムクラスのイニシャライザでコールしています。

UIBezierPath
    private let shapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    private func setupView()    {
        shapeLayer.path = getPath()
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 2.0
        shapeLayer.strokeColor = UIColor.blue.cgColor
        self.layer.addSublayer(shapeLayer)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let point = touch!.location(in: self)
        shapeLayer.fillColor = shapeLayer.path!.contains(point) ? UIColor.red.cgColor : UIColor.white.cgColor
    }

タッチイベントの設定

さて、いよいよ本題のタッチイベントの設定です。今回はカスタムUIViewに画像を表示しているので、先ずはUIViewtouchesBeganをオーバーライドしてUITouchからタッチしたポイントを取得しています。let point = touch!.location(in: self)
その後、CGPathcontainsメソッドでそのポイントがパス内にあるかどうか確認しています。shapeLayer.path!.contains(point) このメソッドは領域内であればtrueを、外ならfalseを返します。
この例では画像をタッチした場合は画像を赤に、外であれば画像を白に変更しています。

VectorImageTouchEvent
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let point = touch!.location(in: self)
        shapeLayer.fillColor = shapeLayer.path!.contains(point) ? UIColor.red.cgColor : UIColor.white.cgColor
    }

まとめ

知ってしまえばとても簡単です。CAShapeLayer素晴らしい。下記にコード全文を載せておきますので、Playgroudにコピー、実行すれば試せます。

TouchableVectorImageView
import UIKit
import PlaygroundSupport
let v = UIViewController()
PlaygroundPage.current.liveView = v


class TouchableVectorImageView:UIView   {
    private let shapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    private func setupView()    {
        shapeLayer.path = getPath()
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 2.0
        shapeLayer.strokeColor = UIColor.blue.cgColor
        self.layer.addSublayer(shapeLayer)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let point = touch!.location(in: self)
        shapeLayer.fillColor = shapeLayer.path!.contains(point) ? UIColor.red.cgColor : UIColor.white.cgColor

    }
}

extension TouchableVectorImageView    {

    func getPath()  -> CGPath {
        //Start: Created by PaintCode
        let bezierPath = UIBezierPath()
        bezierPath.move(to: CGPoint(x: 13.08, y: 129.49))
        bezierPath.addLine(to: CGPoint(x: 1.58, y: 117.99))
        bezierPath.addLine(to: CGPoint(x: 14.58, y: 104.99))
        bezierPath.addLine(to: CGPoint(x: 0.71, y: 91.11))
        bezierPath.addLine(to: CGPoint(x: 27.71, y: 64.1))
        bezierPath.addLine(to: CGPoint(x: 27.71, y: 53.7))
        bezierPath.addLine(to: CGPoint(x: 49.97, y: 31.45))
        bezierPath.addLine(to: CGPoint(x: 49.97, y: 23.61))
        bezierPath.addLine(to: CGPoint(x: 73.08, y: 0.5))
        bezierPath.addLine(to: CGPoint(x: 101.97, y: 0.5))
        bezierPath.addLine(to: CGPoint(x: 110.6, y: 9.13))
        bezierPath.addLine(to: CGPoint(x: 125.95, y: 9.13))
        bezierPath.addLine(to: CGPoint(x: 155.8, y: 39.71))
        bezierPath.addLine(to: CGPoint(x: 155.8, y: 52.35))
        bezierPath.addLine(to: CGPoint(x: 138.37, y: 69.78))
        bezierPath.addLine(to: CGPoint(x: 97.72, y: 29.13))
        bezierPath.addLine(to: CGPoint(x: 61.51, y: 65.34))
        bezierPath.addLine(to: CGPoint(x: 68.66, y: 72.49))
        bezierPath.addLine(to: CGPoint(x: 33.66, y: 107.49))
        bezierPath.addLine(to: CGPoint(x: 47.91, y: 121.74))
        bezierPath.addLine(to: CGPoint(x: 40.16, y: 129.49))
        bezierPath.addLine(to: CGPoint(x: 13.08, y: 129.49))
        bezierPath.close()
        //END
        return bezierPath.cgPath
    }
}


v.view.addSubview(TouchableVectorImageView(frame: CGRect(x: 50, y: 50, width: 200, height: 200)))
v.view.backgroundColor = UIColor.gray

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

(オサーンの備忘録2019)iOSのプロジェクトのlinkerエラーでやった事まとめ

podのリンカーエラーででやった事まとめ

エラー内容

clang:-1: linker command failed with exit code 1 (use -v to see invocation)
  1. 当たり前だけど、「xxxx.xcworkspace」で開く
  2. 念の為 キレイキレイのコマンド pod install --repo-update
  3. 自分の環境では
The `プロジェクト名[Release]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-プロジェクト名/Pods-プロジェクト名.release.xcconfig'. This can lead to problems with the CocoaPods installation

が出てたので、OTHER_LDFLAGSに$(inherited)追加
4. Build Active Architecture Onlyをpodsprojectで合わせる。(これ大事)
で、ビルドが通りました。

それとprovisioningでエラーになっていたので。
PROVISIONING_PROFILEを削除しました。

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

Realmでenumを使うときメモ

結論

privateプロパティのときは@objcMembersを書いていても@objcを書かないとだめ

これでいけそうだけどだめで

@objcMembers
class Phone: Object {

    dynamic var name = ""
    private dynamic var osTypeRawValue = "" // privateの場合は@objcMembersを書いてあってもこれじゃだめ
    var type: OSType {
        get { return OSType(rawValue: osTypeRawValue) ?? .undefind }
        set { osTypeRawValue = newValue.rawValue }
    }

    enum OSType: String {
        case ios
        case android
        case undefind
    }
}

こうするとOK

@objcMembers
class Phone: Object {

    dynamic var name = ""
    @objc private dynamic var osTypeRawValue = "" // @objcを明示的につける
    var type: OSType {
        get { return OSType(rawValue: osTypeRawValue) ?? .undefind }
        set { osTypeRawValue = newValue.rawValue }
    }

    enum OSType: String {
        case ios
        case android
        case undefind
    }
}

こんな感じでenumが使える

let phone = Phone()
phone.type = .ios
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最速で使うFlutter(Ubuntu編)

概要

とりあえずFlutterを使ってみたい方向けのシンプルな解説です。

できること

  • Flutterの導入
  • Android端末上でのシミュレート

Flutter(フラッター)は、Googleによって開発されたフリーかつオープンソースのモバイルアプリケーションフレームワークである。(Wikipedia)

公式ドキュメントを参考にしています。
英語が出来る方は、公式のドキュメント(Get started)を見たほうが早いです。

環境 :
ubuntu 18.04
AndroidStudio インストール済み

シミュレートには、Androidの実機が必要です。買いましょう…

1.インストール

1-1.ダウンロード

公式サイトからダウンロードし、解凍しましょう。
https://flutter.dev/docs/get-started/install/linux

 cd ~/development
 tar xf ~/Downloads/flutter_linux_v1.5.4-hotfix.2-stable.tar.xz

1-2.pathを通します

export PATH="$PATH:$HOME/development/flutter/bin"
source ~/.bashrc

1-3.ネット環境が不安定な方は実行してください

通常は要らないです。

 flutter precache

1-4.依存関係の確認をします

flutter doctor

lib32stdc++6とライセンスへの同意が必要です。以下のコマンドを実行してください。

sudo apt install lib32stdc++6
flutter doctor --android-licenses

1-5.AndroidStudioの設定

Android Studioを起動し、Android Studio Setup Wizardを完了させてください。

1-6.Androidデバイスの設定

開発者向けオプションからUSBデバッグを有効にします。
以下のコマンドを実行し、デバイスが正しく接続されていることを確認してください。

flutter devices

2.エディタの設定

拡張機能/プラグインを追加する必要があります。

VScodの場合:拡張機能からFlutterを追加
AndroidStudioの場合:プラグインからFlutterとDartを追加

3.アプリを作成しよう

今回はAndroidStudioを用います。

3.1 プロジェクトの作成

ファイル > 新規 > New flutter Project
Flutter Applicationを選択します。

Flutter SDK pathを以下のように設定します。

/home/[user]/development/flutter

Runをクリックし実行してみましょう。

Screenshot_20190530-122808.png

できました。

3.2 ホットリロード

Flutterの特徴の一つでもあるホットリロードを試しましょう。

lib/main.dart を開きます。
92行目にある

'You have pushed the button this many times'

を以下のように変更しましょう。

'You have clicked the button this many times'

Screenshot_20190530-123133.png

このように即反映されます。

3.3 プロファイルの方法

*ホットリロードやデバッグモードとは併用出来ません。その分、滑らかに描画できます。

flutter run --profile

4.アプリ作成のガイド

最速で使うFlutter(アプリ作成編) Part1

間違いがあったら教えてください><
最後まで、ありがとうございました。さようなら〜

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

Swift - init(repeating:count:)で配列を生成するときの注意点

基本的な使い方

// 4人で点数を競うときの初期値を0でいれておく

var playerScores = Array(repeating: 0, count: 4)
print(playerScores) // [0, 0, 0, 0]

// 書くプレイヤーがスコアを獲得
playerScores[0] += 5
playerScores[1] += 10
playerScores[2] += 15
playerScores[3] += 20
print(playerScores) // [5, 10, 15, 20]

クラスのインスタンスを格納する配列を生成する

class Player {
  var name = ""
  var score = 0
}

var players = Array(repeating: Player(), count: 4)

// 書くプレイヤーに名前を代入
players[0].name = "John"
players[1].name = "Paul"
players[2].name = "George"
players[3].name = "Ringo"

players.forEach { player in
  print(player.name)
}

/*
Ringo
Ringo
Ringo
Ringo
みんなRingoになってしまった
*/

クラスのような参照型の場合、同じ参照を持つインスタンスがrepeatingにより複数生成されてしまいます。例えば、上記のようにクラスのインスタンスを配列で格納し、セルに表示する情報を管理する場合などは、1つの要素の情報を変えると他の要素にまで影響があるので注意が必要です。

解決策

structなら値型なので上記のように1つの要素の値を変更すると、他の要素まで影響があるということはありません。

struct Player {
  var name = ""
  var score = 0
}

var players = Array(repeating: Player(), count: 4)

// 書くプレイヤーに名前を代入
players[0].name = "John"
players[1].name = "Paul"
players[2].name = "George"
players[3].name = "Ringo"

players.forEach { player in
  print(player.name)
}

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