質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
onclick

onclickとはユーザーのクリック処理を指します。これは"onmousedown"(押下)と"onmouseup"(押上)の二つの事象の組み合わせです

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

1回答

1650閲覧

android開発 DialogFragmentのonStart()内でのOKボタンのOnClickイベント捕捉

rasum

総合スコア21

onclick

onclickとはユーザーのクリック処理を指します。これは"onmousedown"(押下)と"onmouseup"(押上)の二つの事象の組み合わせです

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2021/10/24 03:01

編集2021/10/24 04:14

AndroidのDialogFragmentを利用したダイアログのonStart()にて、OKボタンがタップされた時のイベントが、初めてダイアログを開いた1回目にしか捕捉できません。
Logcatで状況を確認したコードは下記のものです。
キャンセルボタンでダイアログを閉じた後に再度ダイアログを表示した時など、2回目以降もOKボタンイベントを補足するにはどうすればよいでしょうか。

プログラムの目的は、ダイアログに置かれた2つのEditTextの入力が空でないことを確認してからダイアログを閉じるコードを書こうとしているものです。
https://code.luasoftware.com/tutorials/android/android-alertdialog-getbutton-null-pointer-exception/ を参考しました。

kotlinコード

class MyDialogFragment: DialogFragment() { lateinit var myDialog: AlertDialog lateinit var myDialogView: View private val okButton: Button by lazy { (myDialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE) } private val cancelButton: Button by lazy { (myDialog as AlertDialog).getButton(AlertDialog.BUTTON_NEGATIVE) } override fun onStart() { super.onStart() Log.d("MyApp", "Dialog: onStart") okButton.setOnClickListener { Log.d("MyApp", "Dialog:okButton OnClickListener") } cancelButton.setOnClickListener { myDialog.dismiss() } } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val inflater = requireActivity().layoutInflater myDialogView = inflater.inflate(R.layout.my_dialog, null) val builder = AlertDialog.Builder(it) builder.setView(myDialogView) .setPositiveButton(android.R.string.ok, null) .setNegativeButton(android.R.string.cancel, null) myDialog = builder.create()   myDialog } ?: throw IllegalStateException("Activity cannot be null") } }

Logcat出力

2021-10-24 11:39:37.418 11288-11288/PACKAGE D/MyApp: Dialog: onStart 2021-10-24 11:39:42.469 11288-11288/PACKAGE D/MyApp: Dialog:okButton OnClickListener 2021-10-24 11:39:47.494 11288-11288/PACKAGE D/MyApp: Dialog: onStart 2021-10-24 11:39:50.798 11288-11288/PACKAGE D/MyApp: Dialog: onStart 2021-10-24 11:39:53.470 11288-11288/PACKAGE D/MyApp: Dialog: onStart 2021-10-24 11:39:55.847 11288-11288/PACKAGE D/MyApp: Dialog: onStart

MainActivity

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import net.sytes.rokkosan.myalertdialog.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var viewBinding: ActivityMainBinding val myDialogFragment = MyDialogFragment() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // set View Binding viewBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(viewBinding.root) viewBinding.btnOpenDialog.setOnClickListener { myDialogFragment.show(supportFragmentManager, "my") } } }

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"> <Button android:id="@+id/btnOpenDialog" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_open_dialog" android:visibility="visible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> <TextView android:id="@+id/tvData1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" app:layout_constraintBottom_toTopOf="@id/tvData2" app:layout_constraintHorizontal_bias="0.501" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/btnOpenDialog" /> <TextView android:id="@+id/tvData2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/tvData1" app:layout_constraintBottom_toBottomOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>

my_dialog.xml

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <EditText android:id="@+id/etData1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:enabled="true" android:inputType="textPersonName" app:layout_constraintBottom_toTopOf="@+id/etData2" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/etData2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:enabled="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/etData1" /> </androidx.constraintlayout.widget.ConstraintLayout>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2021/10/24 03:12

> キャンセルボタンでダイアログを閉じた後に再度ダイアログを表示 この、ダイアログの表示を管理しているほうのコード(恐らく Activity? )もご提示願えますか。 出来れば回答側で実行しても同じ Logcat 出力が得られる(つまり現象が再現できる)程度の各種コードをお願いします。
rasum

2021/10/24 04:15

jimbe様、「質問の編集」で質問に追記する形で掲載しました。
jimbe

2021/10/24 04:39

ありがとうございます。
jimbe

2021/10/24 06:05

なんとなくですが、参照されたリンク先の方法が必要な内容には思えませんが、普通に onCreateDialog 時に各ボタンにリスナを付けたりではダメなのでしょうか。
rasum

2021/10/24 09:12

「onCreateDialog 時に各ボタンにリスナを付けよう」と下記コードとすると、 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)' on a null object reference と失敗します。 okButton.setOnClickListenerのラムダ式が間違っているのでしょうか。 ``` override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val inflater = requireActivity().layoutInflater myDialogView = inflater.inflate(R.layout.my_dialog, null) val builder = AlertDialog.Builder(it) builder.setView(myDialogView) .setPositiveButton(R.string.dialog_btn_ok, null) .setNegativeButton(android.R.string.cancel, null) myDialog = builder.create() val okButton = myDialog.getButton(AlertDialog.BUTTON_POSITIVE) okButton.setOnClickListener { Log.d("MyApp", "Dialog:okButton OnClickListener") } myDialog } ?: throw IllegalStateException("Activity cannot be null") } ```
jimbe

2021/10/24 10:33 編集

すいません、コメントの説明がダメ過ぎでした。 onCreateDialog 時にというのは、onStart で ok ボタンに登録しているリスナなら、 onCreateDialog 内で書いてある .setPositiveButton(R.string.dialog_btn_ok, null) の null の所に書いても同じでは・・・というつもりでした。 回答に追加したコードではそのようにしていますので、参照してください。 okButton.setOnClickListener ~ での NullPointerException は、 myDialog.getButton() は ダイアログを表示(show()) してからでないと Button オブジェクトを返さないからです。その為に参考にされたリンク先のコードではフラグメントの onStart の中でボタンを取得しています。
rasum

2021/10/24 12:42

jimbe様、やりたいことをズバリを回答欄に記載下さり、大変有り難うございます。今日はできませんが、後ほど実行してみます。 「myDialog.getButton() は ダイアログを表示(show()) してからでないと Button オブジェクトを返さない」ことも、ありがとうございます。
rasum

2021/10/30 05:49

jimbe様、コードを実行して確認しました。ありがとうございました。 次の事項が勉強になりました。 ダイアログのボタンオブジェクトを取得・操作するには、Builder.create()時に、setOnShowListenerして、「ボタンオブジェクトを取得、操作する」ハンドラをセットすればよい。 ダイアログのEditTextの内容によるOKボタンのコントロールは、TextWatcherで入力状況を監視するのが簡単。
guest

回答1

0

ベストアンサー

MainActivity の val myDialogFragment = MyDialogFragment()myDialogFragment.show(supportFragmentManager, "my") の直前に移動させてください。

フラグメントは一般的にシステムに渡した後はアプリで参照を保持しないほうが良いです。表示が終わると自動で削除される(ことがある)為、再利用は出来ず、その参照を保持しているとメモリリークとなります。(正式に具体的にどこでどうなって…という所は追っていないのでお伝え出来ません(_ _;スミマセン )


ダイアログで 2 つの EditText の入力をして OK を押したらインターフェースのメソッドを呼ぶようにしてみました。

MainActivity.kt

kotlin

1package com.teratail.q365939 2 3import androidx.appcompat.app.AppCompatActivity 4import android.os.Bundle 5import android.util.Log 6import com.teratail.q365939.databinding.ActivityMainBinding 7//import net.sytes.rokkosan.myalertdialog.databinding.ActivityMainBinding 8 9class MainActivity : AppCompatActivity(), MyDialogFragment.DialogListener { 10 11 private lateinit var viewBinding: ActivityMainBinding 12 13 override fun onCreate(savedInstanceState: Bundle?) { 14 super.onCreate(savedInstanceState) 15 //setContentView(R.layout.activity_main) 16 17 // set View Binding 18 viewBinding = ActivityMainBinding.inflate(layoutInflater) 19 setContentView(viewBinding.root) 20 21 viewBinding.btnOpenDialog.setOnClickListener { 22 val myDialogFragment = MyDialogFragment() 23 myDialogFragment.show(supportFragmentManager, "my") 24 } 25 } 26 27 override fun onMyDialogOk(text1: String, text2: String) { 28 Log.d("MainActivity", "text1=$text1") 29 Log.d("MainActivity", "text2=$text2") 30 } 31}

MyDialogFragment.kt

kotlin

1package com.teratail.q365939 2 3import android.app.Dialog 4import android.content.Context 5import android.os.Bundle 6import android.text.Editable 7import android.text.TextWatcher 8import android.widget.Button 9import android.widget.EditText 10import androidx.appcompat.app.AlertDialog 11import androidx.fragment.app.DialogFragment 12 13//[ダイアログ](https://developer.android.com/guide/topics/ui/dialogs?hl=ja) 14class MyDialogFragment: DialogFragment() { 15 internal lateinit var listener: DialogListener 16 17 interface DialogListener { 18 fun onMyDialogOk(text1: String, text2: String) 19 } 20 21 override fun onAttach(context: Context) { 22 super.onAttach(context) 23 try { 24 listener = context as DialogListener 25 } catch (e: ClassCastException) { 26 throw ClassCastException((context.toString() + " must implement DialogListener")) 27 } 28 } 29 30 //二つの EditText に文字列があるか無いかで Button の enable を制御する 31 class EditsWatcher(val button: Button, val edit1: EditText, val edit2: EditText): TextWatcher { 32 init { 33 edit1.addTextChangedListener(this) 34 edit2.addTextChangedListener(this) 35 afterTextChanged(null) 36 } 37 override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} //ignore 38 override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} //ignore 39 override fun afterTextChanged(s: Editable?) { 40 button.isEnabled = edit1.text.toString().trim().isNotEmpty() && edit2.text.toString().trim().isNotEmpty(); 41 } 42 } 43 44 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 45 return activity?.let { 46 47 val view = requireActivity().layoutInflater.inflate(R.layout.my_dialog, null) 48 val edData1 = view.findViewById<EditText>(R.id.etData1) 49 val edData2 = view.findViewById<EditText>(R.id.etData2) 50 51 val builder = AlertDialog.Builder(it).setView(view) 52 .setPositiveButton(android.R.string.ok, { dialog, id -> 53 listener.onMyDialogOk(edData1.text.toString(), edData2.text.toString()) 54 }) 55 .setNegativeButton(android.R.string.cancel, { dialog, id -> 56 dialog.cancel() 57 }) 58 59 builder.create().also { dialog -> 60 dialog.setOnShowListener({ 61 val button = dialog.getButton(Dialog.BUTTON_POSITIVE) 62 EditsWatcher(button, edData1, edData2) 63 }) 64 } 65 } ?: throw IllegalStateException("Activity cannot be null") 66 } 67}

投稿2021/10/24 06:01

編集2021/10/24 07:40
jimbe

総合スコア12545

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rasum

2021/10/24 07:32

jimbe様、「フラグメントは一般的にシステムに渡した後はアプリで参照を保持しないほうが良い。表示が終わると自動で削除されることがある」と、ありがとうございます。 ご指摘のとおりにしたら、期待通りに動作しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問