20200117のiOSに関する記事は5件です。

"The bundle uses a bundle name or display name that is already taken."が出た時の対処法

iosアプリを申請しようとしたらこんなエラーが

ERROR ITMS-90129: "The bundle uses a bundle name or display name that is already taken.

でググってみるとbundle nameかbundle display nameが既にあるアプリとかぶってますよというわけだ。

なのでinfo.plistのBundle nameを適当な自分の好きなものに変更すればビルドが通るはずです。

まとめ

審査中につまずいたことがたくさんあったのでいろんなこと書いていきます!

参考

https://application.hateblo.jp/entry/2018/01/08/042725

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

スマホアプリ開発者のための2019年動向まとめ

はじめに

2019年は新元号「令和」のスタートやラグビーワールドカップなどなんとなくめでたい年でした。年始まで忙しかったので2020年の1月中旬ですが2019年のスマホアプリ業界をこっそりまとめます。

個人的には2019年はAndroidアプリを中心にネイティブアプリ開発保守をしていました。
スマホアプリ開発に携わっていない人もこの記事を見れば2019年のいろいろが分かるかも。
振り返り用に「ふむふむ」「へー」程度に見ていただければ幸いです。

【前年】
スマホアプリ開発者のための2018年動向まとめ
Unityでスマホアプリ(特にプラグイン)を開発している人のための2017年対応まとめ
Unityでスマホアプリ(特にプラグイン)を開発している人のための2016年対応まとめ

通信回線について

約10年に1度の通信回線アップデート、5Gがついにはじまりました。
2019年4月に米Verizonが開始し、9月に米Qualcommが開催した「2019 Future of 5G」では半年以内に30以上の通信事業者が5Gを開始または開始予定としていることが発表されました。

スクリーンショット 2020-01-15 22.01.12.png

https://www.verizon.com/about/our-company/5g
https://www.qualcomm.com/documents/2019-future-5g-presentation

日本ではdocomo、KDDIが2019年9月にプレサービスを開始し、2020年を目処に商用サービス開始予定です。高速、大容量、低遅延、多接続、低消費電力などがキーワードとしてあげられています。

https://www.nttdocomo.co.jp/corporate/technology/rd/tech/5g/
https://www.softbank.jp/biz/5g/
https://biz.kddi.com/5g/

また、3Gの停波のお知らせを公開し、auは2022年、SoftBankは2024年、docomoは2026年に停波となることが決定されました。これによってガラケーやらくらくホンを使用していたシニア層がスマホに大量流入することが予想されます。

https://www.nttdocomo.co.jp/info/news_release/2019/10/29_00.html
https://news.kddi.com/kddi/corporate/newsrelease/2018/11/16/3428.html
https://www.softbank.jp/mobile/network/3g-end/

端末について

Appleからは例年通り9月にiPhone 11, iPhone 11 Pro, iPhone 11 Pro Maxが発売、Googleからは5月にPixel3a, 10月にPixel4が発売されました。
iPhoneもPixelも基本的にはカメラ機能推しで「夜景モード」という言葉は今年浸透した印象です。

2019年は数少ないですがGalaxyやLGから折りたたみ端末(Foldable端末)が発売されました。Microsoftからは「Surface Duo」というAndroid端末が発表され2020年のホリデーシーズンに発売予定です。

5G対応の端末が2019年から発売され2019年12月現在は約30機種に増えました。2020年は対応機種が増え日本からも発売されることが予定されています。

2019年のスマホサービスについて

決済サービスの増加

個人的に大きいと思ったスマホアプリのニュースは2019年2月のPaypay100億円キャンペーンでした。
各店のPOSも多くの決済方法に対応し、生活が一変しました。
非接触方式に比べるとアプリ立ち上げやバーコード提示など不便な印象でしたが、
増税時のキャッシュバックキャンペーンなども後押しし、バーコード/QRコード決済が増えました。
Paypay、LINE Pay、メルペイ、Origami Pay、Kyash、ファミペイ、Origami Pay、楽天ペイ、セブンペイなどいろんなペイの選択肢が増えました(そして消えたサービスもありました)

スマホゲームについて

