22時に寝ようと思って2時に寝る。

備忘録や日記を書いてます。きょうは早く寝よう。

UIが消えて何もしなくてよくなっていく

最近読んだ2つの記事がつながって、「なるほど」と腑に落ちた。

サービス開発において「ユーザーがしたいことをできるようにさせてあげる」という議論は活発だが、いっぽうで「しなくていいことをしないようにさせてあげる」分野はまだまだ発展途上だと思う。 (中略) システムで吸収してあげれば、人間がしなくていいことはまだまだある。

しなくていいUX|小山田翔子 / GMOペパボ|note

つまり・・・

UIとかUXとか、サイコーな状態になると、使ってる側はまったくその存在を気にしなくなるのだ。

UIがサイコーになるとUIは消える|米光一成|note

サイコーな状態のUXは、「しなくていいことをしないようにさせてあげる」分野が発展していくと、徐々に増えていく。ユーザーが「しないようにさせてあげられる」システムを作れるようになりたい。

引用した記事

note.mu

note.mu

デザイン - 信頼感を持たせる色・透明感のあるデザイン

今回は、「信頼感を持たせる配色」「透明感がある配色」に着目して、カラーコードと色見本を見ていきます。

信頼感が生まれる配色

f:id:azuuun:20180917222830p:plain

一般的に、信頼・冷静といった印象を与える色は青系、安心感を与えるのは緑系の色だと言われています。

色の数を少なくナチュラルな印象

f:id:azuuun:20180917222954p:plain

冷静な印象を与える

f:id:azuuun:20180917223032p:plain

意欲的な赤色を添える

f:id:azuuun:20180917223058p:plain

緑をメインに安定感を与える

f:id:azuuun:20180917223124p:plain

参考

デザイン - 色の持つイメージ

色について

色というのは、人によって違ったイメージを持つもので、その人の経験や住んでいる国、その土地にある文化によって変化する。色によるイメージをポジティブ・ネガティブの2つの視点からまとめ、それに適した領域を以下に示す。

f:id:azuuun:20180917190404p:plain

ポジティブイメージ
  • 情熱
  • 愛情
  • 勝利
  • 積極的
  • 衝動
ネガティブイメージ
  • 危険
  • 怒り
  • 争い
適したサイト
  • 飲食
  • キャンペーン

f:id:azuuun:20180917190917p:plain

ポジティブイメージ
  • 明るい
  • 活発
  • 幸運
  • 躍動
  • 希望
ネガティブイメージ
  • 臆病
  • 裏切り
  • 警告
適したサイト
  • 食品
  • スポーツ

f:id:azuuun:20180917190925p:plain

ポジティブイメージ
  • かわいい
  • ロマンス
  • 若い
ネガティブイメージ
  • 幼稚
  • 繊細
  • 弱い
適したサイト
  • ブライダル
  • 女性向けのサイト

f:id:azuuun:20180917190937p:plain

ポジティブイメージ
  • 親しみ
  • 陽気
  • 家庭
  • 自由
ネガティブイメージ
  • わがまま
  • 騒々しい
  • 軽薄
適したサイト
  • コミュニティー
  • 飲食
  • キッズ

f:id:azuuun:20180917190946p:plain

ポジティブイメージ
  • 高級
  • 神秘
  • 上品
  • 優雅
  • 伝統
ネガティブイメージ
  • 不安
  • 嫉妬
  • 孤独
適したサイト
  • ファッション
  • ジュエリー
  • 占い

f:id:azuuun:20180917190952p:plain

ポジティブイメージ
  • ぬくもり
  • 自然
  • 安心
  • 堅実
  • 伝統
ネガティブイメージ
  • 地味
  • 頑固
  • 汚い
適したサイト
  • ホテル
  • 旅館
  • インテリア
  • クラシック
  • レトロなサイト

f:id:azuuun:20180917191001p:plain

ポジティブイメージ
  • 知性
  • 冷静
  • 誠実
  • 清潔
ネガティブイメージ
  • さみしさ
  • 冷たい
  • 悲しさ
  • 臆病
適したサイト
  • コーポレート
  • 医療
  • 化学

f:id:azuuun:20180917191012p:plain

ポジティブイメージ
  • 祝福
  • 純粋
  • 清潔
  • 無垢
ネガティブイメージ
  • 空虚
  • 殺風景な
  • 冷たい
適したサイト
  • 医療
  • ニュース
  • EC
  • 美容
  • コーポレート

f:id:azuuun:20180917191024p:plain

ポジティブイメージ
  • 自然
  • 平和
  • リラックス
  • 若さ
  • エコ
ネガティブイメージ
  • 保守的
  • 未熟
適したサイト
  • アウトドア
  • 食品

f:id:azuuun:20180917191047p:plain

ポジティブイメージ
  • 実用的
  • 穏やか
  • 控えめ
