- 1. Jetpack Compose でログインフォームを作る
- 2. 【Kotlin】冗長的なレイアウトファイルからの脱却
- 3. プログラムでOSはHarmony(HarmonyOS)かAndroidか判断する方法
- 4. Universal Android Music Player(UAMP)のカスタマイズ (メニューの変更 2)
- 5. Flutterで手書きを実装する
- 6. [Mockk]SystemClockをモックする
- 7. Android + Kotlin での HTTP リクエストの方法
- 8. 【Android】Looper を持つスレッドの CoroutineDispatcher を作る
- 9. [Coil]キャッシュサイズを変更する方法
- 10. 【Android】ViewPager2+FragmentStateAdapterでFragmentを置き換える
- 11. 孫から祖父へテレビ電話(LINEのできるタブレット)をプレゼントした話
- 12. Application を ViewModelStoreOwner にする方法
- 13. AlertDialogのカスタマイズその1:引数を渡そう
- 14. フォアグラウンドサービスの作り方
- 15. 1年間Flutterで開発をしていてわかったアクセシビリティの問題(Android編)
- 16. Empty Compose Activity から色々なものを作る
- 17. fluter doctorで–android-licensesが出来ないときの対処
- 18. Activity からの戻り値を取得する方法
- 19. Android 12では「おおよそ」の位置情報が選択できるようになるが、LocationManagerでは位置情報の更新を受け取れないらしい
- 20. Jetpack ComposeのdoCompose()開始からアプリ側のComposable関数の呼び出しに至るまでのコードリーディング
Jetpack Compose でログインフォームを作る
## はじめに
Jetpack Compose で入力フォームを作成する方法を記載します。画面に配置する要素は3つで、メールアドレス入力欄、パスワード入力欄、ボタンです。
Empty Compose Activity から作り始めた場合、おそらく追加のパッケージは必要ありません。
## 実装
まずはメールアドレス入力欄の実装です。
“`kotlin
@Composable
fun EmailTextField(
value: String,
modifier: Modifier = Modifier,
onValueChange: (String) -> Unit,
) {
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
keyboardOptions = KeyboardOptions(
keybo
【Kotlin】冗長的なレイアウトファイルからの脱却
アンケート画面などで複数のTextViewやCheckBoxが繰り返し表示される画面を作成するときレイアウトファイル(.xml)が冗長的になってしまうことがあるかと思います。
以下の画像のようなチェックボックスが複数個並んだViewを作成するとします。この時のレイアウトファイルとして真っ先に考えられるのはこんな感じかなっと思います。
“`.xml
プログラムでOSはHarmony(HarmonyOS)かAndroidか判断する方法 ファーウェイは2021年7月23日に[HUAWEI MatePad 11](https://consumer.huawei.com/jp/press/news/2021/news-210713/)をリリースしました。このタブレットはHarmonyOSを搭載しています。AndroidのアプリもHarmonyOSのアプリも正常動作します。
アプリの中でOSがHarmonyOSかAndroidか判断する場面があるかもしれないので、その方法を公開します。
“`java
public boolean isHarmonyOS() {
try {
Class classType = Class.forName(“com.huawei.system.BuildEx”);
Method method = classType.getMethod(“getOsBrand”);
ClassLoader classLoader = classType.getClassLoader();
if (classLoader != null
Universal Android Music Player(UAMP)のカスタマイズ (メニューの変更 2)
#はじめに
Android用アプリのプログラミングを学ぶため、Googleが公開しているサンプルコード **Universal Android Music Player(UAMP)**をカスタマイズしてみます。メニューをカスタマイズするために、オリジナルのコードの動作を確認します。
今回は、メニュー画面で項目がタップされてから下位のメニューを表示するまでの動作を確認します。#環境
####PC
MacBook Pro 16
2.3 GHz 8コアIntel Core i9
16 GB 2667 MHz DDR4
macOS Big Sur ver.11.5.2####開発用SW
Android Studio 4.2.1####Target Device (Virtual Device)
Category: Phone
Name: Pixcel 2
Resolution: 1080×1920 420bpi
API Level: 28
Android: 9.0
CPU: x86#コードの確認
###メニュー項目の選択(下位のメニューが存在する場合)
メニュー画面で項目が
Flutterで手書きを実装する
# 実装する機能
今回実装する機能は、
– 自由に画面をなぞると特定の範囲内で手書きで絵が描けるようにする
– ひとつ戻る(undo)ひとつ進む(redo)ボタンの実装
– 全部消すボタンの実装になります。類似した機能が入ったアプリだと消しゴムが入っていますが、今回のアプリではそこまで必要性を感じなかったため実装しません。
# パッケージ・バージョン
Flutterのバージョンは`2.2.0`です。
使用するパッケージは状態管理のために`hooks_riverpod`と`statenotifier`、`freezed`を使います。
特にそれ以外のパッケージは使用しません。
バージョンは以下の通りです。“`yaml:pubspec.yaml
dependencies:
flutter_hooks: ^0.17.0
freezed_annotation:
hooks_riverpod: ^0.14.0+4dev_dependencies:
build_runner:
freezed:
“`# 手書きの実装
## 土台の作成
本題の実装に
[Mockk]SystemClockをモックする
`mockkStatic()`を使います。
“` Test.kt
class Test {
@Test
fun systemClockTest() {
mockkStatic(SystemClock::class)
every { SystemClock.elapsedRealtime() } returns 100L
assertThat(SystemClock.elapsedRealtime()).isEqualTo(100L)
}
}
“`
Android + Kotlin での HTTP リクエストの方法
## はじめに
Firebase Authentication の ID トークンを HTTP ヘッダに付与したり、独自データと JSON 文字列間の変換を行ったりすることはよくあるのですが、頻繁に使う割に忘れるので記事として残します。
## 環境
build.gradle は次のような内容になっています。
“`groove
plugins {
…
id ‘org.jetbrains.kotlin.plugin.serialization’ version ‘1.5.21’
id ‘com.google.gms.google-services’
}dependencies {
…
implementation “androidx.navigation:navigation-compose:2.4.0-alpha06”
implementation platform(‘com.google.firebase:firebase-bom:28.4.0’)
implementation ‘com.google.fir
【Android】Looper を持つスレッドの CoroutineDispatcher を作る
関連記事:[【Kotlin/JVM】CoroutineDispatcher を作る](https://qiita.com/sdkei/items/a056a1275b05b11ddcd4)
次のようにすることで `Looper` を持つスレッドの `CoroutineDispatcher` を作ることができる。
“`Kotlin
import android.os.Handler
import android.os.HandlerThread
import kotlinx.coroutines.*
import kotlinx.coroutines.android.HandlerDispatcher
import kotlinx.coroutines.android.asCoroutineDispatcherval handlerDispatcher: HandlerDispatcher =
HandlerThread(“HandlerThreadDispatcher”)
.apply { start() }
.looper
[Coil]キャッシュサイズを変更する方法
Androidの画像ローディングライブラリ[Coil](https://coil-kt.github.io/coil/)でディスクキャッシュのサイズを変更する方法を調べたのでメモがてら記事にします。
###方法
Coilは[OkHttp](https://square.github.io/okhttp/)のディスクキャッシュ機構を利用しています。
したがって、キャッシュのサイズを変更するにはOkHttpClientを置き換えます。“` Coil.kt
val cache = Cache(
directory = File(context.cacheDir, “image_cache”),
maxSize = 500L * 1024L * 1024L // 500 MB
)
val imageLoader = ImageLoader.Builder(context)
.okHttpClient {
OkHttpClient.Builder()
.cache(cache)
.build()
【Android】ViewPager2+FragmentStateAdapterでFragmentを置き換える
ViewPager2 + FragmentStateAdapterでFragmentを追加・削除しようとしてハマった時のまとめ。
##やりたいこと
* ViewPagerにセットしたFragmentを別のFragmentに置換したい
##方針Android Developersに以下のような記載がありました。
>ViewPager2 は、編集可能なフラグメント コレクションのページングをサポートしています。基盤コレクションが変更されたときに、notifyDatasetChanged() を呼び出して UI を更新します。
これにより、アプリは、実行時にフラグメント コレクションを動的に編集できるようになり、編集されたコレクションを ViewPager2 が正確に表示します。https://developer.
孫から祖父へテレビ電話(LINEのできるタブレット)をプレゼントした話
# この記事では
齢80を超えた祖父に孫(筆者)から初めてのスマホ(タブレット)をプレゼントしてLINEでおしゃべりするようになるまでを振り返ります。
なお「孫」の発音は「**ま**ご」。##発端
新型コロナの流行拡大が止まらない2020年。田舎の祖父(農家。パソコンはワープロ、ネット環境はない)が高熱で入院。
ごく小さいながら年相応に前立腺がんがあり、その治療でトイレが近くなっていたらしい祖父は水分を控えて結果膀胱炎か何かになったらしい。## 何が起こった
コロナ時代の入院といえば面会制限。
面会できるのは1人だけ、1日30分。洗濯物を引き取らなければならないし、日々の細かな対応も必要というので面会者になったのは祖母(パソコンもワープロも知らない、電話は固定電話のみ)。
車で1時間のところに住んでいる叔父が駆けつけるも、面会制限に引っかかって門前払い。会話はできる状態らしいと聞けば、声が聞きたいし聞かせたいのが心情というものでしょう。
この時点で入院は1か月くらい?と言われていた。そんなこと言われたら叔父も母も(もちろん私も)余計に声が聞きたくなるじゃないか。
そこで叔父、
Application を ViewModelStoreOwner にする方法
## はじめに
気軽に Activity 間でデータを共有する場合は、Application を継承したクラスを ViewModelStoreOwner にすると良いです。このように設計することで、Application を継承したクラスが肥大化することなく、Application にグローバルな値を持たせることができます。
## 実装
“`kotlin
class MyApplication : Application(), ViewModelStoreOwner {
private val store = ViewModelStore()
override fun getViewModelStore(): ViewModelStore {
return store
}
}
“`Application の実装はこれだけです。今後グローバルな状態が増えたとしても、Application が肥大化することはありません。代わりに ViewModel の数が増えます。
## 使用例
次のコードは、`SubActivity` で加算した値が `MainAc
AlertDialogのカスタマイズその1:引数を渡そう
何かと便利な`AlertDialog`ですが、引数を渡してその内容を表示させることも簡単にできます。
ViewBindingを使い柔軟にカスタマイズすることもできますが、今回はシンプルにテキストのみを呼び出し元から渡すサンプルを実装してみたいと思います。# AlertDialogについて
基本的にAndroidのDialogは`タイトル`、`コンテンツエリア`、`PositiveButton`、`NegativeButton`、`NeutralButton`といった部品で構成されています(ボタンの総称を`ActionButton`とも言います)。
Dialogとしては`AlertDialog`が最もよく使われ、Alertとはありますが別に警告に限らず様々な用途で使うことができます。
フォアグラウンドサービスの作り方
## はじめに
通常のサービスには制限がありますが、フォアグラウンドサービスにすることにより制限を緩和できます。
## 実装
次のコードは通常のサービスの実装です。
“`kotlin
class MyService : Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
}
“`それに対して次のコードはフォアグラウンドサービスの実装です。
“`kotlin
class MyService : Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}override fun onStartCommand(intent: Intent
1年間Flutterで開発をしていてわかったアクセシビリティの問題(Android編)
この1年コンスタントにFlutterでコーディングをしていてわかった_スクリーンリーダー(TalkBack)_の問題についての記録です。
iOSについては[1年間Flutterで開発していてわかったアクセシビリティの問題(iOS編)](https://qiita.com/yama_1983/items/b669c011874671efdbaa)をご覧ください。—–
## 文字入力時にボリュームボタンでカーソル移動した時の文字読み上げがない
iOSに比べAndroidは動作の安定性や不具合の修正があり、現状ほとんど問題なく開発ができています。
ただ最近のバージョンで上記の問題が発生しています。
これはAndroid特有のアクセシビリティ機能であり、大変協力な物です。
文字入力中に– ボリュームダウンボタン → 左カーソルキー
– – ボリュームアップボタン → 右カーソルキーの役割を果たします。
スワイプによるジェスチャーでも同様のことができますが、ボタン操作のほうが確実です。
が、残念ながらこのカーソル移動の時にフォーカスされた文字を読み上げない問題が起きています
Empty Compose Activity から色々なものを作る
2021年09月13日現在、Deprecated でない機能を使って色々なものを作る方法を記載します。
## 各機能の実装方法
### Composable に ViewModel を渡す①
* build.gradle の修正は不要
* ViewModel のインスタンス化は Activity の `onCreate` で行う“`kotlin
class MyViewModel : ViewModel() {
}class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
setContent { Foo(viewModel) }
}
}@Composable
fun Foo(viewModel: M
fluter doctorで–android-licensesが出来ないときの対処
# あらすじ
`flutter doctor`の初期設定の一つ。`–android-licenses`について、戸惑うところと、その思考過程の一部始終について解説。初心者向けの内容です。
# ドクター!アンドロイドライセンス!
`flutter doctor –android-licenses`が効かなかった。
“`
flutter doctor –android-licenses
Android sdkmanager not found. Update to the latest Android SDK and ensure that the cmdline-tools are installed to
resolve this.
“`sdkマネージャーが見つからないらしい。
# パスを書き換えてみる その1
探してみると、それっぽいのが見つかったため、
`C:\Users\who\AppData\Local\Android\Sdk\tools\bin\sdkmanager.bat`
pathに`C:\Users\who\AppData\Local\An
Activity からの戻り値を取得する方法
## 環境
Android Studio で、Empty Compose Activity を使用して空のプロジェクトを作成しています。Empty Compose Activity は、Android Studio のバージョンである Arctic Fox をインストールすることで表れます。
## 実装
Activity の状態が STARTED になる前に、`registerForActivityResult` を使って `ActivityResultLauncher` を作成します。今回は、Activity からの文字列をただ単に標準出力に出力することにします。
“`kotlin
class MainActivity : ComponentActivity() {
private val startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_
Android 12では「おおよそ」の位置情報が選択できるようになるが、LocationManagerでは位置情報の更新を受け取れないらしい
Android 12からは以下のようにランタイムパーミッションのダイアログや、設定画面で「正確」な位置情報を許可せず、「おおよそ」の位置情報だけを許可するということができるようになるようです。
|パーミッションダイアログ|アプリ設定|
|:-:|:-:|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/9741e77a-8983-d18b-6c7a-e1241c83f342.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/8032f426-514c-69a7-0c54-62f2a751d55e.png)|「おおよそ」の位置情報が許可された状態、正確な位置情報がオフの状態というのは、`ACCESS_FINE_LOCATION`は許可されず、`ACCESS_COARSE_LOCATION`だけが許可された状態になっています。
Android 12までは`ACCESS_FINE_LOCAT
Jetpack ComposeのdoCompose()開始からアプリ側のComposable関数の呼び出しに至るまでのコードリーディング
https://qiita.com/takahirom/items/d2a89560f8ff2065a7c0
の続きのstateが書き換わってからの動きを追っています。“`kotlin
@Composable
fun Content() {
var state by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
delay(12000)
state = false
}
if (state) {
Node1()
}
Node2()
}
“`**自分用のコードリーディイングメモ記事で、もっとわかりやすいのを後で出すと思います。**
以下runRecomposeAndApplyChanges()内処理のまとめ。
**以下の中で3:の部分を読んでいきます。3の途中までになります。**
1: recordComposerModificationsLocked() を呼ぶ。Recomposer.snapshotInv