2019年は日本の大手企業のリリースが多い年でした。
任天堂からはマリオカートツアー、ドクターマリオワールド、ポケモンマスターズと2019年で3本のリリースがありました。
また、ドラゴンクエストウォークなどの位置ゲームに関して世界的にリリースが多く、Googleからゲーム事例の記事が投稿されています。

魅力あるゲーム体験を実現するGoogle Maps Platformの新機能と最新ゲーム事例
https://developers-jp.googleblog.com/2019/12/new-features-contextualized-gameplay-and-new-games-built-google-maps.html

また、ゲームのサービス形態が変化した年でした。Appleからは定額制サービスのApple Arcade、GoogleからはクラウドゲームのStadiaが発表されサービス開始しました。

子供向けプライバシーの保護の強化

スマホに限らずですが、YouTubeで子供向けプライバシー保護の取り扱いが大きく変更されました。
子供向けであると判断された、あるいはそう申告されたすべてのコンテンツについて、視聴者は無条件で子供と見なされるようになりました。

https://youtube.googleblog.com/2019/09/an-update-on-kids.html
https://youtube.googleblog.com/2020/01/better-protecting-kids-privacy-on-YouTube.html

子供向けプライバシー保護の強化はYouTubeのみでなくGoogle Play Serviceにも実施され、
自分が公開している子供向けアプリもGoogle Play Serviceを実装しているという理由で2019年に突然リジェクトされました。(参考: 2019年以降、GooglePlayの子供向けゲームアプリに○○を実装してはいけない)

iOSも例外ではなく9月に「子ども向け」カテゴリガイドラインが更新されました。
2020年3月3日までは対応の猶予期間となっています。

すべての新規Appはこのガイドラインに従う必要があります。また、できるだけ早く既存のAppを更新することをお勧めします。既存のAppにこのガイドラインを適合するのにさらに時間が必要な場合を考慮し、コンプライアンスに準拠させるために2020年3月3日までさらに6か月の猶予期間を設けることにしました。

iOS

iOS13

iOS 13をプレビュー
https://www.apple.com/jp/newsroom/2019/06/apple-previews-ios-13/
iOS 13 Release Notes
https://developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes

2019年9月19日にiOS13の提供が開始されました。
SwiftUI、ダークモード、SF SymbolsなどUI周りが大きく変更されました。
ただしSwiftUIで開発したアプリはiOS13以降のみの対応となるため、完全移行は数年かかりそうです。
iPad向けのOSがiOSからiPadOSになり、iPad用AppをmacOSへ用意に移植できるProject CatalystもWWDC19で発表されました。

Submit Your iOS Apps to the App Store
https://developer.apple.com/news/?id=09102019a&1568158483
Modernizing Your UI for iOS 13
https://developer.apple.com/videos/play/wwdc2019/224/

iOSアップデートにより、要件も更新されました。
2020年4月からiOS13および3rd-genのiPad Pro対応必須となり、同時に以下を要件としています。

  • LaunchScreenのStoryboard化
  • 複数サイズのサポート
  • 分割スクリーンのマルチタスク化

スクリーンショット 2020-01-15 22.19.12.png

参考:

iOSのその他対応

その他にもPUSH通知、UIWebView受付終了の告知がされています。

Apple Push Notification service(APNs)は、2020年11月以降レガシーバイナリプロトコルをサポートしなくなります。

App Storeは、2020年4月からUIWebViewを使った新しいAppの受付を終了し、2020年12月からUIWebViewを使ったAppのアップデートの受付を終了します。

Android

Android10

ようこそ!Android10
https://developers-jp.googleblog.com/2019/09/android-10.html

2019年9月3日にAndroid10の提供が開始されました。
ジェスチャーナビゲーション対応、5G対応、折りたたみ画面対応、セキュリティ強化などが含まれています。

詳細なこちらへ > Android 10対応したので個人的まとめ (RSSリーダーアプリ編)

APIレベル28(Android 9)以上が必須に

2018年までの必須APIレベルは26でしたが今年は28になりました。
APIレベル28の変更点として、デフォルトのネットワークセキュリティ構成がhttps通信のみ許可になりました。
http通信を行うにはドメインをホワイトリストに追加するなどの対応が必要になります。

