Androidでいい感じにREST APIを扱う(Kotlin Coroutine, OkHttp3, Retrofit2, Moshi) を書いた
Qiitaアドベントカレンダーに参加した。
あんまり有用な記事をかける気がしないのでQiitaに投稿する気はなかった。というのは建前で、多くの人の目に触れる分、下手に間違ったことを書いて過激な人の目に入って攻撃に合うのが恐かった。
しかし書いてみると知識の再確認ができたり、「いいね」がもらえて自己承認欲求が満たされたりと非常に良い経験ができた。
反省点としてはあまり伸びなかったこと。 それなりに関心を引ける分野を選んだつもりだけど、目新しさが足りないのとやはり内容が浅かったのが原因だと思う。
基本はこちらの地下ブログでアウトプットを続けるつもりだけど、来年もアドベントカレンダーだけは参加してもっと面白い記事が書きたいな。
Javaの入力がわかりずらい
こちらで説明した記事だとKotlinの拡張関数を使って簡潔に書いている。 が、それだと処理の流れを追い辛い(かもしれない)のでここではJavaで解説します。
登場人物
・InpurStream ・InputStreamReader ・BufferedReader
InputStreamとは
データ入力に対するストリーム ストリームについてはこちらを参照 ストリーム
InputStreamReader
文字列入力を読み込むためのリーダー 文字列を読み込みたいのでInputStremを文字列情報に変換する。
使い方はコンストラクタにいれるだけ
BufferedReader
InputStreamをBufferingするためのリーダー Buffering ・・・バッファを使い読み書き回数を減らすこと →InputStremReaderのままだと一字ずつしか読むことができないので効率が悪い。 BufferedReaderを使うことで一行ずつ読み込むことが可能になる。
使い方はコンストラクタにいれるだけ
いざ
// 文字列を読むためのReaderを作る InputStreamReader isr = new InputStreamReader(new InputStream()); // このままでは効率が悪いためBufferedReaderを作る BufferedReader br = new BufferedReader(isr); // あとは一行づつ読み込むことができる。 int i = 0; while(br.ready()){ String str = br.readLine(); System.out.println("The " + i++ + "th line : " + str); }
間違っていましたらコメントください(__)
CustomViewでメーターっぽいViewを作成する
続き?
やる事
①コンストラクタを作成
②Viewクラスのメソッドをオーバーライド
- onMeasure()
- onTouchEvent()
- onDraw()
いざ
①コンストラクタを作成
CustomViewを作成する=Viewクラスを継承する際は4つのセカンダリコンストラクタを書く必要がある。ただし@JvmOverloads のアノテーションをプライマリコンストラクタに追記するとコンストラクタはその一つで済む。
具体的には
class MeterView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : View(context, attrs, defStyle) {
で十分となる。
②Viewクラスのメソッドをオーバーライド
onMeasure()
ここでやるべきは
setMeasureDimension()
でViewのサイズを確定させる事。
引数の二つのmeasurespecには親ビューからのサイズ情報が入っており、サイズ指定する場合はMeasureSpec.getSize()で引き出す必要がある。
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { //スクリーンサイズを取得する。 val displayMetrics = DisplayMetrics() (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics( displayMetrics ) mScreenWidth = displayMetrics.widthPixels mScreenHeight = displayMetrics.heightPixels //サイズの指定が会った際に大きさを取得する。 if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)) { mScreenWidth = MeasureSpec.getSize(widthMeasureSpec) } if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)) { mScreenHeight = MeasureSpec.getSize(heightMeasureSpec) } //自分自身のサイズを setMeasuredDimension で確定させる setMeasuredDimension(mScreenWidth, mScreenHeight) initButtonSize(mScreenWidth, mScreenHeight) ※ 一つ一つのボタンの大きさを確定 }
initButtonSize()のなかで各ボタンのサイズを確定させてこんなデータクラスのリストに突っ込んでいる。
data class ExtractLevel( var levelIndex: Int = 0, var position: RectF )
onTouchEvent()
ここでやるべきはタッチされた際の挙動を制御する事。ここのロジック部分のコードは省略するが
やってる事は移動(MotionEvent.ACTION_MOVE)が呼ばれた際に、方向(上下)を判別しinvalidate()
による"onDraw()""の呼び出しである。
override fun onTouchEvent(event: MotionEvent?): Boolean { val currentTouchId = getTouchedLevelIndex(x, y) //現在タップされたレベル位置 MotionEvent.ACTION_MOVE -> { 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 if (mCurrentLevel != currentTouchId && currentTouchId != -1) { updateLevelState(currentTouchId) //現在のタッチされているボタンのレベルを更新 invalidate() //再描画処理 } 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 } }
※厳密には移動距離、移動方向の判別も行っているが気になる人はgitで確認して欲しい。
onDraw()
ここでやるべきはViewの描画処理。今回はonMeasure()
内で確定させた各ボタンをCanvasクラスdrawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)
で描画している。
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawLevels(canvas) } private fun drawLevels(canvas: Canvas) { mExtractLevels.forEach { val paint = Paint() paint.style = Paint.Style.FILL paint.color = ContextCompat.getColor( context, if (isLevelSelected(it.levelIndex)) R.color.colorLevel else R.color.emptyColorLevel ) canvas.drawRoundRect( it.position, connerRadius.toFloat(), connerRadius.toFloat(), paint ) } }
完成
全部で3回位を想定していたが実質1回で終了してしまった。。。
https://developer.android.com/reference/android/view/View.html#public-constructors_1 http://tiro105.hateblo.jp/entry/2014/06/19/154405
AndroidでPopupWindowを使う(Kotlin) No.1
なにげにはじめて触ったので備忘として。
やる事
KotlinでPopupWindowを使ってみる。
レイアウト工夫なしの実装だけであれば
- popupのレイアウト作成
- popupwindow インスタンスを作成してshowする
で終わりです。今回ここまでやるのでとりあえず作りたい方はこの記事だけで大丈夫です。
いざ
①popupwindowのレイアウト作成
・お好みのレイアウトでok
②popupwindow インスタンスを作成してshowする。
・画面外タッチでポップアップを消すためには以下を設定
isOutsideTouchable = true
isFocusable = true
・表示メソッドには位置を指定できるshowAtLocation()、引数のviewの下に配置する
showAsDropDown()がある(後者も引数で位置は調整できる。)
結果
memo
複数ファイルを含むgistはそれぞれのリンクを指定出来ないらしい。
プロジェクト系のコードは別のやり方をした方が良さげ。
よくわからんけどKotlin コルーチンを使いたいって人
が読むべきページ
- https://speakerdeck.com/sys1yagi/kotlin-korutinwo-li-jie-siyou
- https://karino2.github.io/kotlin-lesson/suspend_intro.html
これを読んでもおそらく理解はできない。というか自分が出来ていない。ただとりあえず複雑すぎない処理で使う分には十分なのではなかろうか。