简体   繁体   English

带有 AlertDialog 的自定义 DialogFragment 将 EditText 返回为“”

[英]Custom DialogFragment with AlertDialog returns EditText as ""

I have a custom DialogFragment that I'm using to capture user input that I will create a database entry with.我有一个自定义DialogFragment用于捕获用户输入,我将使用它创建数据库条目。 I'm using EditText in an AlertDialog .我在AlertDialog中使用EditText I am trying to use a single activity for my application and the original tutorial I was studying was using multiple activities and intents but that seems outdated for most cases.我正在尝试为我的应用程序使用单个活动,而我正在学习的原始教程是使用多个活动和意图,但在大多数情况下这似乎已经过时了。

When I debug I find that the EditText is returning "" and is showing up as empty when I call TextUtils.isEmpty() in the MainActivity onDialogPositiveClick .当我调试时,我发现EditText正在返回 "" 并且当我在MainActivity onDialogPositiveClick中调用TextUtils.isEmpty()时显示为空。

I've done a lot of combing through the forms here and I'm confused by:我在这里对 forms 做了很多梳理,我很困惑:

1)many of the answers I find are in Java and not Kotlin 1)我找到的许多答案都在 Java 而不是 Kotlin

2)many mention onCreate but do not specify onCreateView vs. onCreateDialog or if there's just an onCreate that I need to override. 2)很多人提到 onCreate 但没有指定 onCreateView 与 onCreateDialog 或者是否只有我需要覆盖的 onCreate 。

I have researched this and found answers that confuse me a bit about when and if I need to inflate the layout.我对此进行了研究,并找到了一些答案,这些答案让我对何时以及是否需要对布局进行膨胀感到有些困惑。 This current itteration I didn't inflate it at all.当前的迭代我根本没有夸大它。 I just set it in the AlertDialog builder.我只是在AlertDialog构建器中设置它。

Maybe it's the interface I'm not understanding.也许是我不理解的界面。 How am I supposed to pass information between the dialog and MainActivity?我应该如何在对话框和 MainActivity 之间传递信息? The interface seems to pass the dialog itself but I seem to be missing something when it comes to getting the EditText from the dialog.该界面似乎通过了对话框本身,但是在从对话框中获取 EditText 时我似乎遗漏了一些东西。

My custom DialogFragment我的自定义 DialogFragment

class NewSongFragment : DialogFragment() {
    lateinit var listener: NewSongListener

    lateinit var editNewSong: EditText
    lateinit var editBPM: EditText

    interface NewSongListener {
        fun onDialogPositiveClick(dialog: DialogFragment)
        fun onDialogNegativeClick(dialog: DialogFragment)
    }

    /** The system calls this to get the DialogFragment's layout, regardless
    of whether it's being displayed as a dialog or an embedded fragment. */
   /*
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout to use as dialog or embedded fragment
        return inflater.inflate(R.layout.fragment_new_song, container, false)

    }
*/
    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            listener = context as NewSongListener
        } catch (e: ClassCastException) {
            // The activity doesn't implement the interface, throw exception
            throw ClassCastException((context.toString() +
                    " must implement NewSongListener"))
        }
    }



    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)

            //add inflater
            //val inflater = requireActivity().layoutInflater;
            //val view = inflater.inflate(R.layout.fragment_new_song, null)
            builder
                .setView(R.layout.fragment_new_song)
                .setCancelable(true)
                .setNegativeButton(R.string.cancel,DialogInterface.OnClickListener { dialog, id ->
                    dialog?.cancel()
                })
                .setPositiveButton(R.string.button_save,
                    DialogInterface.OnClickListener {dialog, _ ->
                        listener.onDialogPositiveClick(this)
                    })

            // Create the AlertDialog object and return it
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")

    }

}

My MainActivity我的主要活动

class MainActivity : AppCompatActivity(),NewSongFragment.NewSongListener {
    private val songViewModel: SongViewModel by viewModels {
        SongViewModelFactory((application as SongApplication).repository)
    }

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