2019年のターゲットAPIレベル要件の拡大について
https://developers-jp.googleblog.com/2019/03/2019-api.html

AndroidでのTLS採用に関する最新情報
https://developers-jp.googleblog.com/2020/01/android-tls.html

また、2019年8月以降64ビットが必須要件になりました。
Unity5.6以前を使用したゲームの場合は2021年8月までの延長期間が与えられています。

アプリを64ビット要件に対応させましょう
https://developers-jp.googleblog.com/2019/02/get-your-apps-ready-for-64-bit.html

2年連続でAPIレベルが夏から秋にかけてAPIレベルの底上げを行っています。
例年通りだと2020年も行われることが予想されます。
旧サポートライブラリの最終バージョンが28なので、
APIレベル29対応では必然的にAndroidX対応が必要となります。
余裕があるときにAndroidX対応をしていたほうが良さそうです。

Android関連のドキュメントの拡充

2019年1月にAndroidのCodelabが公開されました。
基礎コースと応用コースが用意され、学習が容易になりました。

https://developer.android.com/courses

AndroidXはドキュメントページで最新バージョンがわかるようになった他、
Feedでのバージョン情報提供もはじまりました。
SlackなどでFeedを登録しておけば最新ライブラリの情報がキャッチ可能になります。

https://developer.android.com/jetpack/androidx/versions
https://developer.android.com/feeds/android-release-notes.xml

Androidのその他

2018年末のKotlin1.3でコルーチンが正式対応となり、Google Developers Blogでもコルーチン関連の記事が公開されました。
プロジェクトの動的モジュール化やコード圧縮ツールR8も注目のトピックとしてあげられています。

また、Project Marbleという以前からのAndroid Studio改善の取り組みが反映された、Android Studio 3.5がリリースされました。
詳細はこちら >Android Studio3.5の変更点をもっと詳しく知りたい..!

2020年春に登場するKotlin1.4

Kotlin 1.4の計画および将来的な展望
https://blog.jetbrains.com/jp/2020/01/16/2731

12月に行われたKotlinConf 2019でKotlin1.4の展望が発表されました。
(ちょうど昨日に日本語版blogが更新されました!)
マルチプラットフォーム化やKotlinのSAM変換についての変更などがあります。

Flutter

2019年はFlutter関連のニュースも多くありました。
6月にFlutter for Web発表、12月にはFlutter単独で技術イベントFlutter Interactが行われ注目度は今年も上がっています。

Flutter Interact
https://developers.google.com/events/flutter-interact

Flutterの追い風(?)でDartもバージョンアップが頻繁に行われ、
2018年末の最新バージョンは2.0でしたが2019年末はDart2.7になり、
コレクション機能や拡張メソッド対応など一年で様変わりしました。
DartPadというDartを気軽に試すことができるツールも登場しました。

DartPad
https://dartpad.dev/

Flutterはコンテストも多く開催し、
5月には5KBで作るFlutter Create、11月には時計を作るFlutter Clockを発表しました。
# Flutter Clockの参加締切は2020年1月20日までなのでまだ間に合います。

React NativeやFlutterのUI構築手法

React NativeやFlutterのUI構築手法はネイティブ開発に影響を与え
2019年に「Jetpack Compose」「SwiftUI」が続けて発表されています。
UIはコードベースでプレビューを確認しながら作るという手法が近くに一般化しそうです。

スクリーンショット 2020-01-17 20.31.13.png
SwiftUI

スクリーンショット 2020-01-17 20.31.13.png
Jetpack Compose

Unity

スマホ関係者はUnite 2019の基礎公演、開発者は開発ロードマップ最新情報のYouTube動画を見るのがおすすめです。
基礎公演40:00ではVR/ARや自動運転、アニメーション活用に関して、
非ゲーム分野でシミュレーターとしてのUnity活用概要があります。

Unite 2019 基礎公演
https://youtu.be/zLQ9oY08p84?t=2405

Unity開発ロードマップ最新情報では直近のUnity更新内容が紹介されています。

Unity開発ロードマップ最新情報
https://www.youtube.com/watch?v=o9EJu4LRIdY

