I'm trying to make a mobile application with a button that should create an Alert dialog with a search bar in it, However for some reason i can't get the MultiAutoCompleteTextView to work with it as it keeps giving me KotlinNullPointerExceptions. and adding nullpointer safety will just skip the setting the adapter.
addItem.setOnClickListener {
val builder = AlertDialog.Builder(this).create()
val alertview = View.inflate(this, R.layout.content_searchproduct, null)
val itemsList = listOf("Item1","items2","Btem3","btem4")
builder.setView(alertview)
val textfield =builder.findViewById<MultiAutoCompleteTextView>(R.id.textidplaceholder)
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, itemsList)
textfield!!.setAdapter(adapter)
textfield.threshold = 1
builder.textidplaceholder.setTokenizer(MultiAutoCompleteTextView.CommaTokenizer())
builder.setButton(AlertDialog.BUTTON_POSITIVE,"Add") { _: DialogInterface?, _: Int -> searchProducts(textfield.text.toString()) }
builder.setButton(AlertDialog.BUTTON_NEGATIVE,"Cancel") { _: DialogInterface?, _: Int -> }
builder.show()
}
Do this :
val textfield =alertview.findViewById<MultiAutoCompleteTextView>(R.id.textidplaceholder)
instead of :
val textfield =builder.findViewById<MultiAutoCompleteTextView>(R.id.textidplaceholder)
Related
I have custom dialog where inside its xml has a Submit button that whenever clicked, it should dismiss the softKeyboard.
I have the following code:
MainActivity.kt (Inherits from BaseActivity)
val updateDialog = Dialog(this, R.style.CustomDialog)
updateDialog.setContentView(R.layout.dialog_update)
val tvSubmitToFirestore = updateDialog.findViewById<HelveticaBoldTextView>(R.id.tv_update_item)
tvSubmitToFirestore.setOnClickListener {
hideKeyboard(currentFocus ?: View(this))
}
BaseActivity:
open class BaseActivity : AppCompatActivity() {
//hide keyboard when instance of an event
fun Context.hideKeyboard(view: View) {
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
But the keyboard remains on its position after clicking the said button.
Update:
//update item
val tvUpdate = showItemDialog.findViewById<HelveticaNormalTextView>(R.id.tv_update)
tvUpdate.setOnClickListener {
//close search dialog
showItemDialog.dismiss()
val updateDialog = Dialog(this, R.style.CustomDialog)
updateDialog.setContentView(R.layout.dialog_update)
updateDialog.setCancelable(false)
//spinner settings
val spinner = updateDialog.findViewById<Spinner>(R.id.sp_update)
populateSpinner(spinner, dialogProductCategory.text.toString())
//set default values of update dialog fields == the current product's properties(name, category, price)
val etProductName = updateDialog.findViewById<TextInputEditText>(R.id.et_update_product_name)
val etProductPrice = updateDialog.findViewById<TextInputEditText>(R.id.et_update_product_price)
etProductName.setText(dialogProdName.text.toString())
etProductPrice.setText(dialogProductPrice.text.toString())
//update item
val tvSubmitToFirestore = updateDialog.findViewById<HelveticaBoldTextView>(R.id.tv_update_item)
//TODO allow user to update an item with the same name provided that it should only exist once
// and must be unique
tvSubmitToFirestore.setOnClickListener {
// hideKeyboard(currentFocus ?: tvSubmitToFirestore)
hideKeyboard1(it, this#MainActivity)
val newProductName = etProductName.text.toString().trim()
val newProductCategory = spinner.selectedItem.toString().uppercase()
val newProductPrice = etProductPrice.text.toString().toDouble()
GlobalScope.launch {
validateProduct(newProductName, newProductCategory, newProductPrice)
}
//TODO : allow user to reuse the product name when updating
}
You can use the new WindowInsetsController library to hide and show keyboard. Use this function:
fun hideKeyboard(view: View, activity: Activity) {
WindowInsetsControllerCompat(activity.window, view).hide(WindowInsetsCompat.Type.ime())
}
In your case, you call use it like this:
tvSubmitToFirestore.setOnClickListener { view ->
hideKeyboard(view, this) // 'this' refers to MainActivity
}
I have a custom dialog in my android project and it was working fine. After I removed kotlin extension from the project, I have modified my code as follows but there is some issue with the Views in the custom dialog. Codes etTitle.visibility = View.GONE and val newRequest = etDetail.text.toString() didn't work as I expected. It didn't hide the view etTitle and the value in the EditText etDetail is not picked also, it always returns emplty even when there is some value.
private lateinit var bindingDialogLayout: CustomDialogBinding
fun specialRequestDialog(currentRequest: String?) {
bindingDialogLayout = CustomDialogBinding.inflate(layoutInflater)
val dialogLayout = layoutInflater.inflate(R.layout.custom_dialog, null)
val etTitle = bindingDialogLayout.etTitle
val etDetail = bindingDialogLayout.etDetails
etTitle.visibility = View.GONE
etDetail.setText(currentRequest)
MaterialAlertDialogBuilder(this)
.setTitle("What is your special request?")
.setCancelable(false)
.setPositiveButton("Save") { dialog, which ->
val newRequest = etDetail.text.toString()
if (newRequest.isEmpty()) {
showErrorSnackBar("Type in if you have any special request, else hit cancel", true)
} else {
addButton.visibility = View.GONE
deleteButton.visibility = View.VISIBLE
}
}
.setNegativeButton("Cancel") { dialog, which ->
dialog?.dismiss()
}
.setView(dialogLayout)
.show()
}
You set the wrong view to the dialog.
Use this instead:
.setView(bindingDialogLayout.root)
I implemented a "Don't show again" option to my Alert Dialog, but it's not working as intended:
All the other questions are 6-7 years old and in java, and since I am completely new to programming I only know the basics of kotlin as of right now..
fun showDialog() {
val dialogBuilder = AlertDialog.Builder(context)
val inflater = requireActivity().layoutInflater;
dialogBuilder.setView(inflater.inflate(R.layout.alert, null))
dialogBuilder.setMessage("Please always put the total on the bottom right corner. An example is shown below.")
dialogBuilder.setPositiveButton("Alright, got it!",
DialogInterface.OnClickListener { dialog, whichButton ->
pb.visibility = View.VISIBLE
checkPermission(Manifest.permission.CAMERA,CAMERA_PERMISSION_CODE)
startActivityForResult(receiptsViewModel.cameraIntent(requireActivity()),REQUEST_CODE_KAMERA)
})
val mainView: View = inflater.inflate(R.layout.alert, null)
checkBox = mainView.findViewById<View>(R.id.checkBox) as CheckBox
val b = dialogBuilder.create()
b.show()
checkBox.setOnCheckedChangeListener { compoundButton, b ->
if (compoundButton.isChecked) {
storeDialogStatus(true)
} else {
storeDialogStatus(false)
}
}
if (dialogStatus) {
b.hide()
} else {
b.show()
}
}
private fun storeDialogStatus(isChecked: Boolean) {
val mSharedPreferences = requireActivity().getSharedPreferences("CheckItem", AppCompatActivity.MODE_PRIVATE)
val mEditor = mSharedPreferences.edit()
mEditor.putBoolean("item", isChecked)
mEditor.apply()
}
private val dialogStatus: Boolean
private get() {
val mSharedPreferences = requireActivity().getSharedPreferences("CheckItem",
AppCompatActivity.MODE_PRIVATE
)
return mSharedPreferences.getBoolean("item", false)
}
The problem I see is that the checkbox that you're adding a listener to is for a layout that you're not using. You inflated a layout and set that as your dialog view. Then you inflate a second copy of the layout and set a listener on the checkbox in that unused second layout.
A few other tips, but these aren't things that are preventing it from working. They'll just make your code clearer:
You can chain Builder calls so you don't have to keep putting dialogBuilder. and you don't even have to store it in a variable.
findViewById<View> can be changed to findViewById<CheckBox> so you don't have to cast its result to CheckBox.
You can return early from the function if the dialog isn't needed rather than creating the dialog, showing it, and then immediately hiding it.
Instead of using if (someBoolean) doSomething(true) else doSomething(false) you can simplify to doSomething(someBoolean).
private fun startCamera() {
pb.visibility = View.VISIBLE
checkPermission(Manifest.permission.CAMERA,CAMERA_PERMISSION_CODE)
startActivityForResult(
receiptsViewModel.cameraIntent(requireActivity()),
REQUEST_CODE_KAMERA
)
}
fun showDialog() {
if (dialogStatus) {
startCamera()
return
}
val mainView = requireActivity().layoutInflater.inflate(R.layout.alert, null)
checkBox = mainView.findViewById<CheckBox>(R.id.checkBox)
checkBox.setOnCheckedChangeListener { compoundButton, b ->
storeDialogStatus(compoundButton.isChecked)
}
AlertDialog.Builder(context)
.setView(mainView)
.setMessage("Please always put the total on the bottom right corner. An example is shown below.")
.setPositiveButton("Alright, got it!") { _, _ -> startCamera() }
.create()
.show()
}
I also find it odd that you have a property for checkBox that couldn't possibly be useful outside this function. You should probably remove the property.
Also, you should look into using DialogFragment instead of a bare Dialog. There are issues with bare Dialogs, such as them disappearing after a screen rotation. The official documentation explains how to use DialogFragment. I will admit, though, that I think DialogFragment is kind of convoluted to use, especially for a new Android programmer.
Your logic seems to be faulty. This piece of code does not work as intended:
if (dialogStatus) {
b.hide()
} else {
b.show()
}
You should not create the dialog at all if the user has opted out. Please try this modified code:
fun showDialog() {
if (dialogStatus) {
return
}
val dialogBuilder = AlertDialog.Builder(context)
val inflater = requireActivity().layoutInflater
dialogBuilder.setView(inflater.inflate(R.layout.alert, null))
.setMessage("Please always put the total on the bottom right corner. An example is shown below.")
.setPositiveButton("Alright, got it!",
DialogInterface.OnClickListener { dialog, whichButton ->
pb.visibility = View.VISIBLE
checkPermission(Manifest.permission.CAMERA, CAMERA_PERMISSION_CODE)
startActivityForResult(
receiptsViewModel.cameraIntent(requireActivity()),
REQUEST_CODE_KAMERA
)
})
dialogBuilder.create().show()
val mainView: View = inflater.inflate(R.layout.alert, null)
checkBox = mainView.findViewById<CheckBox>(R.id.checkBox)
checkBox.setOnCheckedChangeListener { compoundButton, b ->
if (compoundButton.isChecked) {
storeDialogStatus(true)
} else {
storeDialogStatus(false)
}
}
}
ImageView in first alert dialog opens second dialog to change an imageResource of the ImageView in the first dialog. However I don't know how to make connection between two alert dialogs
Both have different xml layouts, so I assume that in second dialog I should make a reference to the layout of the first dialog
private fun editItemDialog() {
val dialogBuilder1 = AlertDialog.Builder(this)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.edit_dialog, null)
dialogBuilder1.setView(dialogView)
var editIconButton = dialogView.findViewById<View>(R.id.editIcon) as ImageView
editIconButton.setOnClickListener{
showIconDialog()
}
dialogBuilder1.setTitle("Edit mode")
dialogBuilder1.setPositiveButton("Save") { _, _ ->
//sth
}
dialogBuilder1.setNegativeButton("Cancel") { _, _ ->
//sth
}
val b = dialogBuilder1.create()
b.show()
}
private fun showIconDialog() {
val dialogBuilder = AlertDialog.Builder(this)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.icons, null)
dialogBuilder.setView(dialogView)
//examplary two icons to select
var travelRB = dialogView.findViewById<View>(R.id.travel) as RadioButton
var travRB = dialogView.findViewById<View>(R.id.travel) as RadioButton
dialogBuilder.setTitle("Icon dialog")
dialogBuilder.setMessage("Select an icon")
dialogBuilder.setPositiveButton("Save") { _, _ ->
//here I would like to change an icon of the ImageView, for example:
editIconButton.setImageResource(R.id.travel)
dialogBuilder.setNegativeButton("Cancel") { _, _ ->
//sth
}
val b = dialogBuilder.create()
b.show()
}
You can add a callback to the second dialog
fun showIconDialog(callback : (Drawable) -> Unit) {
//code
callback.invoke(someDrawable)
}
And on the first one you just do this:
showIconDialog() { someDrawable ->
//code to change the layout src icon
}
Once the user clicks on change_account on my activity a dialog was shown then once the user clicks on create count on this dialog I want to show another dialog.
But unfortunately I got this error:
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I have seen on the net some code to removeView() but I do not know how to use it. Especially because I call the dialogue from another dialog.
and here is my code the line which causes the error is that one
creatCount.create().apply { show() }
And here is the complete code:
class ClientAcountActivity : AppCompatActivity(),AdapterView.OnItemClickListener{
override fun onCreate(savedInstanceState: Bundle?) {
....
change_account.setOnClickListener { openChangeCompte() }
}
fun openChangeCompte()
{
val dialogBuilder = AlertDialog.Builder(this)
val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val row = inflater.inflate(R.layout.dialog_listview, null, false)
val listAccount= row.findViewById<ListView>(R.id.transfer_type_list)
Log.d("ClientAccountActivity", Injection.provideAccountRepository().availableAccountsType.toString())
listAccount.adapter = CountChangeAdapter(Injection.provideAccountRepository().availableAccountsType, this)
listAccount.onItemClickListener = AdapterView.OnItemClickListener { adapterView: AdapterView<*>, view: View, i: Int, id: Long ->
if((adapterView.getCount()!=4) && (i==adapterView.getCount()-1))
{
val creatCount: AlertDialog.Builder = AlertDialog.Builder(this).apply {
setView(row)
setTitle("Quel compte voulez vous créer ")
setPositiveButton("OK", DialogInterface.OnClickListener() {
dialogInterface: DialogInterface, i: Int ->
fun onClick(dialog:DialogInterface , which:Int) {
}})
setNegativeButton("Cancel", DialogInterface.OnClickListener() {
dialogInterface: DialogInterface, i: Int ->
fun onClick(dialog:DialogInterface , which:Int) {
finish()
}})
}
creatCount.create().apply { show() } //the line which cause the pb
}
else
{
Injection.provideAccountRepository().selectedAccount=id.toInt()
updateBalance()
changeAccoutDialog!!.dismiss()
}
}
dialogBuilder.setView(row)
dialogBuilder.setTitle("Quel compte voulez vous choisir?")
changeAccoutDialog = dialogBuilder.create().apply { show() }
}
}
The problem here is due to setting the variable row into two dialog's view: you should create a second row (with the same layout using inflater) in order to set it to the second dialog. Here is the code corrected:
fun openChangeCompte()
{
val dialogBuilder = AlertDialog.Builder(this)
val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val row = inflater.inflate(R.layout.dialog_listview, null)
val listAccount= row.findViewById<ListView>(R.id.transfer_type_list)
Log.d("ClientAccountActivity", Injection.provideAccountRepository().availableAccountsType.toString())
listAccount.adapter = CountChangeAdapter(Injection.provideAccountRepository().availableAccountsType, this)
listAccount.onItemClickListener = AdapterView.OnItemClickListener { adapterView: AdapterView<*>, view: View, i: Int, id: Long ->
if((adapterView.count !=4) && (i==adapterView.count -1))
{
val row2 = inflater.inflate(R.layout.dialog_listview, null)
val listAccount= row2.findViewById<ListView>(R.id.transfer_type_list)
val creatCount: AlertDialog.Builder = AlertDialog.Builder(this).apply {
setView(row2)
setTitle("Quel compte voulez vous créer ")
setPositiveButton("OK") { _: DialogInterface, _: Int ->
fun onClick(dialog:DialogInterface , which:Int) {
}}
setNegativeButton("Cancel") { _: DialogInterface, _: Int ->
fun onClick(dialog: DialogInterface, which:Int) {
finish()
}}
}
creatCount.create().apply { show() } //the line wich cause the pb
}
else
{
Injection.provideAccountRepository().selectedAccount=id.toInt()
updateBalance()
changeAccoutDialog !!.dismiss()
}
}
dialogBuilder.setView(row)
dialogBuilder.setTitle("Quel compte voulez vous choisir?")
changeAccoutDialog = dialogBuilder.create().apply { show() }
}