I have a alertdialog that contains a hyperlink, however the hyperlink isn't clickable. It does show as a hyperlink
val termsDialog = AlertDialog.Builder(this#MainActivity)
val termsView = layoutInflater.inflate(R.layout.termsdialog, null)
val termsBox: CheckBox = termsView.findViewById(R.id.termsCheckbox)
val termsMsg = Html.fromHtml("By using this application you accept to our Terms and Conditions and Privacy Policy. \nMore information here")
termsDialog.setTitle("Terms and Conditions")
termsDialog.setView(termsView)
termsDialog.setMessage(termsMsg)
termsDialog.setPositiveButton("OK") { _, _ -> }
termsDialog.setCancelable(false)
termsBox.setOnCheckedChangeListener { compoundButton, _ ->
if (compoundButton.isChecked) {
storeDialogStatus(true)
} else {
storeDialogStatus(false)
}
}
// Automatic show terms dialog when dialog status is not checked
if (!this.getDialogStatus()) {
termsDialog.show()
}
Create a TextView for your message in termsdialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/dialog_textview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Then you must call setMovementMethod(LinkMovementMethod.getInstance()) on your TextView:
val termsDialog = AlertDialog.Builder(context)
val termsView = layoutInflater.inflate(R.layout.termsdialog, null)
val termsMessage: TextView = termsView.findViewById(R.id.dialog_textview)
val termsMsg = Html.fromHtml("By using this application you accept to our Terms and Conditions and Privacy Policy. \nMore information here")
termsDialog.setTitle("Terms and Conditions")
termsDialog.setView(termsView)
termsMessage.setText(termsMsg)
termsMessage.setMovementMethod(LinkMovementMethod.getInstance())
termsDialog.show()
Related
Currently, I have a Material Exposed Dropdown Menu in a popup window, but when I tap outside the popup window, I don't want it to be dismissed if the Material Exposed Dropdown Menu is open. As for what I have tried so far: I can set a setOnClickListener for the AppCompatAutoCompleteTextView with a boolean flag that changes when it is opened or closed, but this only impact whether the text is clicked in the Material Exposed Dropdown. If I set an onClickListener to the TextInputLayout it only works if I tap the border of the Material Exposed Dropdown Menu. If I setEndIconOnClickListener on arrow, it overrides whatever listener is attached by default and the dropdown menu is no longer opened, and the arrow no longer gets flipped, even if I set the Dropdown menu to open manually. I want a unified way to handle this so that the popup window is not dismissible when the material exposed dropdown menu is open. Not sure how much help it will be, but here is the code I have that is currently handling the menus:
private fun addIngredient(view: View) {
val fragmentWidth = view.width
val units = resources.getStringArray(R.array.add_ingredient_measurement_units)
val volUnits = resources.getStringArray(R.array.volumetric_measurement_units)
val massUnits = resources.getStringArray(R.array.mass_measurement_units)
val layoutInflater: LayoutInflater = context?.applicationContext?.getSystemService(
Context.LAYOUT_INFLATER_SERVICE
) as LayoutInflater
#SuppressLint("InflateParams")
val addInventoryPopup = layoutInflater.inflate(R.layout.add_inventory_popup, null)
val conversionLayoutContainer = addInventoryPopup.findViewById<LinearLayout>(R.id.add_ingredient_conversion_container)
val closeAddInventoryPopupFab = addInventoryPopup.findViewById<FloatingActionButton>(R.id.add_ingredient_close_fab)
val unitsMenu = addInventoryPopup.findViewById<AppCompatAutoCompleteTextView>(R.id.add_ingredient_units_menu)
val arrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_menu_item, units)
unitsMenu.setAdapter(arrayAdapter)
unitsMenu.addTextChangedListener {
conversionLayoutContainer.removeAllViews()
val currentText = it.toString()
if (volUnits.contains(currentText) || massUnits.contains(currentText)) {
val conversionLayout = layoutInflater.inflate(R.layout.convert_units, conversionLayoutContainer as ViewGroup)
val conversionHeaderText = conversionLayout.findViewById<TextView>(R.id.conversion_text)
val firstUnitMenu = conversionLayout.findViewById<AppCompatAutoCompleteTextView>(R.id.first_unit_menu)
firstUnitMenu.text = it
val secondUnitMenu = conversionLayout.findViewById<AppCompatAutoCompleteTextView>(R.id.second_unit_menu)
if (volUnits.contains(currentText)) {
conversionHeaderText.text = getString(R.string.vol_conversion_text)
val firstUnitArrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_menu_item, volUnits)
val secondUnitArrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_menu_item, massUnits)
firstUnitMenu.setAdapter(firstUnitArrayAdapter)
secondUnitMenu.setAdapter(secondUnitArrayAdapter)
} else if (massUnits.contains(currentText)) {
conversionHeaderText.text = getString(R.string.mass_conversion_text)
val firstUnitArrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_menu_item, massUnits)
val secondUnitArrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_menu_item, volUnits)
firstUnitMenu.setAdapter(firstUnitArrayAdapter)
secondUnitMenu.setAdapter(secondUnitArrayAdapter)
}
} else {
Toast.makeText(requireContext(), "No Unit", Toast.LENGTH_LONG).show()
}
}
val popupWindow = PopupWindow(
addInventoryPopup,
(fragmentWidth * 0.90).toInt(),
ViewGroup.LayoutParams.WRAP_CONTENT,
true
)
closeAddInventoryPopupFab.setOnClickListener { popupWindow.dismiss() }
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0)
}
and here is the part XML file of the layout I am using to inflate the Popup window that contains the material exposed dropdown menu:
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/add_ingredient_units_menu_container"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="54dp"
android:hint="#string/unit">
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="#+id/add_ingredient_units_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cursorVisible="false"
android:drawablePadding="-12dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="none"
android:padding="0dp"
android:text="#string/none"
android:textSize="15sp"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
Also my targetSDK is 33 and my min is 26.
When trying to make a popup dialog with paired bluetooth devices in a spinner, my app crashes upon opening. See this code for the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<Spinner
android:id="#+id/spinner_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/bConnectBtn"
android:text="CONNECT"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
In the code below here, I call a function that checks for bonded devices and then puts it in the spinner:
private fun onBluetoothEnabled() {
val bondedDevices = bluetoothAdapter?.bondedDevices
if (bondedDevices != null) {
val bondedAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, bondedDevices.map { it.name })
bondedAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner_devices.adapter = bondedAdapter
bConnectBtn.setOnClickListener {
val device = bondedDevices.toList()[spinner_devices.selectedItemPosition]
setupClient(device)
}
}
}
Here I show the dialog:
val bluetoothView = layoutInflater.inflate(R.layout.bluetoothdialog, null)
val bluetoothDialog = AlertDialog.Builder(this#MainActivity)
bluetoothDialog.setTitle("Paired Devices")
bluetoothDialog.setView(bluetoothView)
bluetoothDialog.setCancelable(false)
bluetoothDialog.setNeutralButton("TEMP CLOSE") { _, _ -> }
bluetoothDialog.show()
Some extra details about this, this works just fine when the spinner is in the main activity xml, but when I put the spinner in a popup dialog xml file, it crashes upon start. When I add ? or !! to spinner_devices?.adapter it works but doesn't fill the spinner with the bonded devices which makes sense because it allows null now.
When I debug my code, I can see that the bondedApapter gets filled with paired bluetooth devices, but when it gets to the spinner_devices.adapter it is null. Any guesses on what I am doing wrong?
There is some object initialization when you tries to bind adapter from AlertDialog. Checkout the below code that is working fine.
val bluetoothView = layoutInflater.inflate(R.layout.bluetoothdialog, null)
val bluetoothDialog = AlertDialog.Builder(this#MainActivity)
bluetoothDialog.setTitle("Paired Devices")
bluetoothDialog.setView(bluetoothView)
bluetoothDialog.setCancelable(false)
bluetoothDialog.setNeutralButton("TEMP CLOSE") { _, _ ->}
bluetoothDialog.show()
**//get views from inflated layout
val spinnerDevices = bluetoothView.findViewById(R.id.spinner_devices)
val bConnectBtn = bluetoothView.findViewById(R.id.bConnectBtn)**
//bind adapter
val bondedAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, bondedDevices.map { it.name })
bondedAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerDevices.adapter = bondedAdapter
bConnectBtn.setOnClickListener {
val device = bondedDevices.toList()[spinnerDevices.selectedItemPosition]
Toast.makeText(this#MainActivity,"Connection to:${device.name}",Toast.LENGTH_SHORT).show()
}
For those wondering. I was able to fix it and made it a bit more usefull by being able to click on a bluetooth device and make it connect. See code below for full code:
private fun showPairedDevicesPopup() {
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
val pairedDevices: Set<BluetoothDevice> = bluetoothAdapter.bondedDevices
// Create a list of device names
val deviceNames = ArrayList<String>()
pairedDevices.forEach { deviceNames.add(it.name) }
// Create an array adapter to display the list of device names
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, deviceNames)
// Build the alert dialog
val builder = AlertDialog.Builder(this)
builder.setTitle("Paired Devices")
builder.setCancelable(false)
builder.setAdapter(adapter) { _, which ->
// Get the selected device
val selectedDevice = pairedDevices.elementAt(which)
// Attempt to connect to the selected device
val socket: BluetoothSocket?
try {
socket = selectedDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
socket.connect()
} catch (e: IOException) {
// Failed to connect to the device
e.printStackTrace()
}
}
builder.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
// Show the alert dialog
val dialog = builder.create()
dialog.show()
}
I made a custom tab item for my tab layout and initialized it using view binding as follows:
val tabView = CustomTabBinding.inflate(LayoutInflater.from(mContext), null, false)
tabView.tvCustomTabTitle.text = it.title
tabView.tvCustomTabCount.visibility = View.GONE
Now when the user selects/unselects the tab I want to change the appearance of this custom view. Usually I achieved this using kotlin synthetics as follows:
fun setOnSelectView(tabLayout: TabLayout, position: Int = 0) {
val tab = tabLayout.getTabAt(position)
val selected = tab?.customView
if (selected != null)
selected.tv_custom_tab_title?.apply {
setTextColor(mContext.getColorCompat(R.color.colorAccent))
typeface = setFont(true)
}
selected?.tv_custom_tab_count?.apply {
setBackgroundResource(R.drawable.bullet_accent)
mContext.getColorCompat(android.R.color.white)
}
}
But now how do I achieve this using view binding?
I am using the method of findViewById():
fun Context.setOnSelectView(tabLayout: TabLayout, position: Int = 0) {
val tab = tabLayout.getTabAt(position)
val selected = tab?.customView
if (selected != null){
val title = selected.findViewById<TextView>(R.id.tv_custom_tab_title)
val count = selected.findViewById<TextView>(R.id.tv_custom_tab_count)
title.apply {
setTextColor(getColorCompat(R.color.colorAccent))
typeface = setFont(true)
}
count.apply {
setBackgroundResource(R.drawable.bullet_accent)
getColorCompat(android.R.color.white)
}
}
}
but I am hoping there is a better way to do this. If yes, then please do help me out.
Late reply but this is how I used view binding for custom tab layout, hope it helps
custom_tab.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv_custom_tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/tv_custom_tab_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
your activity/fragment:
val tab = binding.tabLayout.getTabAt(position)
tab.setCustomView(R.layout.custom_tab)
val tabBinding = tab.customView?.let {
CustomTabBinding.bind(it)
}
tabBinding?.tvCustomTabTitle?.text = "your title here"
Despite a lot of searches and trials, I can't avoid my AlertDialog to close if my EditText is empty... I saw that it was a current issue on StackOverflow with a lot of responses but when I try it, it doesn't work...
Here is my Kotlin code, thanks for your help...
import androidx.appcompat.app.AlertDialog
import android.content.DialogInterface
private fun showMyEditextDialog() {
val alertDialog = AlertDialog.Builder(this)
val view = layoutInflater.inflate(R.layout.my_layout, null)
val myedittext = view.findViewById(R.id.myedittext) as EditText
alertDialog.setTitle(getString(R.string.title))
alertDialog.setView(view)
alertDialog.setCancelable(false)
alertDialog.setPositiveButton(R.string.ok, DialogInterface.OnClickListener { dialogInterface, i ->
var isValid = true
if ( isEmpty(myedittext.text.toString()) ) {
isValid = false
Toast.makeText(this, "empty", Toast.LENGHT_SHORT).show()
}
if ( isValid ) {
Toast.makeText(this, "yeah!", Toast.LENGHT_SHORT).show() }
if ( isValid ) {
dialogInterface.dismiss()
}
})
}
My xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/question" />
<EditText
android:id="#+id/myedittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
</LinearLayout>
If I enter a value, I've got my "yeah" message.
If I don't enter a value, I've got my "empty" message but my dialog dismiss...
Thanks for your help,
MT
Use onShow to handle this like below:
val dialog = alertDialog.create()
dialog.setOnShowListener {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
var isValid = true
if ( isEmpty(myedittext.text.toString()) ) {
isValid = false
Toast.makeText(this#MainActivity, "empty", Toast.LENGTH_SHORT).show()
}
if ( isValid ) {
Toast.makeText(this#MainActivity, "yeah!", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
}
}
dialog.show()
I'm unsure if there's a way to bypass an alertdialog's buttons' functions. If there is, I've never found it. However, you could go with a much simpler solution. Just create your own "alert" view with an editText and buttons. Set the view to view.setVisibility(View.INVISIBLE) or (View.GONE), and any of its children views will be invisible or gone as well. I generally, when this is necessary, do this with a semi-transparent black background behind the view as the parent; and set that view's visibility back and forth. Then, you can customize the functionality of the buttons and the rest of the view in any way you want.
You need to get the positive button to override the method onclick
you can use this code:
private fun showMyEditextDialog() {
val alertDialog = AlertDialog.Builder(this)
val view = layoutInflater.inflate(R.layout.my_layout, null)
val myedittext = view.findViewById(R.id.myedittext) as EditText
alertDialog.setTitle(getString(R.string.title))
alertDialog.setView(view)
alertDialog.setCancelable(false)
alertDialog.setPositiveButton(R.string.ok, null)
alertDialog.create()
var dialog = alertDialog.create()
dialog.show()
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
var isValid = true
if ( isEmpty(myedittext.text.toString()) ) {
isValid = false
Toast.makeText(this, "empty", Toast.LENGTH_SHORT).show()
}
if ( isValid ) {
Toast.makeText(this, "yeah!", Toast.LENGTH_SHORT).show() }
if ( isValid ) {
dialog.dismiss()
}
}
}
I have this code:
var firstKitList = mutableListOf<String>("test", "potato", "another item")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_kit_list)
val mainKitList = kitListView
val mainListViewAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, firstKitList)
mainKitList.adapter = mainListViewAdapter
newKitListBtn.setOnClickListener {
// Handler code here.
val intent = Intent(this, NewKitListActivity::class.java)
startActivity(intent);
}
}
For this layout.
How do I go around for when I click the button, to show up an alert dialog for me too add a name (as if I was creating an item to be added to that list) and then go to the next activity? (this part is already created as you can see on the code)
I created function which hold alert dialog with editText. When your click on save name will be stored in multableList and redirected to new activity.
Modified Code
var firstKitList = mutableListOf<String>("test", "potato", "another item")
// Mutable List for holding names
val nameList = mutableListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_kit_list)
val mainKitList = kitListView
val mainListViewAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, firstKitList)
mainKitList.adapter = mainListViewAdapter
newKitListBtn.setOnClickListener {
// Show Alert Dialog
showNewNameDialog()
}
}
Alert Dialog Function
fun showNewNameDialog() {
val dialogBuilder = AlertDialog.Builder(this)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.custom_dialog, null)
dialogBuilder.setView(dialogView)
val editText = dialogView.findViewById<EditText>(R.id.editTextName)
dialogBuilder.setTitle("Custom dialog")
dialogBuilder.setMessage("Enter Name Below")
dialogBuilder.setPositiveButton("Save", { dialog, whichButton ->
//do something with edt.getText().toString();
// Add Name in list
nameList.add(editText.text.toString())
// Handler code here.
val intent = Intent(this, NewKitListActivity::class.java)
startActivity(intent);
})
dialogBuilder.setNegativeButton("Cancel", { dialog, whichButton ->
//pass
})
val b = dialogBuilder.create()
b.show()
}
Custom Dialog Layout: custom_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<EditText
android:id="#+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
I changed the code from Rajesh Dalsaniya's answer to be a bit more concise using kotlin's features:
fun showNewNameDialog(activity: Activity) {
AlertDialog.Builder(activity).apply {
val dialogView = activity.layoutInflater.inflate(R.layout.custom_dialog, null)
val editText = dialogView.findViewById<EditText>(R.id.editTextName)
setView(dialogView)
setTitle("Custom dialog")
setMessage("Enter Name Below")
setPositiveButton("Save") { _, _ ->
//do something with edt.getText().toString();
// Add Name in list
activity.nameList.add(editText.text.toString())
// Handler code here.
val intent = Intent(activity, NewKitListActivity::class.java)
activity.startActivity(intent);
}
setNegativeButton("Cancel") { _, _ ->
//pass
}
}.create().show()
}
The xml stays:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<EditText
android:id="#+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>