すわりんのブログ

androidとかサブカルとかのブログです

BottomSheetカスタムあれこれ

supportLibraryにBottomSheetDialogFragmentというのがあります。 これは下からスッと出てくるダイアログもどきで コンテンツの共有やGoogleMapアプリなどで使われています。

このBottomSheetDialogFragmentを使用する際 独自の動作部分をカスタマイズ出来るのでメモ代わりに残します。

以下の記事を参考にしました。 http://qiita.com/napplecomputer/items/5b3d1225533a59488ac3#bottomsheet%E3%81%AE%E8%A1%A8%E7%A4%BA%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B

表示後STATE_EXPANDED(全て表示)にしたい!

通常は一部分のみ表示され、上へスワイプすることで全域を見ることが出来るが 初めから全域を表示させたい時。

onCreateDialogをOverrideし setOnShowListenerでStateをEXPANDEDに変える

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.setOnShowListener {
            val d = dialog as BottomSheetDialog
            val bottomSheet = d.findViewById(android.support.design.R.id.design_bottom_sheet) as FrameLayout
            
            val behavior = BottomSheetBehavior.from(bottomSheet)
            behavior.state = BottomSheetBehavior.STATE_EXPANDED
            
        }
}
            

COLLAPSEDを無効にしたい!

一部分のみ見えてる状態をなくしたい時。 EXPANDEDと組み合わせると全画面ダイアログになります。 DialogFragmentでやれ

やっぱりonCreateDialogをoverrideし BottomSheetCallbackを設定する

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.setOnShowListener {
            val d = dialog as BottomSheetDialog
            val bottomSheet = d.findViewById(android.support.design.R.id.design_bottom_sheet) as FrameLayout
            
            val behavior = BottomSheetBehavior.from(bottomSheet)
            behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                override fun onSlide(bottomSheet: View, slideOffset: Float) {

                }

                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    //Drag,Collapsedの時はExpandedにする
                    if (newState == BottomSheetBehavior.STATE_DRAGGING || newState == BottomSheetBehavior.STATE_COLLAPSED) {
                        behavior.state = BottomSheetBehavior.STATE_EXPANDED
                    }
                }
            })
            
        }
}

[所要時間:8分]

3回調べたらメモに残そう

コードを書く上でparcelableの実装とかdrawableで使用できるタグとか ちょっとしたことだけどそのたびにググってることは結構あると思う。 そういったのはメモに残していつでも取り出せるようにしておくと便利。 そのメモを元にブログの記事に出来たりするし。 (このブログが荒いのはメモが元なのもある)

自分はQuiverというメモアプリに残して書き溜めてます。

happenapps.com

FreeTrial版もあるのでまずはお試しすることをオススメします。

メモを残す上で大事なのは検索性を考えること。 タグや本文にできるだけヒットする単語を仕込んでおきましょう。 でないと肝心な時に取り出せないで結局調べ直す羽目になる。

[所要時間:10分]

FCMの疎通テスト

Firebaseネタ。

Firebase Notificationsで通知のテストを行いたい時 手元のターミナルからリクエストを送れば ちゃんと送信されます。 これは送る型は決まっているがバックエンドが間に合ってないときや 送る条件を満たすのが煩雑な時に役に立ちます。(やりたいことは通知を受取適切に処理しているか、なので)

使えるパラメーターは以下を参考にして下さい。 https://firebase.google.com/docs/cloud-messaging/http-server-ref#-http-json

またAuthorizationのValueはFirebaseCPから取得してください。

以下curlとhttpieのコマンドです。 data部分にペイロードを記述します。

curl

curl --header "Authorization:key=abcdefg12345678" --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send -d '{"to":"端末のID"}' '{"data":{"score":"3x1"}}'

httpie

http -v POST https://fcm.googleapis.com/fcm/send Authorization:key=abcdefg12345678 to=端末のID data={"score":"3x1"}

(ペイロードがちょっと怪しいかも間違ってたらすみません)

[所要時間:10分]

Launcherを複数持つ

androidのちょっとした小ネタ。 開発中では何度も同じ画面を行き来することになるが 階層が深くなると時間のロスも出てきて勿体無い。

そこでAndroidManifest内のActivityタグに intentFilterを記述すれば、そのActivityから立ち上げる事が出来るので 時間の節約になるし動作テストも快適になる。 ただしリリース時には必ず消すこと。

