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

[Kotlin]委譲を掘り下げる

はじめに 度々出てくる委譲を良く分からずに使ってしまっているので、掘り下げたいと思います。 委譲とは? 一言で表すと、「任せる」すること。 あるオブジェクトが、他のオブジェクトの処理を委託します。 継承との違い まず、継承とは親クラスのメンバをオーバーライドする形で機能を引き継ぐことです。 某ピンク饅頭キャラのように親の機能を「コピー」します。 親の機能を完コピした子クラスは、自分ものとしてメソッドを使うことができます。 そして、委譲とは子が親の機能に「委託」することです。 これが、ざっくりとした違いです。 メリデメの話 これだけだと、抽象的すぎるのでメリットとデメリットを整理しておきましょう。 継承のメリット コードの再利用が簡単 継承のデメリット 変更時に影響範囲が継承先に広がることがある 委譲のメリット 親の機能や責務を引き継がなくて済む 委譲のデメリット 「任せる」分だけインスタンス生成が必要 どんな課題を解決してくれるのか? 委譲のメリットにもあるように、親クラスの機能や責務を引き継がなくて済むことがあります。 Androidだと、Activity/FragmentでViewModelを委譲としてインスタンス化すると思います。 それも、責務が混在しないためにやっているのだなと改めて思いました。 おわりに 思うところがあれば、追記していきます。 そんなに大した概念ではないかなと思うのですが、意外とメリデメ分かってないのでそこの整理が出来て良かったです。 Kotlinでは、byを使えば簡単に委譲を実現できます。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KotlinでviewBindingを使う

ブロジェクト作成 赤のMainActivityを開きSplitで開くと、コードとデザインを同時に確認できます。 水色がtexttViewのコードとエディタです。 ボタン追加 ボタンを追加すると、コードとデザイン両方追加されます。 背景色も変更してみる 赤枠のbackgroundをいじれば変更できました。 バインディングの設定 build.gradleを開いて、赤で囲ったコードを追加し、右上のSync Nowを押します。 この辺りのやり方は公式ドキュメントを見てください。 バインディングを使う バインディングクラス 上で設定したので、バインディングクラスがファイルごとに生成されるそうです。 今回、初期ではactivity_main.xmlがあるので、ActivityMainBindingが生成されています。 例えば、activity_result.xmlを作成すると、ActivityResultBindingが生成されるはずです。 定義に飛んでみる ActivityMainBindingにカーソルを合わせてcommand + クリックするとxmlファイルに飛べるので関連性が分かると思います。 使い方 このbindingを使って、レイアウトの変数とビューにアクセスできます。 設定方法はバインディングクラスのinflate()メソッドを使用して、オブジェクトをバインドできるそう。 layoutInflaterをいうのは、レイアウトXMLファイルを対応するViewオブジェクトにインスタンス化するものだそうです。(公式ドキュメント) 詳しいことは公式ドキュメント参照。 カウントアップ処理を追加してみた tapCountを作成してこれをtextViewに反映します。 bindingを通してtextViewやbuttonにアクセスしてやりたい処理を書くことができるそうです。 最後に 今回はバインディングの方法について書いてみました。 まだAndroid・Kotlin始めて3日目くらいなので他の方法などあれば教えてくださーい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Mac]Flutterで保存したドキュメントのpath