DOTS (Data-Oriented Technology Stack)

DOTS - Unity の新しいマルチスレッド対応の Data-Oriented Technology Stack
https://unity.com/ja/dots

UnityはUnityを根幹から変える取り組みが行われており、DOTSに置き換わります。

  • Entity 1.0 (2020.1〜)
  • DOTS NetCode (2020.1〜)
  • DOTS Audio
  • DOTS Physics
  • DOTS Animation

エディタUIも再設計されビジュルスクリプティング機能もベータ公開予定。
映像向けパイプラインにはPythonサポートされます。
その他として、Serializeが進化してリファレンスがSerialize可能になりましたうれしい。

モバイル向けの変更

モバイル向けに以下がロードマップの動画内で発表されています。
Unity as a LibraryはUnityとネイティブアプリの関係性を大きく変化させそうです。

  • Project Tiny: Instant Runのような仕組みを提供。
  • Unity Distribution Portal: Apple, Google以外のプラットフォームにも複数ゲーム配信ハブシステムも提供。
  • Unity as a Library: ネイティブアプリ向けにUnityで作ったアプリをライブラリとして使用できる機能。

まとめ

2019年はだいたい以下のような感じでした(個人の感想です)

  • 2019年のスマホは決済サービスが流行(増税の影響?)
  • 2019年のスマホゲームは最大手参入と新サービス形態(Apple Arcade, Stadio)。
  • 2019年は子供向けプライバシー強化が大きく行われた
  • 2020年はとにかく5Gを中心に変化
  • ネイティブのUI開発は旧手法・新手法(SwiftUI, Jetpack Compose)・別手法(Flutter, React Native)から選択する必要あり。
  • Unityは新手法のDOTSに改装中

告知

2月のDroidKaigi 2020でビジュアルリグレッションテストについて話します。まだ資料できてません。
https://droidkaigi.jp/2020/accepted/

この記事が参考になったら「いいね」を、あとで読む場合は「ストック」を、投げ銭したくなったらPaypayで以下をおねがいします。
PNGイメージ.png

今年もよろしくおねがいいたします。

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

NeumorphismをSwiftUIで簡単に実装できるライブラリ、Neumorphismicを作ってみた

先日Neumorphism: 令和時代のスキューモーフィズムを読みました。

これが流行る頃にはSwiftUIも使えるようになってるだろう…ということでSwiftUIでNeumorphismのライブラリを作ってみました。

SwiftPMにしか対応していませんが、Xcode 11からとても使いやすくなりましたし、SwiftUIのOSSなのでこれで十分だと思います。スターつけてくださると嬉しいです!

完成形

Demoの画面です。SwiftUIということで全プラットフォームのDemoを一応作りましたが、iOS以外は図形が表示されるだけの手抜きです。
Demo view
Settings view

使い方

簡単な使い方はこんな感じです。2層目以降はZStackで背景色をつける必要もないですし、.environmentも必要ありません。下のコードだと少し複雑に見えるかもしれませんが、各Viewで増えるのは.modifier(NMConvexModifier())のみです。下のコードもSwiftUIを少し触った方ならすぐわかると思います。

struct ContentView: View {

    let baseColor = Color(hex: "C1D2EB")

    var body: some View {
        ZStack {
            baseColor
                .edgesIgnoringSafeArea(.all)

            Circle()
                .fill(baseColor)
                .frame(width: 300, height: 200)
                .modifier(NMConvexModifier())
                .environment(\.nmBaseColor, baseColor)
        }
    }
}

作り方

実際のコードとは多少違います。

ModifierでShadowを実装する

Modifierについてはこの記事でひと通りわかると思います。簡単にいうと.fontとか.frameとかをまとめてViewに適合できるやつです。
SwiftUIでもshodowは1つしか追加できません。なのでZStackViewを2つ重ねてそれぞれに.shadowをつける必要があります。

struct ConvexModifier: ViewModifier {
    let lightShadowColor: Color
    let darkShadowColor: Color
    func body(content: Content) -> some View {
        ZStack {
            content
                .shadow(color: darkShadowColor, radius: 16, x: 9, y: 9)
            content
                .shadow(color: lightShadowColor, radius: 16, x: -9, y: -9)
        }
    }
}