        //create view
        val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
        val adapter = ItemAdapter(this,
            ItemAdapter.OnClickListener { rating -> songViewModel.insertRating(rating) }
        )
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)

        //initialize data
        songViewModel.allSongs.observe(this) { song ->
            // Update the cached copy of the songs in the adapter.
            song.let { adapter.submitList(it) }
        }


        // Use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView

        recyclerView.setHasFixedSize(true)

        //add song button
        val fab = findViewById<FloatingActionButton>(R.id.fab)
        fab.setOnClickListener {
            showNewSongDialog()
            }
        }

    private fun showNewSongDialog() {
        // Create an instance of the dialog fragment and show it
        val dialog = NewSongFragment()
        dialog.show(supportFragmentManager, "NewSongFragment")
    }
    override fun onDialogPositiveClick(dialog: DialogFragment) {
        // User touched the dialog's positive button
        val editNewSong = dialog.view?.findViewById<EditText>(R.id.newSongTitle)
        val editBPM = dialog.view?.findViewById<EditText>(R.id.newSongBpm)
        if(TextUtils.isEmpty(editNewSong?.text)){

        }else{
            val newSong = Song(editNewSong?.text.toString(),100)
            songViewModel.insertSong(newSong)
            val rating = Rating(System.currentTimeMillis(),newSong.songTitle, 50)
            songViewModel.insertRating(rating)
        }

    }

    override fun onDialogNegativeClick(dialog: DialogFragment) {
        // User touched the dialog's negative button
    }


}

Because you are adding the dialog as a Fragment , you should use onCreateView to inflate the view, rather than trying to add a view in onCreateDialog .因为您将对话框添加为Fragment ,所以您应该使用onCreateView来扩充视图,而不是尝试在onCreateDialog中添加视图。

You are adding the layout with a resource identifier, so your call to get the view is returning null.您正在添加带有资源标识符的布局,因此您获取视图的调用将返回 null。 (Why? The view is inflated internally and just handled differently.) Since you are using the AlertDialog to collect data, you will have to add an inflated view. (为什么?视图在内部膨胀,只是处理方式不同。)由于您使用AlertDialog收集数据,因此您必须添加膨胀视图。

I am also going to suggest that you change the interface to hide the details of the dialog;我还将建议您更改界面以隐藏对话框的详细信息; There is no reason for the main activity to know the internal structure of the dialog.主活动没有理由知道对话的内部结构。 It just needs the song title and BPM and maybe some other stuff.它只需要歌曲名称和 BPM 以及其他一些东西。 You will find the code a little easier to understand and maintain.您会发现代码更易于理解和维护。

Here is a slight rework.这是一个轻微的返工。 This code just captures the song title, but it can easily be extended to include other data as well.此代码仅捕获歌曲标题,但也可以轻松扩展以包含其他数据。

In NewSongFragment :NewSongFragment 中

interface NewSongListener {
    fun onDialogPositiveClick(songTitle: String)
    fun onDialogNegativeClick(dialog: DialogFragment)
}

val inflater = requireActivity().layoutInflater;
val view = inflater.inflate(R.layout.fragment_new_song, null)
builder
    .setView(view)
    .setCancelable(true)
    .setNegativeButton(R.string.cancel, DialogInterface.OnClickListener { dialog, id ->
        dialog?.cancel()
    })
    .setPositiveButton(R.string.button_save)
    { dialog, _ ->
        Log.d("Applog", view.toString())
        val songTitle = view?.findViewById<EditText>(R.id.newSongTitle)?.text
        listener.onDialogPositiveClick(this)
    }

In MainActivity.kt在 MainActivity.kt

override fun onDialogPositiveClick(songTitle: String) {
    // songTitle has the song title string
}

Android dialogs have some quirks. Android 对话框有一些怪癖。 Here are a number of ways to do fragment/activity communication.以下是进行片段/活动通信的多种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM