這裡遇到的一個問題是,當fab點下,跳出自訂的layout(dialog_add)後
回到MainActivity畫面,再次點擊fab,就會閃退,報錯
/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tobuylist, PID: 12402
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
請教恩師後,發現原本dialogBuilder沒有呼叫setOnDismissListener這個方法,要加上去
.setOnDismissListener {
(dialogItem.parent as ViewGroup).removeView(dialogItem)
}
得到的解釋是一個容器同時只能裝一個view,第一次點擊fab,
讓dialogBuilder這個容器.setView(dialogItem)裝了這個view之後,沒有remove的動作,
所以當再次點fab,又要再setView時,裡面已經有先前的那個view,就會出錯,
因此setOnDismissListener裡面呼叫removeView()就是用來當dialog結束後,將內容的view給remove掉
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dialogBuilder = AlertDialog.Builder(this@MainActivity)
val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
// 在自訂的dialog中,若要調用view,須寫findViewById
val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
val date_button = dialogItem.findViewById<Button>(R.id.btn_date)
// 清單顯示部分
pieceList.add(item)
recycler_view.adapter = RecyclerViewAdapter(pieceList)
recycler_view.layoutManager = LinearLayoutManager(this)
// float action button
fab.setOnClickListener {
dialogDate.text = SimpleDateFormat("yyyy/MM/dd").format(System.currentTimeMillis())
dialogBuilder
.setTitle("新增清單")
.setView(dialogItem)
// 設定當dialog被點掉時,remove原來放進來的view(dialogItem),否則再次點fab時會丟exception
.setOnDismissListener {
(dialogItem.parent as ViewGroup).removeView(dialogItem)
}
.show()
date_button.setOnClickListener {
val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)
DatePickerDialog(this, { _, year, month, day ->
run {
// val format = "你設定的日期為:${setDateFormat(year, month, day)}"
// val formatDate = SimpleDateFormat("yyyy/MM/dd").parse("$year/$month/$day")
dialogDate.text = "$year/${month+1}/$day"
}
}, year, month, day).show()
}
}
}
}
上面的方式,再次點fab,再次裝的view,是原先的view,因此若原先的view有編輯,
相關的資訊會被記錄下來,再次點fab,再次裝的view,就會是前次有輸入過的內容
例如:
如果是不想要這樣的情形,就要改為每次點fab時,都新建一個dialogItem再丟給setView
因此每次點fab,都會跳一個新的dialog,也不會報錯
只是此方法相對耗能,因為每次都要inflate一個新的view,不過在簡單的範例上感覺不到影響
修改方式為將以下4個變數放在fab.setOnClickListener中宣告
val dialogBuilder = AlertDialog.Builder(this@MainActivity)
val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
val date_button = dialogItem.findViewById<Button>(R.id.btn_date)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dialogBuilder = AlertDialog.Builder(this@MainActivity)
// 清單顯示部分
pieceList.add(item)
recycler_view.adapter = RecyclerViewAdapter(pieceList)
recycler_view.layoutManager = LinearLayoutManager(this)
// float action button
fab.setOnClickListener {
val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
// 在自訂的dialog中,若要調用view,須寫findViewById
val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
val date_button = dialogItem.findViewById<Button>(R.id.btn_date)
dialogDate.text = SimpleDateFormat("yyyy/MM/dd").format(System.currentTimeMillis())
dialogBuilder
.setTitle("新增清單")
.setView(dialogItem)
.show()
date_button.setOnClickListener {
val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)
DatePickerDialog(this, { _, year, month, day ->
run {
// val format = "你設定的日期為:${setDateFormat(year, month, day)}"
// val formatDate = SimpleDateFormat("yyyy/MM/dd").parse("$year/$month/$day")
dialogDate.text = "$year/${month+1}/$day"
}
}, year, month, day).show()
}
}
}
}