しかし、これだけでは影の色をいちいち入力する必要があります。

色をEnvironmentで伝搬する

SwiftUIでは@Environmentを使うことでその子View全てに値を伝えることができます。詳しくはこの記事を読んでください。
そしてこれは自作することもできます。Neumorphismでは基本的にViewに1色しか使わないためこれが非常に有効です。さらに、ConvexModifierbaseColorを基準に影の色を決めればよくなります。自作する方法はこちらをご覧ください。

struct BaseColorKey: EnvironmentKey {
    static let defaultValue: Color = .gray
}

extension EnvironmentValues {
    var baseColor: Color {
        get { self[BaseColorKey.self] }
        set { self[BaseColorKey.self] = newValue }
    }
}

さて、色を変換したいわけだけど…

パッと見、SwiftUIのColorからはrgbやhueや取得できそうにありません。しかし#C1D2EBFFのようにカラーコードを返してくれる.descriptionがあります。ということでカラーコードからColorを生成(このリンクではUIColor)できるようにし、RGBとHSLRGBとHSBの変換コードを用意します。

Colorから色情報を取れるとわかったので、早速lighterColorを実装します。

func getRGBA() -> (r: Double, g: Double, b: Double, a: Double) {
    let string = String(self.description.dropFirst())
    let v = Int(string, radix: 16) ?? 0

    let r = Double(v / Int(powf(256, 3)) % 256) / 255
    let g = Double(v / Int(powf(256, 2)) % 256) / 255
    let b = Double(v / Int(powf(256, 1)) % 256) / 255
    let a = Double(v / Int(powf(256, 0)) % 256) / 255

    return (r, g, b, a)
}

func getHSLA() -> (h: Double, s: Double, l: Double, a: Double) {
    let (r, g, b, a) = getRGBA()
    let (h, s, l) = ColorTransformer.rgbToHsl(r: r, g: g, b: b)
    return (h, s, l, a)
}

func lighter(_ value: Double) -> Color {
    let (h, s, l, a) = getHSLA()
    return Color(hue: h, saturation: s, lightness: min(l + value, 1), opacity: a)
}

func darker(_ value: Double) -> Color {
    let (h, s, l, a) = getHSLA()
    return Color(hue: hsb.h, saturation: hsb.s, lightness: max(l - value, 0), opacity: a)
}
struct ColorExtension_Previews: PreviewProvider {
    static var previews: some View {
        let color = Color(hex: "C1D2EB")

        return Group {
            ColorPreview(color)
            ColorPreview(color.lighter(0.12))
            ColorPreview(color.darker(0.18))
        }
        .previewLayout(.fixed(width: 200, height: 100))
    }
}

Colors
こうなりました。影として使わないとよくわかりませんね。

ConvexModifierを完成させる

材料は揃ったので合わせてみましょう。

struct ConvexModifier: ViewModifier {

    @Environment(\.baseColor) var baseColor: Color

    func body(content: Content) -> some View {
        ZStack {
            content
                .shadow(color: baseColor.darker(0.18), radius: 16, x: 9, y: 9)
            content
                .shadow(color: baseColor.lighter(0.12), radius: 16, x: -9, y: -9)
        }
    }
}
struct ConvexModifier_Previews: PreviewProvider {
    static var previews: some View {
        ZStack {
            Color(hex: "C1D2EB")
                .edgesIgnoringSafeArea(.all)

            Circle()
                .fill(Color(hex: "C1D2EB"))
                .modifier(ConvexModifier())
                .frame(width: 300, height: 300)
        }
        .environment(\.baseColor, Color(hex: "C1D2EB"))
    }
}

.environmentbaseColorを伝えるの忘れないようにしましょう。
Image
いい感じですね!

environmentを使ったので当然

struct ConvexModifier_Previews: PreviewProvider {
    static var previews: some View {
        ZStack {
            Color(hex: "C1D2EB")
                .edgesIgnoringSafeArea(.all)

            Circle()
                .fill(Color(hex: "C1D2EB"))
                .frame(width: 300, height: 300)
                .modifier(ConvexModifier())
                // `environment`で影の色を変える
                .environment(\.baseColor, Color.red)
        }
        .environment(\.baseColor, Color(hex: "C1D2EB"))
    }
}

