20191230のAndroidに関する記事は6件です。

[Android]カスタムビューの作り方 (複合コンポーネント)

はじめに

Android では公式にあるとおりカスタムビューを作成する方法が何パターンかあります。
今回は複合コンポーネントを作成してみたので作成方法をまとめたいと思います。

名称 説明
フルカスタムコンポーネント Viewを継承していちから新たなコンポーネントを作成するパターン
複合コンポーネント 既存のコンポーネントを複数組み合わせて新たなコンポーネントを作成するパターン

mermaid.png

今回は次のような3つのボタンをまとめ、選択したボタンのテキストが
赤く表示される複合コンポーネントを作成したいと思います。

Dec-30-2019 20-05-56.gif

1. Containerクラスを継承する

複合コンポーネントを作成するためには、まずどのContainerクラスを継承するか決めます。
今回はLinearLayoutを利用するので次のように実装します。

SelectorView.kt
class SelectorView(context : Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) 

このようにLinearLayoutを継承したクラスを定義するとレイアウトでSelectorViewを記述できるようになります。

main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

    <kaleidot725.customviewsample.SelectorView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</FrameLayout>

2. 複数のコンポーネントを組み合わせたレイアウトを作成して読み込む

次に複合コンポーネントで読み込むレイアウトを作成します。
3つのボタンを並べた複合コンポーネントを作成したいので、
次のようにmergerの中に3つButtonを入れたレイアウトを作成します。

selector_view.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:id="@+id/one"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="1"/>

    <Button
        android:id="@+id/two"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="2"/>

    <Button
        android:id="@+id/three"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="3"/>
</merge>

そして複合コンポーネントでView.inflateを利用して読み込めば
複数のコンポーネントを組み合わせたカスタムビューを実装できます。

SelectorView.kt
class SelectorView(context : Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
    init {
        View.inflate(context, R.layout.selector_view, this)
    }
}

3. 複数のコンポーネントを組み合わせて処理を実装する。

レイアウトで定義した複数コンポーネントを制御する処理を実装し、
独自の複合コンポーネントならではの制御ができるようにします。
次のように選択したボタンのテキスト色を変え、他のボタンのテキスト色を戻す処理を実装してみます。