ネガティブイメージ
  • あいまい
  • 疑惑
  • 不正
  • 無気力
適したサイト
  • 工業
  • 家電
  • ファッション

黄緑

f:id:azuuun:20180917191108p:plain

ポジティブイメージ
ネガティブイメージ
  • 未熟
  • 子供っぽい
適したサイト
  • 新生活
  • 新年度
  • 先進的なサイト

f:id:azuuun:20180917191057p:plain

ポジティブイメージ
  • 高級
  • エレガント
  • 洗練
  • 一流
  • 威厳
ネガティブイメージ
  • 恐怖
  • 不安
  • 絶望
適したサイト
  • ジュエリー
  • ファッション

参考

iOS - AppExtensions Today の概要

前提としてToday ウィジェットは以下のように動作することを期待しています。

  • 常に最新の情報が表示される
  • ユーザーの操作に的確に応答する
  • 効率よく動作する(特に iOS 向けウィジェットはメモリを浪費すると強制終了させられる)

簡潔に、きびきびと動作することを期待される上、成約も多いので合理的なUI設計が求められますし、対話的に操作する要素は最小限に留める必要があります。特に iOS の場合は、キーボード入力はできないという特徴があります。

また、Today のウィジェット内でスクロール要素をもたせるのは困難です。なぜなら Today ウィジェット自体がスクロールする仕様のため、個別のウィジェット内でスクロールするのはユーザーフレンドリーではないためです。

UI を設計する

ビューのレイアウトには AutoLayout を使用しましょう。Today ビューが占める面積は限られており、着目する情報を迅速に表示する必要があるので、必要以上に大きなウィジェットは避けましょう。 ビューの幅に合わせる必要がありますが、高さは表示内容に応じて調整できます。

内容を更新する

Today の拡張ポイントには、ウィジェットの状態を管理して、内容を更新するためのAPIが用意されています。

ウィジェットが常に最新の状態であることが期待されているので、システムは随時、ビューのスナップショットを取得しようとします。ウィジェットが一旦消えて、再び可視化状態になると、直近のスナップショットを一旦表示した上で、最新のビューに置き換わるように動作します。

スナップショットの取得前にウィジェットの内容を確認するにはNCWidgetProvidingプロトコルに従い、処理します。ウィジェットwidgetPerformUpdateWithComletionHandler:が呼び出されたら、ビューを最新の内容に更新して、完了ハンドラを呼び出すことで、状態を管理します。

完了ハンドラ、次のいずれかの定数を渡します。

  • NCUpdateResultNewData: 内容が入れ替わったのでビューの再描画の必要がある
  • NCUpdateResultNoData: 内容が同じなので更新は不要
  • NCUpdateResultFailed: 更新処理中にエラーが起きた

参考

developer.apple.com

RxJava - BackpressureStrategy の種類

今回は Backpressure の挙動を指定するための列挙型、BackpressureStrategy について見ていきます

BackpressureStrategy とは

Flowable は場合によって生成スピードが Subscribe の処理速度以上に速い場合があります。そういった場合は、データは通知されるのを待つことになります。その待つデータに関する挙動を指定するのが BackpressureStrategy です。

BackpressureStrategy の種類一覧

概要
BUFFER 消費者に通知されるまで、すべてのデータがバッファされる
DROP 消費者にデータが通知できるようになるまでに生成されたデータを破棄する
LATEST 生成された最新のデータ(1件)のみをバッファし、生成される度に最新のデータで上書きする
ERROR 通知待ちとなっているバッファデータが最大バッファサイズを超えた場合に MissingBackpressureException が発生し、エラー通知する
NONE 処理は行わず、onBackpressureBuffer(int capacity) または 他のパラメータ化された onBackpressureXXX メソッドを使用する場合に使用可能

参考

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJava - IntelliJ IDEA で RxJava の環境構築

実際に RxJava のサンプルコードを書いていく上での環境を構築していきます。今回はエディタとして IntelliJ IDEA を用います。

www.jetbrains.com

動作確認環境

  • OS: macOS High Sierra 10.13.6
  • IntelliJ IDEA: 2018.2.1 (Ultimate Edition) Build #IU-182.3911.36
  • JRE: 1.8.0_152-release-1248-b8 x86_64
  • JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o

環境構築

今回導入する RxJava のバージョンは記事執筆時点で最新の 2.2.0 です。

Release 2.2.0 · ReactiveX/RxJava · GitHub

IntelliJ IDEA で新たにプロジェクトを作成する

  • 起動後の Welcome to IntelliJ IDEA 画面にて、+ Create New Projectを選択

f:id:azuuun:20180818223403p:plain

  • サイドメニューから Gradle を選び、Next で次へ