とできるだろうと思っていたのですができませんでした。.redの時は黒い影が出てきて、その他の場合は影がなくなりました。Color(hex:)を使ったら行けたのでよくわかりません。

Highlight時に表示を変えられるButtonも作ってみた

ハイライト時にNeumorphismではどうするのが正解なんだろうと考えるためにとりあえず作ってみました。個人的に標準Buttonは ハイライト時に色が薄すぎる気がするのでこれを使ってますが、標準のButtonでもいい気がします。押下時にボタンを小さくしたいときなどに使ってみてください。

struct HighlightableButton<Label>: View where Label: View {

    private let action: () -> Void
    private let label: (Bool) -> Label

    public init(
        action: @escaping () -> Void,
        label: @escaping (Bool) -> Label
    ) {
        self.action = action
        self.label = label
    }

    @State private var isHighlighted = false

    public var body: some View {
        label(isHighlighted)
            .animation(.easeOut(duration: 0.05))
            .gesture(DragGesture(minimumDistance: 0)
                .onChanged { _ in
                    withAnimation { self.isHighlighted = true }
                }
                .onEnded { _ in
                    self.action()
                    withAnimation { self.isHighlighted = false }
                }
        )
    }
}
struct ConvexModifier_HighlightableButton_ForPreviews: View {
    @State var isSelected = false
    var body: some View {
        HighlightableButton(action: {
            self.isSelected.toggle()
        }) { isH in
            Image(systemName: self.isSelected ? "house.fill" : "house")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: isH ? 54 : 60)
                .foregroundColor(Color(hex: "C1D2EB").darker(value: 0.18))
                .background(
                    Circle()
                        .fill(Color(hex: "C1D2EB"))
                        .frame(width: isH ? 90 : 100,
                               height: isH ? 90 : 100)
                        .modifier(ConvexModifier())
                )
                .opacity(isH ? 0.6 : 1)
        }
    }
}

.modifier(ConvexModifier())Buttonの中に書いてください(標準のButtonでも同じです)。外に書くときちんと適用されません。ForPreviewsみたいな名前になっているのは、PreviewProviderの中には@Stateが置けないからです。
GIF

FloatingTabViewも作ってみた

@touyouさんもタブを作ってることだし作るかーみたいな感じで作ってみました。ViewBuilderを読み解こうとまでは思わなかったので(そもそもできるんですかね)、標準のTabViewのような綺麗さはありませんが、まあ使えるのではないでしょうか。タブの数は4つまでにしてみました。標準のTabViewにあるその他を実装する気力はなかったので切り捨てています。
使い方はこんな感じです。

struct FloatingTabView_ForPreviews: View {
    enum Season: String, CaseIterable {
        case spring, summer, fall, winter
        var color: Color {
            switch self {
            case .spring: return .pink
            case .summer: return .blue
            case .fall:   return .orange
            case .winter: return .white
            }
        }
    }
    @State var season: Season = .spring
    var body: some View {
        FloatingTabView(selection: $season, labelText: { s in
            s.rawValue
        }, labelImage: { _ in Image(systemName: "camera") }) { s in
            s.color.edgesIgnoringSafeArea(.all)
        }
    }
}

例を作るのが面倒なのが目に見えますね…。labelImageなんてカメラだけですし。この例では色を変えていますが、Neumorphismでは色を変えるのはご法度なので注意。(もちろん局所的にアクセントとして使うのはOKです)
Screen Shot 2020-01-12 at 20.34.46.png
ああ、影の色が汚い…。まあ色変えるとこうなるよっていう悪い例と思ってください。
ちなみにGeometryReaderのせいかLive PreviewにしていないとTabが下に落ちてしまいました。SwiftUIは7不思議どころじゃありません。そこら辺に穴が一杯です。全く理由がわからず何となくLive Previewにしてみたところ合っていたことがわかりました。恐ろしや。

凹も作りたかったけど