class SelectorView(context : Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {

    val oneButton : Button
    val twoButton : Button
    val threeButton : Button

    init {
        View.inflate(context, R.layout.selector_view, this)

        oneButton = findViewById(R.id.one)
        twoButton = findViewById(R.id.two)
        threeButton = findViewById(R.id.three)

        oneButton.setOnClickListener {
            oneButton.setTextColor(Color.RED)
            twoButton.setTextColor(Color.BLACK)
            threeButton.setTextColor(Color.BLACK)
        }

        twoButton.setOnClickListener {
            oneButton.setTextColor(Color.BLACK)
            twoButton.setTextColor(Color.RED)
            threeButton.setTextColor(Color.BLACK)
        }

        threeButton.setOnClickListener {
            oneButton.setTextColor(Color.BLACK)
            twoButton.setTextColor(Color.BLACK)
            threeButton.setTextColor(Color.RED)
        }
    }
}

Dec-30-2019 20-05-56.gif

*. なぜmergerを使うのか?

mergerですが無駄なViewを生成しないために利用しています。
例えばmergerLinearLayoutに置き換えたレイアウトを
複合コンポーネントで読み込むと次の構造でViewが生成されてしまいます。

mermaid.png

ですがmergerを利用すると次の構造でViewが生成されるので無駄にViewを生成を避けられます。
無駄に
Viewを生成するとUIパフォーマンスの低下に繋がるのでmerger`を利用したほうがよいです。

mermaid.png

おわりに

今回作成したサンプルは次にまとめています。
なので必要に応じて閲覧していただければと思います。

参考文献

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

35歳未経験でエンジニアになった自分がこの一年でやったこと

はじめに

35歳定年説、という言葉があります。
文字通りエンジニアの定年は35歳までであるという意味ですが、逆に私は35歳で実務未経験からエンジニアという道に踏み込みました。

転職から約一年が経ったので、この一年の振り返りの意味も込めて記事を投稿します。

この記事の目的

  • 未経験からエンジニアへ転進しようとしている人の応援がしたい!
  • プログラム初心者に「こんなクソ雑魚でもエンジニアになれるんだ!」と希望を与えたい!

誰?

@m-coder と申します。2018年10月よりAndroidアプリエンジニアをやっております。使用言語はKotlinです。

経歴

(多少ぼかしが入っています)
学歴はほぼです。高卒です。理系ですらないです。
職歴はアルバイト生活ののち、3年ほど事務職でExcelマクロをしこしこ組んでいました。
いろいろあって去年の10月に今の会社へ転職し、実務未経験からAndroidエンジニアになりました。

入社前のプログラミングスキル

高校の頃からぼんやりと「プログラミングでゲームとか作れたら楽しそうだなあ」と思いつつC言語をかじってお決まりのようにポインタで挫折してみたり、VBでじゃんけんゲームを作って遊んでみたりしていました。

といっても「趣味でプログラム組んでます」と言えるほどの実力もなく、せいぜい画面一個の、2、3時間もあれば組めるようなアプリを数個作ってみたことがあるぐらい、という程度のプログラミングスキルでした。
クラス?オブジェクト指向?なにそれおいしいの?

今できること

アーキテクチャはクリーンアーキテクチャ、MVVMを経験しました。
当たり前ですがプロジェクトはGit管理です。
Androidの主要なライブラリ(Retrofit2、OkHttp3、RxJava(RxAndroid、RxKotlin)、Dagger2、Realm、Glide、Picasso、Data Binding、Android Architecture Components etc...)をとりあえず一通り使った、ぐらいの経験値を積みました。
テストはユニットテストやUIテストを少し書いた経験がありますが、まだまだ本格的に導入はできていません。
今はKotlin Coroutineを勉強中です。CircleCIやfastlaneを使った連携も機会があれば勉強したいと思っています。
デザインパターン? あーそーゆーことね完全に理解した。

一年間でやったこと

入社前のスキルを見てもらうと分かるように、とにかくプログラマーとしてはミジンコレベルです。
なんなら情報系の学部で学んだ新卒一年目の後輩に知識で負けます。
記憶力も当たり前のように落ちてきており危機感がハンパないです

そんな感じに口が裂けても「エンジニアです」とは言えなかった自分が、一年で「エンジニアです(小声)」と言えるようになるまでにやったことを書いていきます。

技術系全般の勉強方法

アーキテクチャなど、技術系全般の知識を身に付けるためにした勉強です。

技術系の記事に日常的に触れる

QiitaStack Overflowをはじめとして、一日一回は技術系の情報に触れるようにしました。
私の場合は少しでも気になった記事はPocketに記事をストックしておき、時間が空いた時などに眺めていました。
ふとした時に「あれはこういう意味だったのか!」と気付いたりすることもあるため、意味がわからなくても、とりあえずストックする、というスタンスをとっています。

他人のソースコードを読む

おそらく先達のエンジニアの方々が百万遍ぐらい言っている事だと思いますが、自分でやってみても一番費やす時間が多く、一番学びも多かったのがこれです。
自分が関わったプロジェクト・関わってないプロジェクト・OSSなど、とにかくソースコードを読んで実行してブレークポイント設定して値がどう変わるか見て…というのを繰り返しました。

他人のソースを読むことによって
1. アルゴリズムなど、自分にはない発想の気づきになる → 自分の引き出しが増える!
2. 実装に不安を感じている部分の答え合わせになる(かも)
などのメリットがあります。

ただ、これ(他人のソースコードを読むこと)が普通に出来るようになったのはここ3ヶ月ぐらいで、それまでは読んでも「なるほど、わからん」となっていた事の方が多いです。
非常に勉強にはなりますが、初心者のうちはハードルが高い学習方法だというのも事実だと思います。

手を動かす&わからないところはググる

当たり前の話で申し訳ないのですが、やはりプログラムはある程度自分で書かないと身につきません。
しかも私はクソ雑魚ですが職業エンジニアですので、期日内に動くアプリを提供しなければなりません。
どんなクソコードでもいいからとにかく動くものをと、ひたすら書いて、ビルドして、アプリをクラッシュさせて半泣きで修正するのを繰り返しました。Logcatはいいお友達です。

そしてエンジニアに重要だなと実感したのはググり力です。
抱えている問題を解決するコードをいかに早く見つけ出すかはものすごく重要で、正直動けばコピペでも良いと思います
ググり力さえ身につければあなたももうエンジニアです。 ※個人の感想です

Android関連の勉強

Android、Kotlinの知識を身に付けるためにした勉強です。

Kotlin助走教本を読む

有志の方がまとめられたKotlin助走教本を3周ほど読みました。
導入部分などは今となっては少し古くなっていますが、Kotlinの基礎的な情報がまとめられており、今でも充分ためになります。

公式リファレンスをざらっと読む

Kotlin公式 ※日本語訳サイトあり 
のリファレンスになんとなく目を通しました。最初に全部読もうとしたりすると心が折れるので、ざっくりと流し読んだあとは文法に詰まったりした時に参照する、という利用方法です。

カンファレンスのスライドを読む

少し知識が身についたら、DroidKaigiなどのセッションで発表されたスライドをガンガン読みました。
DroidKaigi 2019 スライドまとめ
DroidKaigi 2018 スライドまとめ
DroidKaigi 2017 スライドまとめ(1日目)
Kotlin Fest 2019 スライド一覧
Kotlin Fest 2018 資料一覧
スライドの良いところは、最新の技術のキャッチアップが出来るという点です。

「いまこういう技術が流行っている」「最新バージョンでこんな機能が追加された」といった情報は書籍等では得られにくいので、カンファレンス資料を追いかけるのが良いと思います。
Qiitaでも良いですが、この手の資料は発表者が顔出しで発表する資料のため、一定以上の完成度があるという利点があります。

参考までに自分は下記の優先順で読んでいきました。
1. 今自分がキャッチアップしようとしている技術近辺のスライド → Dagger、アーキテクチャ周りなどが多めでした
2. 現時点では関係ないけど将来的に使いそうだと思った技術のスライド(AAC、Coroutineなど) → 結果的にかなり役立ちました
3. 関係ないけど興味があるスライド → 息抜き

技術書はそんなに読まない

私の場合はですが、技術書はそんなに読み込んでないです。
(学習しはじめの頃に速習Kotlinは読みました。安くてKotlinの要点がまとまっているのでオススメです。)

その中でも大変参考になったのは以下の3冊です。
1. 実践 Android Data Binding
2. Master of Dagger → 現在進行形でお世話になっています。
3. Android テスト全書 → まだ実践に活かせていませんが名著だと思います。

あとはほとんどQiitaなどの技術系記事にお世話になりました。
ブログ系でお世話になった率が高いのは下記です。
1. Kenji Abe - Medium -
2. stsnブログ
3. Y.A.M の 雑記帳

最後に

この記事が少しでも初心者の方や未経験からエンジニアになる方のお力になれれば幸いです。

「おめでとう! @m-coder は ミジンコから すこし大きいミジンコに 進化した!」
ってなれるように今後も頑張っていきます。

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

【ぶっちゃけAndroidアプリ開発】sqliteでデータベースを作成する

とりあえずsqliteでデータベースを作成したい人のためのTipsです。
csvからインポートしてデータベースを作成します。

<使用環境>
・Macbook Pro
・バージョン10.15.2(Catalina)

1.csvファイル

test.csv
1,東京都庁,東京都新宿区西新宿2-8-1,03-5321-1111,metro.tokyo.jp
2,神奈川県庁,神奈川県横浜市中区日本大通1,045-210-1111,pref.kanagawa.jp
3,埼玉県庁,埼玉県さいたま市浦和区高砂3-15-1,048-824-2111,pref.saitama.lg.jp
4,千葉県庁,千葉県千葉市中央市場町1-1,043-223-2110,pref.chiba.lg.jp
5,静岡県庁,静岡県静岡市葵区追手町9-6,054-221-2455,pref.shizuoka.jp

住所録ちっくなcsvファイルを作成しておく。

2.データベースを作成してcsvをインポート

ターミナルでデータベースの器を作成しつつsqliteに入る。
既にデータベースがある場合も同じコマンドでOK。
今回、データベース名は「test.db」。

$ sqlite3 test.db
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.
sqlite> 

「create table」SQL文でテーブルを作成する。
今回、テーブル名は「addressbook」。

sqlite> create table addressbook(seq integer, name text, address text,phone text, mail text);
sqlite> 

「.tables」コマンドでテーブルが作成できているか確認する。

sqlite> .tables
addressbook
sqlite> 

「.show」コマンドでsqlite設定を確認する。

sqlite> .show
        echo: off
         eqp: off
     explain: auto
     headers: off
        mode: list
   nullvalue: ""
      output: stdout
colseparator: "|"
rowseparator: "\n"
       stats: off
       width: 
    filename: test.db
sqlite> 

colseparatorの設定が「|」であることが確認できる。
これがインポートファイルのセパレータ記号なので、「.separator」コマンドで「,」へ変更する。

sqlite> .separator ,
sqlite> 

「.show」コマンドで確認。

sqlite> .show
        echo: off
         eqp: off
     explain: auto
     headers: off
        mode: list
   nullvalue: ""
      output: stdout
colseparator: ","
rowseparator: "\n"
       stats: off
       width: 
    filename: test.db
sqlite> 

「.import」コマンドでcsvファイルをインポートする。ファイルパスは変更してください。
エラーが出なければ大丈夫。

sqlite> .import /Users/xxxxxxx/test.csv addressbook
sqlite> 

「select *」SQL文でテーブルの中身を確認する。

sqlite> select * from addressbook;
1,東京都庁,東京都新宿区西新宿2-8-1,03-5321-1111,metro.tokyo.jp
2,神奈川県庁,神奈川県横浜市中区日本大通1,045-210-1111,pref.kanagawa.jp
3,埼玉県庁,埼玉県さいたま市浦和区高砂3-15-1,048-824-2111,pref.saitama.lg.jp
4,千葉県庁,千葉県千葉市中央市場町1-1,043-223-2110,pref.chiba.lg.jp
5,静岡県庁,静岡県静岡市葵区追手町9-6,054-221-2455,pref.shizuoka.jp
sqlite> 

「.exit」コマンドでsqliteを抜ける。

sqlite> .exit
$ 

ここまででデータベースファイルの作成完了です。
Android Studioにコピペして、プログラムからアクセスできます。プログラムから使う方法は別記事「【ぶっちゃけAndroidアプリ開発】SQLiteデータベースにアクセスして画面に表示するサンプル」を参照。

3.sqliteを使う上で知っておくべきコマンド類

(1)ターミナルコマンド

$ sqlite3 データベース名
・データベースを作成、接続する。

(2)sqliteコマンド

sqlite> .import csvファイル名 テーブル名
・csvファイルをインポートする。
sqlite> .show
・設定を表示する。
sqlite> .exit
・sqliteから抜ける。
sqlite> .separator ,
・セパレーターを「,」に変更する。
sqlite> .header on
・テーブルのデータを表示するときにカラム名を表示する。(見やすい)
sqlite> .mode column
・テーブルのデータを表示するときにカラムが揃えられる。(見やすい)

(3)SQL文

sqlite> create table テーブル名(カラム名1 データ型1, カラム名2 データ型2, ...);
・テーブルを作成する。
sqlite> select * from テーブル名;
・テーブルのデータを全て表示する。
sqlite> delete from テーブル名;
・テーブルのデータを全て削除する。

(4)データ型

sqliteで使用できるデータ型は以下の5つ。
TEXT テキスト型
INTEGER 整数型
REAL 浮動小数点型
BLOB バイナリーラージオブジェクト
NULL


ぶっちゃけAndroidアプリ開発は、アプリ開発にあたってとりあえず知っておくべきことをズバリ書きます。例外はありますのでご了承ください。
勉強中の身でありますので、誤りなどあればご指摘いただけると有り難いです。

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

Android で OpenCL を試す

OpenCL

OpenCL(Open Computing Language)は、マルチコアCPUやGPU などによる異種混在の計算資源において、
並列コンピューティングのためのクロスプラットフォームなAPIである。
標準化団体のクロノス・グループ(Khronos Group) によって仕様が策定され、
ロイヤリティフリーなオープン仕様として公開されている。

wikipedia : OpenCL

Android では、公式にはサポートされていないが。
CPU/GPUメーカーによりサポートされている。
機種依存性 高し。

Android上でのOpenCLの現状

Android で OpenCLの環境を作る

まず、CPU と GPUのメーカーと型番を調べる。

Nexus5 で実行した例

CPU

$ adb shell cat /proc/cpuinfo | grep Hardware
Hardware : Qualcomm MSM 8974 HAMMERHEAD (Flattened Device Tree)

GPU

$ adb shell dumpsys | grep GLES
GLES: Qualcomm, Adreno (TM) 330, OpenGL ES 3.0 V@127.0 AU@ (GIT@I96aee987eb)

これに対応したOpenCLドライバーを入手する。

Getting Started with OpenCL on Android

OpenCL on Mobile Devices

Qualcomm のサイトから OpenCLドライバーを入手すると、
ROM イメージを入れ替えるように記載されている。

Qualcomm Tools & Resources

もっと簡易な方法がないか調べてみると、
アプリに OpenCL ドライバーを同封する方法が見つかった。
githubリポジトリには、 Adreno 330 用のドライバーと、
ヘッダーファイルが同封されている。
今回は、これを試す。

github : OpenCL-android

下記にて OpenCL ドライバーが配布されているが、
動作せず。

github : Proprietary OpenCL drivers for Android

OpenCL ヘッダーファイルは
Khronos の github リポジトリで配布されている。
これに置き換えても動作する。

github : Khronos OpenCL-Headers

アプリを作成する

下記のプロジェクトファイルを自分の環境に合わせる。

github : OpenCL-android

下記を参考にした。

CMakeLists.txt
# OpenCL Header 
set(OPENCL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../opencl)
set(LIB "${OPENCL_DIR}/lib")
include_directories(${OPENCL_DIR}/include)

# OpenCL Driver 
add_library(libOpenCL SHARED IMPORTED )
set_target_properties(libOpenCL PROPERTIES
    IMPORTED_LOCATION "${LIB}/${ANDROID_ABI}/libOpenCL.so")

# C++ コード をコンパイルする
add_library( 
             ${target}
             SHARED
             native-lib.cpp )

# ターゲットをビルドする
target_link_libraries( # Specifies the target library.
                        ${target} 
                        libOpenCL
                       ${log-lib} )

# "libOpenCL.so" をアプリに同封する
  configure_file(
    "${LIB}/${ANDROID_ABI}/libOpenCL.so" 
    "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libOpenCL.so" 
    COPYONLY)

大きな修正が1つ必要です。

下記のようにカーネルファイルを読み込んでいる。

std::ifstream kernelFile(fileName, std::ios::in);

しかし、ネティブコードではアプリのファルダーにあるファイルは読み込めない。

Java にて、アプリのファルダーにあるファイルを読み込んで、
アプリごとのファイル領域にコピーして、
そのファイルパスをネティブコードに通知する方法にする。

    protected void onResume() {

        // カーネルファイルをコピ=してファイルパス名を取得する
        String path = AssetFile.getFilePath(this, CL_FILE_NAME);
        // ネティブコードを実行する
        String text = stringFromJNI(path);

そのほかの修正。
元のプログラムでは、OpenCLのカーネルが正しく動作しているかを確認していない。
ホスト側 (CPU)  と ターゲット側(GPU) で同じ計算を行い、照合するようにした。

native-lib.cpp
// result1 : CPU の計算結果
// result2 :  GPU の計算結果

    for(int k = 0;k <  ARRAY_SIZE;k++){
        float f1 = result1[k];
        float f2 = result2[k];
        int r1 = (int)f1;
        int r2 = (int)f2;
        // LOGD("result: %f", f2);

// 照合する
        if (r1 != r2) {
             LOGD("unmstch: %f , %f", f1, f2);
            return 1;
        }
    }

アプリを実行する

analyze apk により下記の2つが同封されていることが確認できる。
- libnative_lib.so
- libOpenCL.so
opencl1_analyze_apk.png

スクリーンショット
CPUとGPUの計算に要した時間を表示する
opencl1_main.png

GPU の方が遅くなっている。
メモリ転送などのオーバーヘッドによるものと思われる。

C++でOpenCL(高速化編)

サンプルコードをgithub に公開した。
https://github.com/ohwada/Android_Samples/tree/master/OpenCL1

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

[Android]カスタムビューの作り方 (フルカスタムコンポーネント)

はじめに

Android では公式にあるとおりカスタムビューを作成する方法が何パターンかあります。
今回はフルカスタムコンポーネントを作成してみたので作成方法をまとめたいと思います。

名称 説明
フルカスタムコンポーネント Viewを継承していちから新たなコンポーネントを作成するパターン
複合コンポーネント 既存のコンポーネントを複数組み合わせて新たなコンポーネントを作成するパターン

mermaid.png

今回はnumberdisplayModeを設定すると、モードごとに数字を表示する次のようなビューを作ろうと思います。

Screenshot_1577611733.png Screenshot_1577612085.png

1. 独自のViewクラスを継承する

フルカスタムコンポーネントを作成するために、まずViewを継承したクラスを実装します。

NumberView.kt
class NumberView(context : Context, attributeSet: AttributeSet) : View(context, attributeSet)

このようにViewを継承したクラスを定義するとレイアウトでCustomViewを記述できるようになります。

main_activity.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

    <kaleidot725.customviewsample.NumberView
        android:id="@+id/number_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:number="1234567890"
        app:displayMode="japanese"/>

</FrameLayout>

2. 独自のAttributesを宣言する

フルカスタムコンポーネントで独自のAttriubtesを利用するには、
valuesattrs.xmlを作成し、独自のAttributesを宣言する必要があります。
次のようにattrs.xmlを記述すると、レイアウトでAttributesで利用できるようになります。

attrs.xml
<resources>
    <declare-styleable name="NumberView">
        <attr name="number" format="integer"/>
        <attr name="displayMode" format="enum">
            <enum name="number" value="0"/>
            <enum name="english" value="1"/>
            <enum name="japanese" value="2"/>
        </attr>
    </declare-styleable>
</resources>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

    <kaleidot725.customviewsample.NumberView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:number="1" 
        app:displayMode="number"/>

</androidx.constraintlayout.widget.ConstraintLayout>

3. 独自のAttributesを取得する

obtainStyledAttributesを利用すれば、独自に宣言したattributesを取得できます。
attributesを宣言するとR.styleable.<CustomView名称>_<attributes名称>を指定できるようになっているので、
次のようにそのIDobtainStyledAttributesに指定してattributesを取得します。

NumberView.kt
    private var number : Int = 0
    private var displayMode : Int = 0

    init {
        context.theme.obtainStyledAttributes(attributeSet, R.styleable.NumberView, 0, 0).apply {
            try {
                number = getInteger(R.styleable.NumberView_number, 0)
                displayMode = getInteger(R.styleable.NumberView_displayMode, 0)
            } finally {
                recycle()
            }
        }
    }

4. onDrawに描画処理を記述する

View.onDrawをオーバーライドすることでViewの描画内容を変更できます。
Viewの描画にはCanvasを利用します、Canvasでどのような描画ができるかは次に詳しくまとまっています。

今回はCanvasdrawTextで文字の描画、drawRectで背景の描画を実装してみます。
また文字の描画ではnumberdisplayModeに応じて描画する文字列を変換するようにしてみます。

NumberView.kt
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        val backgroundPaint = Paint().apply {
            setColor(Color.GREEN)
        }
        canvas?.drawRect(0f, 0f, this.width.toFloat(), this.height.toFloat(), backgroundPaint)

        val textPaint = Paint().apply {
            setColor(Color.BLACK)
            textSize = 50f
        }
        val text = getDisplayNumber(number, displayMode)
        val textWidth = getTextWidth(text, textPaint)
        canvas?.drawText(text, (this.width / 2f) - (textWidth / 2), this.height / 2f, textPaint)
    }

    private fun getTextWidth(text : String, paint : Paint) : Float {
        val bounds = Rect()
        paint.getTextBounds(text, 0, text.length, bounds)
        return bounds.width().toFloat() + bounds.left.toFloat()
    }

    private fun getDisplayNumber(number : Int, displayMode : Int) : String {
        fun String.replace(vararg pairs: Pair<String, String>): String =
            pairs.fold(this) { acc, (old, new) -> acc.replace(old, new, ignoreCase = true) }

        return when(displayMode) {
            0 -> { number.toString() }
            1 -> { number.toString().replace(
                    "0" to "〇", "1" to "一", "2" to "二", "3" to "三", "4" to "四",
                    "5" to "五", "6" to "六", "7" to "七", "8" to "八", "9" to "九"
                )
            }
            else -> { "error" }
        }
    }

すると指定したNumberJapanseに変換されて表示されるようになります。

Screenshot_1577611733.png

5. 独自のAttributesを変更できるようにする

最後に独自のAttributesを変更できるようにsetNumbersetDisplayModeメソッドを用意します。
Attributesの変更を反映させるために変更後はinvalidaterequestLayoutを呼ぶ必要があります。

NumberView.kt
    private var number : Int = 0
    private var displayMode : Int = 0

    fun setNumber(number : Int) {
        this.number = number
        this.invalidate()
        this.requestLayout()
    }

    fun setDisplayMode(displayMode: Int) {
        this.displayMode = displayMode
        this.invalidate()
        this.requestLayout()
    }

試しにNumberViewを取得して、setNumbersetDisplayModeを呼び出してみます。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val numberView : NumberView = findViewById(R.id.number_view)
        numberView.setNumber(999999)
        numberView.setDisplayMode(0)
    }
}

こんな感じで設定変更が適用され表示も変化するようになります。

Screenshot_1577612085.png

おわりに

今回作成したサンプルは次にまとめています。
なので必要に応じて閲覧していただければと思います。

参考文献

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

スマホで簡単にマイニングができるPi Network

Pi Networkとは

Pi Networkとはスタンフォード大学の博士課程のグループによって開発されている仮想通貨だ。
今年の3月に公開され、現在では125万人を超えている。

Pi Networkの特徴

マイニングが簡単にできる

ビットコインなどの今までの仮想通貨では高性能なコンピュータを用いて知識のある人がマイニングをしていたが、Pi Networkでは誰でもスマホで1日に一回ボタンをタップするだけでマイニングをすることができる。

Pi Networkの始め方

現在Pi Networkはβ版のためinvite code(招待コード)が必要なので以下のリンクからアプリをダウンロードしinvite codeのところにentotsuを入れることで登録できる。

http://minepi.com/entotsu

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