I have multiple option select and I need to get array of selected options but all I get is latest option selected.
Code
class PublishActivity : AppCompatActivity() {
var selectedTags: List<String>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_publish)
pTags.setOnClickListener {
var tagIds = ArrayList<String>()
val tagOptions = ArrayList<String>()
for (i in tags) {
tagOptions.add(i.title)
tagIds.add(i.id)
}
var checkedItems = ArrayList<Int>()
checkedItems.forEach{ index -> tagIds[index + 1] }
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.project_tags))
.setMultiChoiceItems(tagOptions.toTypedArray(), null) { dialog, which, checked ->
if (checked) {
checkedItems.add(which)
} else if (checkedItems.contains(which)) {
checkedItems.remove(Integer.valueOf(which))
}
// Respond to item chosen
pTags.setText("${checkedItems.size} tags selected")
}
.setPositiveButton(resources.getString(R.string.ok)) { dialog, which ->
for (i in checkedItems) {
Log.d("eeee1", tagOptions[i])
selectedTags = listOf(tagOptions[i])
}
}
.setNeutralButton(resources.getString(R.string.clear)) { dialog, which ->
pTags.text = null
pTags.hint = "0 tag selected"
if (checkedItems.size > 0) {
checkedItems.clear()
}
}
.show()
}
}
}
Log.d("eeee1", tagOptions[i]) returns such data in logcat
D/eeee1: 3D Printing
D/eeee1: 3D Architecture
D/eeee1: .NET/Mono
D/eeee1: ActionScript
but in my selectedTags I get only D/eeer1: [ActionScript]
It supposed to give me something like this D/eeer1: ["3D Printing", "3D Architecture", ".NET/Mono", "ActionScript"]
PS: what I'm actually look to achieve here is to get id of those selected items instead of their names that's why I have var tagIds = ArrayList<String>() but if that's not possible to achieve as long as it just return array of all names (like sample above) it's fine by me as well.
Any idea?
The following code sets your variable to a list with a single item. So you just overwrite your variable over and over again
selectedTags = listOf(tagOptions[i])
you need:
//Declaration
var selectedTags: MutableList<String> = mutableListOf()
...
// In loop
selectedTags.add(tagOptions[i])
You could also do it with a more functional approach:
//Declaration
var selectedTags: List<String>? = listOf()
...
// Skip the loop and use the map function
.setPositiveButton(resources.getString(R.string.ok)) { dialog, which ->
selectedTags = checkedItems.map{ tagOptions[it] }
}
To get the Id's instead of the titles you should just be able to use your tagIds instead of tagOptions. Just make sure that you get your typing right. The selectedTags list needs to be of the same type as tag.id.
You are getting only last inserted value because you are creating fresh list when ok button is clicked and assigning it to selectedTags. Problem at selectedTags = listOf(tagOptions[i]) line of your code.
Solution:
Declare a single list and put selected values into it. Like :
val selectedTags = arrayListOf<String>()
then use below code inside ok button click:
.setPositiveButton("Ok") { dialog, which ->
for (i in checkedItems) {
//selectedTags = listOf(tagOptions[i])
selectedTags.add(tagOptions[i])
}
}
Related
I have created a variable private var deals=ArrayList<Deals>() in a fragment and I have set a click listener in the onCerateView() like the following.
binding.tvAllDeals.setOnClickListener {
viewAllDeals()
}
So that it will trigger the following method
private fun viewAllDeals(){
val intent = Intent(context,ViewAllDealsActivity::class.java)
intent.putExtra("details",deals)
Log.d("Tag2", "Size is ${deals.size}")
startActivity(intent)
}
I have the following function to get the data from the firestore and then I save the result in the variable 'deals'. However, whenever I click the 'tvAllDeals' it shows many images, when I check the size of the 'deals' using Log.d 'Tag1' always shows the correct size, which is 3, whereas 'Tag2' show some random numbers like 6, 9, 24. I try to find out why this is happening but I didn't get any idea. The variable 'deals' is not used anywhere else other than declaring and initializing, to assign the value and to pass it in the 'viewAllDeals()'
private fun getDeals() {
FirestoreClass().getDeals(
onSuccess = { list ->
Result.success(list)
successDeals(list) ///// THIS FUNCTION WILL SHOW THE IMAGES IN A VIEWPAGER
deals.clear()
deals=list
Log.d("Tag1", "Size is ${deals.size}")
},
onFailure = {
}
)
}
Edit:
NOTE: 'Tag3' also shows correct array size like 'Tag1'. However,
private fun successDeals(list: ArrayList<Deals>) {
Log.d("Tag3", "Size is ${deals.size}")
if (list.size > 0) {
binding.vpDeals.visibility = View.VISIBLE
val adapter = DealsAdapter(binding.vpDeals,requireContext(), list)
binding.vpDeals.adapter = adapter
binding.vpDeals.orientation = ViewPager2.ORIENTATION_HORIZONTAL
sliderHandle= Handler()
sliderRun= Runnable {
binding.vpDeals.currentItem=binding.vpDeals.currentItem+1
}
binding.vpDeals.registerOnPageChangeCallback(
object :ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
sliderHandle.removeCallbacks(sliderRun)
sliderHandle.postDelayed(sliderRun,4000)
}
}
)
} else {
binding.vpDeals.visibility = View.GONE
}
}
I have a MutableList in my Android project where i'm adding an object called Articolo, then when a new item is added to that list i need to check if one item with same ID exist and if it does i need to update it's quantity.
The issue is that i'm trying to use MutableList.find to find the object with the same ID and when i find it i'm simply add the quantity to existing quantity but instead it remains immutable.
Here is my Articolo.kt
data class Articolo(var barcode: String, var qta: Int) {
constructor() : this ("", 0)
}
And here is my function where i'm adding data to MutableList
private var articoli = mutableListOf<Articolo>()
private fun addBarcode(barcode: String, qta: Int) {
if (barcode.isEmpty()) {
txtBarcode.requestFocus()
return;
}
articoli.find{
it.barcode == barcode
}?.qta?.plus(qta) ?:
articoli.add(Articolo(barcode, qta))
}
So if i add the first object like barcode: 1111, qty: 1 and then another same object instead of having one element array with qty 2 i still have qty 1..
That's because .plus(Int) returns a new value. You're not changing the property.
Instead you should do:
fun addBarcode(barcode: String, qta: Int) {
val existant = articoli.find { it.barcode == barcode }
if (existant != null) existant.qta += qta
else articoli.add(Articolo(barcode, qta))
}
#VaiTon86 has the answer (you're not actually changing the value in the Articolo object) but really, you should probably be using a Map here anyway:
maximum one of each item
lookup by some value (barcode)
that's a map!
There's a few ways you could implement it, here's one:
val articoli = mutableMapOf<String, Articolo>()
private fun addBarcode(barcode: String, qta: Int) {
articoli.getOrPut(barcode) { Articolo(barcode, 0) }
.let { it.qta += qta }
}
So the getOrPut just adds a new zero-quantity Articolo entry if there isn't already one, and then you add qta to what's already there for that entry.
I am trying to initialize my array upon user input. Say if the user enters an item into the text field and then they press the add button, I want the string from the text field to go into the array.
class CustomList : AppCompatActivity() {
lateinit var thingsList: MutableList<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom_list)
addItemBtn.setOnClickListener {
if(item_text_field.text.toString() == "") {
Toast.makeText(this, "Must enter text first", Toast.LENGTH_SHORT).show()
} else {
val item = item_text_field.text.toString()
thingsList = item
}
}
}
}
There's no need of lateinit here, and unless you initialize the variable you cannot add items to it. You can instead use lazy to initialize it when needed. And the MutableList.add() is used to add items to a list.
// thingsList will be initialized whenever accessed for the first time
val thingsList by lazy { mutableListOf<String>() }
addItemBtn.setOnClickListener {
if(item_text_field.text.toString() == "") {
Toast.makeText(this, "Must enter text first", Toast.LENGTH_SHORT).show()
} else {
// use add on the MutableList to add times into it
thingsList.add(item_text_field.text.toString())
}
}
In my code, I create a mutable list and add elements from a model:
var lista: MutableList<ExpenseItem> = mutableListOf()
...
class ExpenseItem (val name: String, val word: String, val flavour: String)
...
val currentExpense = ExpenseItem("Sergio", "Aguacate", "Duro")
val currentExpense1 = ExpenseItem("amaya", "fresas", "pan")
val currentExpense2 = ExpenseItem("emma", "limon", "agua")
lista.add(currentExpense)
lista.add(currentExpense1)
lista.add(currentExpense2)
Now I am looking for a way to remove elements knowing, for example, the ´name´ field
I have tried the filters, remove, drop, etc for the list. I've also tried "when", but I think I'm not finding the correct syntax or way to do it,
I really appreciate the help.
It sounds like the method you want is
lista.removeAll { it.name == nameToRemove }
If you intend to modiify the actual list, then you'll want removeAll.
lista.removeAll {
it.name == "nameToRemove"
}
If you don't want to modify the original list, then filter can you get a new list without those elements.
val newList = lista.filter{
it.name != "nameToRemove"
}
Below shows a complete explanation of the behavior
var list: MutableList<String> = mutableListOf("1","2", "3")
//Shows all items
list.forEach {
println(it)
}
//Makes a new list with all items that are not equal to 1
val newList = list.filter {
it != "1"
}
newList.forEach {
println(it)
}
//Original list is untouched
list.forEach {
println(it)
}
//Modifies this list to remove all items that are 1
list.removeAll {
it == "1"
}
list.forEach {
println(it)
}
I have list of ids and I am maping it to list of sublists so getting list> and then I need to get one list of items but I don't know the proper operator for it.
.map { it ->
val step = 200
var count = it.stores.size
val subLists = ArrayList<List<Int>>()
var i = 1
while (count > 0) {
val start = (i - 1) * step
//if...
var end = i * step
count -= step
val items = it.items.subList(start, end)
subLists.add(items)
i++
}
subLists
}
.toFlowable()
.flatMapIterable { it -> it }
.flatMap {
personDao.loadById(it)
}.toList()
.I need to get one list of items , how?
You can just simply use:
val oldList: List<List<T>> = listOf()
val newList = oldList.flatMap { it }
And you don't have to use Rx for it
If you need Rx:
val flowable = Flowable.fromIterable(oldList).flatMap {
Flowable.fromIterable(it)
}
And you get Flowable<T>
I want to answer my question which I haven't thought well .so my answer use map and inside map go over list and it to list of Items
.map {
var items = emptyList<Item>()
it.map {
items += it
}
items
}.toFlowable()