凹凸どちらも作りたかったのですが、凹の方はいい案が思い浮かばず、凸だけになってしまいました。適合したいaViewよりひとまわり大きいbViewを作って、そこからaViewの大きさを切り抜いて、aViewの上にbViewを2つ置いて影をつければ行けそうだなとは思ったんですが、くり抜く方法がわかりませんでした。Pathを使えば何とかなりそうですが、Viewの形を取る方法もないですし…。

使う上での諸注意

HighlightableButtonのところでも書きましたが、Buttonで使う際は.modifier(ConvexModifier())Buttonの中に書いてください。そうしないときれいに作れません。
またBinding系のコンポーネントは2つ同時にViewに存在すると使えなくなるようです。

TextField("C1D2EB", text: $model.userInput)
    .foregroundColor(baseColor.darker(0.5))
    .padding(5)
    .background(
        RoundedRectangle(cornerRadius: 5, style: .continuous)
            .fill(baseColor)
            .modifier(NMConvexModifier(radius: 9))
    )

のようにbackgroundに設定したView.modifier(ConvexModifier())してください。Viewの量的にもこちらの方がパフォーマンスもいいです。NeumorphismではViewの量が多くなりがちなので。

初OSS & 初Qiita?

cocoapodsなどにも対応したかったのですが、SwiftUIのOSSですし、自分の学ぶ量としてもSwiftPMだけで十分だろうとSPMのみになっています。それでも十分つまづきまくりましたし。
初めてのOSSなので、改善点などたくさんあると思います。もしなんかあったらTwitterなどに送ってくださると嬉しいです!(もちろんissueでも)

Qiitaも初投稿ですが、そろそろ開発から離れて受験勉強しないと浪人する未来しか見えないので当分記事を書くことはないでしょう。1年後に戻って来れるように頑張ります。

いいねとスターつけてくださると嬉しいです!
Neumorphismic - GitHub

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

iOS の Dynamic Type でテキストサイズはどのくらい変化するのか?

はじめに

iOS のアクセシビリティ機能の1つにユーザーインターフェース上のテキストサイズを自動的にスケーリングする Dynamic Type があります。

Scaling Fonts Automatically - UIKit | Apple Developer

Android ではテキストに対して Scale-independent Pixels (sp) という単位でのサイズ指定するのとは異なり、テキストに対して Header, Body のような用途別のスタイルで指定するのが特色です。

そのため、ユーザーのサイズ設定に応じて各スタイルのフォントサイズがどのように変化するのかが想像しにくいため、サンプルアプリを作って見た目と数値で確認できるようにしてみました。

サンプルアプリ

サンプルアプリのリポジトリはこちらです。

temoki/UIKit_DynamicType - GitHub

アプリを起動すると、デバイスの現在の設定に応じてカテゴリ別にテキストとそのサイズが表示されます。

app_screenshot.png

フォントサイズを決める変数

UIContentSizeCategory

UIContentSizeCategory - UIKit | Apple Developer Documentation

ユーザーが iOS のアクセシビリティ設定で変更可能なテキストサイズのカテゴリです。「さらに大きな文字」を ON にすると、最大 12 段階でサイズを変更できることになります。

さらに大きな文字 OFF
app_screenshot.png

さらに大きな文字 ON
app_screenshot.png

name case rawValue
XS .extraSmall "UICTContentSizeCategoryXS"
S .small "UICTContentSizeCategoryS"
M .medium "UICTContentSizeCategoryM"
L .large "UICTContentSizeCategoryL"
XL .extraLarge "UICTContentSizeCategoryXL"
XXL .extraExtraLarge "UICTContentSizeCategoryXXL"
XXXL .extraExtraExtraLarge "UICTContentSizeCategoryXXXL"
A11yM .accessibilityMedium "UICTContentSizeCategoryAccessibilityM"
A11yL .accessibilityLarge "UICTContentSizeCategoryAccessibilityL"
A11yXL .accessibilityExtraLarge "UICTContentSizeCategoryAccessibilityXL"
A11yXXL .accessibilityExtraExtraLarge "UICTContentSizeCategoryAccessibilityXXL"
A11yXXXL .accessibilityExtraExtraExtraLarge "UICTContentSizeCategoryAccessibilityXXXL"

UIFont.TextStyle

UIFont.TextStyle - UIFont | Apple Developer Documentation