iPhone sample.dart void _saveFile() async { final documents = await getApplicationDocumentsDirectory(); new Directory('${documents.path}/log').create().then((Directory directory) { print(directory.path);//ここでpath取得 final file = File('${directory.path}/test.log'); file.writeAsString('test'); }); } 普通に保存したパスをコンソール出力して FInde上でcmd + shft + Gにて貼り付ければ飛べます Android Androidの場合、上述のIPhoneの方法では出来ません [View] > [Tool Windows] > [Device File Explorer] data/data/アプリ名/app_flutter/以下にありました。 Finderのパスですと /Users/ユーザー名/Documents/AndroidStudio/DeviceExplorer/エミュレーター名/data/data/アプリ名/app_flutter/以下でした 人によって違うかもしれないので参考程度に 公式ドキュメント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

キーボードを非表示する方法 | Kotlin

キーボードを非表示にする方法。 (ついでにキーボード表示する方法も) 何度も同じこと調べてしまう人間なので、自分のために事細かに補足しまくっています。 ので、ダラダラ長い記事です。 初心者による初心者の自分の為のメモ!!(初投稿) 1.背景タップでキーボード非表示にする方法 イメージ ・EditText(氏名とTELのとこ)をタップするとキーボードが表示される ・背景(linearLayoutにした)をタップするとキーボードが閉じる MainActivity class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } //画面がタッチされた時に反応するやつ override fun onTouchEvent(event: MotionEvent?): Boolean { // InputMethodManagerを取得 val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager //背景のlinearLayoutを取得 val linearLayout = findViewById<LinearLayout>(R.id.linear_layout) // キーボードを閉じる inputMethodManager.hideSoftInputFromWindow( linearLayout.windowToken, InputMethodManager.HIDE_NOT_ALWAYS ) return false } } レイアウトは適当だけど(キーボードもnumber表示とかになってない)、 こんな感じ。 activity.main <LinearLayout android:id="@+id/linear_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity" android:layout_width="match_parent" android:layout_height="match_parent" android:focusableInTouchMode="true" android:orientation="vertical"> <EditText android:id="@+id/ed_name" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:layout_marginLeft="100dp" android:hint="氏名" /> <EditText android:id="@+id/ed_tel" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginTop="44dp" android:layout_marginLeft="100dp" android:hint="TEL"/> </LinearLayout> onTouchEvent 画面がタッチされたときに呼ばれる方。今回は"タッチされたこと"だけを目的に使っているけど、どんな操作されたか(スクロールとか)もMotionEventで把握できるらしい。 InputMethodManager 入力方式を明確にしたい時に使うみたい。入力方式を明確っていうのは、EditTextはタップすると通常キーボードが表示されるようになってるけどそうゆうのを自分で制御できるよ、ってことだと思う。 getSystemServiceのINPUT_METHOD_SERVICEというactivityの入力関係に携わる方をInputMethodManager型にキャストして取得しているイメージ。 HIDE_NOT_ALWAYS 元々キーボードが表示されている場合を除いて、通常はキーボードを非表示にする。 結局やっていることは、 「通常タップするとキーボードが表示するもの(EditText)にフォーカスが当たっていなければ、キーボードを非表示にする。」 と理解している。 上記の実装は背景としてLayout(linearLayout)を明示する考え方。 だけど、 背景としてLayoutは指定せず、現在のフォーカスがView(EditText)別の何か(キーボード表示されないLayoutやView)なのかって考え方をするなら、 上記のコードのLayout取得の箇所消して、代わりにこちらを入れても良いみたい。 val focusView = currentFocus ?: return false currentFocus 文字通り現在のフォーカスを取得する方 エルビス演算子の?:で現在のフォーカスが取得できなければfalseを返す ちなみに?:の意味は、左側に値があればそれを返して、nullなら右側を返す。 2.Viewタップで非表示にする方法 イメージ ・キーボードを非表示にしたいViewをタップしたときに随時非表示にする ・hideKeyboard関数を作っておくことで、好きなViewに好きなタイミングで非表示にする ・今回は戻るボタンを押すとキーボードが非表示になる NewActivity class NewActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_new) //戻るボタンを取得 val backBtn = findViewById<Button>(R.id.back_Btn) //hideKeyboard()でボタンを押すとキーボードが非表示になる backBtn.setOnClickListener { hideKeyboard(context = this,backBtn) } } //引数のViewには(今回はボタンの)Viewが入ってくる fun hideKeyboard(context:Context,view: View){ val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(view.windowToken,InputMethodManager.HIDE_NOT_ALWAYS) } } 1と違うのは、キーボード非表示にする関数を作ることでhideKeyboard()を使いまわせるようにしたこと。 関数としてまとめると楽ってだけで、結局やっていることは変わらないと思う。 3.逆にキーボード表示させる方法 EditTextはタップしたら即キーボードが表示されるから、タップした後の表示で良ければ出番ないと思うけども。 これでできたはず!! fun showKeyboard(context: Context){ val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED,0) } 一応使ってみる.... イメージ ・独自のDialogを作ったとき ・タップさえさせず、起動後すぐにキーボード表示したいとき (大体起動後すぐにキーボード出たら邪魔くさいと思うけど) ・ダイアログとかでEditText1つしかない!これだけ必ず!的な(?) dialog override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) val context = requireContext() dialog.setOnShowListener{ showKeyboard(requireContext()) } fun showKeyboard(context: Context){ val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED,0) } ダイアログのところだけはわざわざここだけ試すってことしてないから、 本当にこれだけでいけるのかは怪しい.... おーーーしまいっ☆ 参考記事 ①https://hirauchi-genta.com/kotlin-edittext/ ②https://qiita.com/tkmd35/items/7d2bd568bd646d0ce6a9 ③https://developer.android.com/training/keyboard-input/visibility?hl=ja ④https://akira-watson.com/android/touchevent.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AndroidのSMS認証コード自動入力について(SMS User Consent API)

はじめに SMSで届いた認証コードを、ワンタップでアプリに反映することができるSMS User Consent APIの実装方法についてまとめました。 開発環境 PC:MacBook Pro OS:macOS BigSur Android Studio:Arctic Fox 2020.3.1 SMS User Consent APIの導入方法 1.ライブラリを追加 build.gradle(app) dependencies { // 以下2行を追加 implementation "com.google.android.gms:play-services-auth:20.0.1" implementation "com.google.android.gms:play-services-auth-api-phone:18.0.1" } 2.レイアウトを作成 activity_main.xmlに認証コードを入力するEditTextを配置します。 activity_main.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"> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Enter verification code" android:importantForAutofill="no" android:inputType="text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="HardcodedText" /> </androidx.constraintlayout.widget.ConstraintLayout> 3.MainActivityを編集 MainActivity.ktにSMS認証コードを受信し自動入力するための処理を記述します。 MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onResume() { super.onResume() val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION) registerReceiver(smsVerificationReceiver, intentFilter) // SMSメッセージの受信待機開始 SmsRetriever.getClient(this).startSmsUserConsent(null) } override fun onPause() { super.onPause() // SMSメッセージの受信待機解除 unregisterReceiver(smsVerificationReceiver) } private val smsVerificationReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action && intent.extras != null ) { val status = intent.extras?.get(SmsRetriever.EXTRA_STATUS) as Status when (status.statusCode) { CommonStatusCodes.SUCCESS -> { requestSmsCode(intent) } CommonStatusCodes.TIMEOUT -> { Log.d(MainActivity::class.java.simpleName, "smsVerificationReceiver timeout") } } } } } private val requestSmsResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult? -> if (result?.resultCode != Activity.RESULT_OK) { return@registerForActivityResult } result.data?.let { data: Intent -> val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE) ?: "" val oneTimeCode = parseOneTimeCode(message) findViewById<EditText>(R.id.editText).setText(oneTimeCode) } } private fun requestSmsCode(intent: Intent) { val consentIntent = intent.extras?.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT) requestSmsResult.launch(consentIntent) } private fun parseOneTimeCode(message: String): String { // 送信するメッセージに合わせて文字列を処理する return message.split("\n")[0].split(":")[1] } } 実装は以上で終わりです。 実際にSMSで送られてきたコードが自動入力できるか確認してみます。 SMS User Consent APIの動作確認方法 まずSMSを送信する検証端末(エミュレータ)を起動し、AndroidStudioのTerminalを開きます。 Terminalに以下のコマンドを入力し、先ほど起動した端末を確認します。 $ adb devices ←コマンド List of devices attached emulator-5554 device ←”emulator-5554”が対象端末 次に以下のコマンドを入力し、対象端末にSMSを送信します。 今回は電話番号が「09012345678」、SMSの内容が「認証コード code:123456」の場合です。 $ adb -s emulator-5554 emu sms send 09012345678 認証コード code:123456 ←コマンド OK ←成功した場合 SMS受信時に表示されるダイアログのAllowボタンをタップすると認証コードが自動入力されます。 参考文献 ・Google developers ・[Android]SMS認証のユーザー負担を減らすSMS User Consent APIを使ってみた
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

キーボードの表示状態を監視する方法

はじめに たまーにキーボードの表示有無によって、UIを制御したいケースがあったりしますよね。 そういった場合に使用できる実装を残しておこうと思います。 表示状態を監視 キーボードの表示状態を監視するには、以下の実装を行うことで可能です。 fragment.kt binding.root.addOnLayoutChangeListener { view, _, _, _, _, _, _, _, _ -> val r = Rect() view.getWindowVisibleDisplayFrame(r) val location = IntArray(2) view.getLocationOnScreen(location) val screenHeight = view.rootView.height // 変化の差分を算出 val heightDiff = screenHeight - r.height() - location[1] // 画面縦幅の差分が想定している高さより大きい場合はキーボードが表示されたと判断する val isShowKeyboard = heightDiff > screenHeight * KEYBOARD_MIN_HEIGHT_RATIO } companion object { private const val KEYBOARD_MIN_HEIGHT_RATIO = 0.15 } 以上になります。 ちなみに余談ですが、GlobalLayoutListenerで監視することも可能ですが、こちらにあるように色々問題を抱えているようで、画面破棄されるまで使用し続けるような実装はメモリーリークに繋がるのでおすすめ出来ません。 さいごに 意外とこういった実装に頭を悩まされたりしますよね。 なるべく未来の自分が楽をできるよう、今後もどんどん投資していこうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む