f:id:azuuun:20180818223330p:plain

  • Project SDKについて聞かれた場合は IntelliJ IDEA 側でよしなにやってくれていると思いますので、そのとおり進めてください
  • GroupId, ArtifactId, Versionについて
    • https://improve-future.com/what-are-groupid-artifactid.html でわかりやすく説明されています
    • GroupId はプロジェクトを一意に識別できるもので com.example.azuuun.rxjava といったフォーマットで入力
    • ArtifactId は任意のプロジェクト名 RxJavaPlayground といったものを入力
    • Version はデフォルトでよいと思います
  • 次の画面の module の設定画面はデフォルトで進めて問題ないです
  • ProjectName などは先程設定した ArtifactId がデフォルトで設定されていますが、適当に名前を入力します

Gradle でライブラリを適用する

f:id:azuuun:20180818224704p:plain

  • プロジェクトが作成された後、build.gradle ファイルを開きます
  • dependenciescompile 'io.reactivex.rxjava2:rxjava:2.2.0'追記
  • ファイル右上に Enabled Auto-Import といった表示があればクリックします
  • 正常に導入されるかを確認

サンプルコードを書いてみる

HelloRxJavaというファイルを作成し、以下のコードを書いて実行してみましょう。

import io.reactivex.*;
import io.reactivex.schedulers.Schedulers;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

public class HelloRxJava {
    public static void main(String[] args) throws Exception {

        Flowable<String> flowable =
                Flowable.create(new FlowableOnSubscribe<String>() {
                    @Override
                    public void subscribe(FlowableEmitter<String> emitter) throws Exception {
                        String[] datas = { "Hello, RxJava", "こんにちは、RxJava" };
                        for (String data : datas) {
                            if (emitter.isCancelled()) {
                                return;
                            }

                            // データを通知する
                            emitter.onNext(data);
                        }

                        // 完了したことを通知する
                        emitter.onComplete();
                    }
                }, BackpressureStrategy.BUFFER);

        flowable.observeOn(Schedulers.computation())
                .subscribe(new Subscriber<String>() {

                    private Subscription subscription;

                    // 購読を開始したときの処理
                    @Override
                    public void onSubscribe(Subscription s) {
                        // Subscription を Subscriber 内で保持
                        this.subscription = s;
                        // 受け取るデータ数の要求
                        this.subscription.request(1L);
                    }

                    // 通知を受け取ったときの処理
                    @Override
                    public void onNext(String data) {
                        String threadName = Thread.currentThread().getName();
                        System.out.println(String.format("%s: %s", threadName, data));

                        // 次に受け取るデータのリクエスト
                        this.subscription.request(1L);
                    }

                    // エラー通知を受け取ったときの処理
                    @Override
                    public void onError(Throwable t) {
                        t.printStackTrace();
                    }

                    // 完了通知を受け取ったときの処理
                    @Override
                    public void onComplete() {
                        String threadName = Thread.currentThread().getName();
                        System.out.println(String.format("%s: 完了しました", threadName));
                    }
                });

        Thread.sleep(500L);
    }
}

以下のような出力が出れば、環境は正常に構築できています。

RxComputationThreadPool-1: Hello, RxJava
RxComputationThreadPool-1: こんにちは、RxJava
RxComputationThreadPool-1: 完了しました

以上です。

次の記事

azunobu.hatenablog.com

参考

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJava - Cold および Hot な生産者(Flowable / Observable)

今回は、生産者(Publisher)は大きく分けて Cold と Hot の2つに分類することができます。それら2つについて説明してきます。

Cold な生産者

f:id:azuuun:20180818180031p:plain

  • Cold な生産者は 1つの消費者とのみ購読関係を結ぶ
  • 1つの消費者と購読関係を結ぶ度にデータを通知するためのタイムラインを生成する

Hot な生産者

f:id:azuuun:20180818181001p:plain

  • Hot な生産者は 複数の消費者と購読関係を結ぶ
  • 既に生成しておいたタイムラインに対して購読関係を結んだ消費者が後から加わるかたち

購読のタイミング

  • Cold な生産者に対する購読は、購読開始時点で生産者側でデータの生産が開始される
  • Hot な生産者に対する購読は、購読を開始したといっても生産者側でデータが生成されるとは限らない
  • Hot な生産者を購読する場合、途中からのデータを通知される可能性もあるため、複数の購読者が同じデータを受け取れるとは限らない

RxJava での Cold / Hot な生産者

  • 基本的に生成メソッドで作られる生産者は Cold な生産者である
  • Hot な生産者をつくるには Cold な生産者を作ってから Hot な生産者へと変換するメソッドを呼んで変換するか、 Processor や Subject をつくる
  • Hot な Flowable / Observable として ConnectionFlowable / ConnectionObservable がある
    • Cold な Flowable / Observable を Hot な生産者に変換するメソッドを呼ぶと 上記2つが生成される

次の記事

azunobu.hatenablog.com

参考

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJavaリアクティブプログラミング (CodeZine BOOKS)