UIKit の各種コントロールに設定するテキストスタイルです。

name case rawValue
Large Title .largeTitle "UICTFontTextStyleTitle0"
Title 1 .title1 "UICTFontTextStyleTitle1"
Title 2 .title2 "UICTFontTextStyleTitle2"
Title 3 .title3 "UICTFontTextStyleTitle3"
Headline .headline "UICTFontTextStyleHeadline"
Subhead .subheadline "UICTFontTextStyleSubhead"
Body .body "UICTFontTextStyleBody"
Callout .callout "UICTFontTextStyleCallout"
Footnote .footnote "UICTFontTextStyleFootnote"
Caption1 .caption1 "UICTFontTextStyleCaption1"
Caption2 .caption2 "UICTFontTextStyleCaption2"

テキストサイズの変化

UIContentSizeCategory と UIKit.TextStyle の組み合わせによるフォントサイズを表にまとめてみました。

XS S M L XL XXL XXXL A11yM A11yL A11yXL A11yXXL A11yXXXL
Large Title 31 32 33 34 36 38 40 44 48 52 56 60
Title 1 25 26 27 28 30 32 34 38 43 48 53 58
Title 2 19 20 21 22 24 26 28 34 39 44 50 56
Title 3 17 18 19 20 22 24 26 31 37 43 49 55
Headline 14 15 16 17 19 21 23 28 33 40 47 53
Subhead 12 13 14 15 17 19 21 25 30 36 42 49
Body 14 15 16 17 19 21 23 28 33 40 47 53
Callout 13 14 15 16 18 20 22 26 32 38 44 51
Footnote 12 12 12 13 15 17 19 23 27 33 38 44
Caption1 11 11 11 12 14 16 18 22 26 32 37 43
Caption2 11 11 11 11 13 15 17 20 24 29 34 41

グラフにもしてみました。

スクリーンショット 2020-01-17 14.33.46.png

「さらに大きな文字」が ON の場合に想像以上に大きなフォントサイズになることがわかりますね。この状態でもレイアウトが破綻しないアプリを作るのはなかなか大変そうです?


この記事では Xcode 11.3 と iOS 13.3 シミュレータで確認した結果を掲載しています。

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

(swift)画像のデータサイズを縮小する方法(UIImage)

方法

UIGraphicsImageRendererを使用することで、画像のデータサイズを変更することができます。

以下のExtensionを使用することで、resizedメソッドが使えます。
(参考: https://stackoverflow.com/questions/29137488/how-do-i-resize-the-uiimage-to-reduce-upload-image-size)

extension
extension UIImage {
    //データサイズを変更する
    func resized(withPercentage percentage: CGFloat) -> UIImage? {
        let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
        return UIGraphicsImageRenderer(size: canvas, format: imageRendererFormat).image {
            _ in draw(in: CGRect(origin: .zero, size: canvas))  
        }
    }
}
使用例
var usersImage = UIImage()
//ここでは、UIImagePickerControllerを使用しています。
let pickerImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage

//pickerで取得したUIImageのサイズを90%カットする。
let resizedImage = pickerImage?.resized(withPercentage: 0.1)

//usersImageに代入する
usersImage = resizedImage

UIGraphicsImageRendererとは?

A graphics renderer for creating Core Graphics-backed images.
(和訳: Core Graphics-backed画像を作成するためのグラフィックスレンダラー。)
(引用: https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer)

Core Graphicsとは?

Quartzテクノロジーのパワーを活用して、高忠実度の出力で軽量の2Dレンダリングを実行します。パスベースの描画、アンチエイリアスレンダリング、グラデーション、画像、カラーマネジメント、PDFドキュメントなどを処理します。
(引用: https://developer.apple.com/documentation/coregraphics)

Quartzとは?

ユーザーがスライドショーとCore Imageフィルターを使用して、画像を閲覧、編集、保存できるようにします。
(引用: https://developer.apple.com/documentation/quartz)

つまり?

UIGraphicsImageRendererは、Core GraphicsフレームワークとQuartzフレームワークを使用して、画像(UIImage)の作成や編集を実行します。

引用文献(スペシャルサンクス)

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