<application>
~~~~~
  <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter android:label="@string/app_name">
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>[f:id:suwashimizu:20171121094101p:plain]

        <activity
            android:name=".SubActivity"
            android:screenOrientation="portrait"
            android:label="SampleTest">
            <intent-filter android:label="@string/app_name">
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
  </application>

2つのLauncherを持つことができた

f:id:suwashimizu:20171121094101p:plain

[所要時間:12分]

あなたはJavaでオブジェクト指向開発ができないのかを読んだよ

寝る前にコツコツと読みました。

なぜ、あなたはJavaでオブジェクト指向開発ができないのか―Javaの壁を克服する実践トレーニング

なぜ、あなたはJavaでオブジェクト指向開発ができないのか―Javaの壁を克服する実践トレーニング

オブジェクト指向って?から始まり 中盤からはじゃんけんゲーム・トランプゲームを題材にして オブジェクト指向(以降OOP)について学ぶ内容。

javaを学びながらOOPではなく、javaの基本が分かってる人向け。 なのでプログラミング始めました!って人が最初に読む本ではなく ある程度作れるようになったけどソースコードがスパゲッティ スッキリ書けないと悩んでる人やOOPについて再考したい人向け。

全体を把握する必要性や、抽象化への落とし込みの手順について書かれているので これからの考えをまとめるのに役立ちそう。 OOPは現実をモデリングするが必ずしも現実と合わせる必要はないのは確かになあと思った。 例えばじゃんけんゲームではゲームマスタークラスとプレイヤークラスを作成するが 勝利を宣言するのはプレイヤークラスの責務で 審判は勝利宣言を受け取るだけ。 普通に作ると審判側で勝利の判定を行ってしまいそうだが 確かにプレイヤーで宣言したほうが分かりやすい。 プログラムは嘘つかないから虚偽宣言とか考えなくて良いわけだ。

最終章はトランプゲームのフレームワーク作りだったので これを元に派生するトランプゲームを作るのも面白そう。 大富豪とか大富豪とか

同じジャンルの本を纏めて読むと学習効率良いとのことなので 他にも読んでみようかな

RxでHotObservableとFilter

RxにはHotObservableとColdObservableがある。 HotObservableについてはそんなもんなあるなーぐらいで 実際に使う機会がなく、あまり理解できてなかった。

rxの使用用途がretrofitを介してのAPIとのやりとりが主だったのも大きい。

んで触る必要が出てきたのでどう動くのかテストしてみた所

    @Test
    fun filterTest() {

        val publisher = PublishSubject.create<String>()

        publisher.onNext("abc")
        publisher.onNext("777")

        //数値のみを出力する
        val numberObserver = publisher.filter {
            try {
                it.toInt()
                true
            } catch (e: NumberFormatException) {
                false
            }
        }.map(String::toInt)

        //10文字以上の文字列を出力する
        val longTextObserver = publisher.filter {
            it.length >= 10
        }

        longTextObserver.subscribe(this::printText)
        numberObserver.subscribe(this::printNum)

        publisher.onNext("123")

        publisher.onNext("BBB")

        publisher.onNext("BBBBBBBBBBBBBBBBBBBBBBBB")
        publisher.onNext("1111111111")
        publisher.onNext("11111111111111111111111111111111")
    }

    fun printNum(num: Int) {
        println("num:$num")
    }

    fun printText(text: String) {
        println("text:$text")
    }

結果がこれ

output

num:123
text:BBBBBBBBBBBBBBBBBBBBBBBB
text:1111111111
num:1111111111
text:11111111111111111111111111111111

HotObservable#onNext(value)で値を流す。 HotObservable#subscribeした後から流した値が受け取れる。: abc,777は出力されない。 HotObservable#filterやmapなどで別のObservableを生成することが出来る。: numberFilterやlongTextFilterがそれ HotObservable#filterで生成したObservableをSubscribeすれば特定のフィルタリングした値だけを受け取れる。 ちなみにちゃんと購読解除処理書かないと参照持ち続けるので注意しよう。

ということはjsonを受け取って、様々な型に変換し特定の型だけ流すObservableも生成できるということか! この辺は本で読んだけだったので理解が深まった。 触らないとダメやね。