I have 6 repetitive codes and I just want to use for-loop logic.
I tried to use "getIdentifier" and "findViewById" But I failed.
val sb_spinner_secret_p1: Spinner = findViewById(R.id.sb_secret1)
ArrayAdapter.createFromResource(this, R.array.secret, android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
sb_spinner_secret_p1.adapter = adapter
}
I tried this but it never works
for(i in 1..7){
val sb_spinner = "sb_spinner_secret_p$i"
val sbsecret = "sb_secret$i"
val sb_spinner_resId = resources.getIdentifier(sb_spinner,"id", packageName)
val sbsecret_resId = resources.getIdentifier(sbsecret,"id", packageName)
}
Related
How to pass all elements from "data" to "simpleData" for SimpleAdapter? For instance we have 100+ elements, it is not resonable to write elements by one. (should i use a loop? but how?)
TITLE doesn't show properly when simpleAdapter has used:[https://i.stack.imgur.com/W1kgJ.png]
hope you can help me, thanks in advance <3
val data = listOf<Book>(
Book("Memory", R.drawable.cover_1),
Book("The king of drugs", R.drawable.cover_2),
Book("SIN", R.drawable.cover_4),
Book("The martian", R.drawable.cover_5),
Book("No place like here", R.drawable.cover_6),
)
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityMainBinding.inflate(layoutInflater).also { setContentView(it.root) }
super.onCreate(savedInstanceState)
setupMyBookAdapter()
setupMySimpleAdapter()
}
private fun setupMySimpleAdapter() {
val simpleData = mutableListOf(
mapOf(TITLE to data[0].title, PHOTO to data[0].thumbnail),
mapOf(TITLE to data[1].title, PHOTO to data[1].thumbnail),
...
...
mapOf(TITLE to data[n].title, PHOTO to data[n].thumbnail)
)
val adapter2 = SimpleAdapter(this, simpleData, R.layout.cardview_item, arrayOf(TITLE, PHOTO), intArrayOf(R.id.book_title,R.id.book_cover))
binding.mylistview2.adapter = adapter2
}
Set title and cover of books as equal resources, for example R.string.title_0, R.drawable.cover_0.
Next use loop:
int i=0;
while( true ){
int id = getResources().getIdentifier( "title_"+i, "string", getPackageName() );
if( id > 0){
String title = getString(id);
// add to List here
i++;
}else{
break;
}
}
in my ViewModel:
private val _itemList = mutableStateListOf<Post>()
val itemList: List<Post> = _itemList
fun likePost(newPost: Post){
val index = _itemList.indexOf(newPost)
_itemList[index] = _itemList[index].copy(isLiked = true)
}
Here my Post data class:
data class Post(
val id: Int,
val name: String,
val isLiked: Boolean = false,
)
And here my Composable:
val postList = viewModel.itemList
LazyRow(content = {
items(postList.size) { i ->
val postItem = postList[i]
PostItem(
name = postItem.name,
isLiked = postItem.isLiked,
likePost = { viewModel.likePost(postItem)}
)
}
})
The change does not update in the UI instantly, I first have to scroll the updated item out of the screen so it recomposes or switch to another Screen and go back to see the change.
For some reason it doesn't like updating, it will add and delete and update instantly. You have to do it this way when updating for our to update the state.
fun likePost(newPost: Post){
val index = _itemList.indexOf(newPost)
_itemList[index] = _itemList[index].copy()
_itemList[index].isLiked = true
}
You are returning a List<> effectively and not MutableStateList from your ViewModel.
If you want the list to not be mutable from the view, I happen to use MutableStateFlow<List<>> and return StateFlow<List<>>. You could also just convert it to a list in your composable.
Edit:
//backing cached list, or could be data source like database
private val deviceList = mutableListOf<Device>()
private val _deviceListState = MutableStateFlow<List<Device>>(emptyList())
val deviceListState: StateFlow<List<BluetoothDevice>> = _deviceListState
//manipulate and publish
fun doSomething() {
_deviceListState.value = deviceList.filter ...
}
In your UI
val deviceListState = viewModel.deviceListState.collectAsState().value
I am trying to use TinyDB from Github to save a list (mustableListOf), however when I try to save a string to the List, it puts an error on the 2nd parameter.
val tinydb = TinyDB(this)
var todoList = mutableListOf(
Todo("Write your first TODO statement", false)
)
val adapter = TodoAdapter(todoList)
binding.rvTodos.adapter = adapter
binding.rvTodos.layoutManager = LinearLayoutManager(this)
binding.btnAddTodo.setOnClickListener {
val title = binding.etTodo.text.toString()
val todo = Todo(title, false)
todoList.add(todo)
//puts an error on the "mutableListOf(todoList)"
tinydb.putListString("TodoList", mutableListOf(todoList))
adapter.notifyItemInserted(todoList.size - 1)
}
How could I resolve this?
Github TinyDB Link: https://github.com/kcochibili/TinyDB--Android-Shared-Preferences-Turbo
Updated code: however when the app is launched on my phone, the app keeps stopping. It only works the first time when nothing is stored in TinyDB. It doesn't put an error on the 2nd parameter anymore, but I feel like it's not storing/working in its intended way. Thanks.
val tinydb = TinyDB(this)
var todoList = mutableListOf(
Todo("Write your first TODO statement", false)
)
// line below is to get the list and set it to recyclerview; however app keeps stopping when invoked
tinydb.getListObject("TodoList", Todo::class.java)
val adapter = TodoAdapter(todoList)
binding.rvTodos.adapter = adapter
binding.rvTodos.layoutManager = LinearLayoutManager(this)
binding.btnAddTodo.setOnClickListener {
val title = binding.etTodo.text.toString()
val todo = Todo(title, false)
todoList.add(todo)
//changed to putListObject
tinydb.putListObject("TodoList", arrayListOf(todoList))
adapter.notifyItemInserted(todoList.size - 1)
}
Updating value of recyclerview but unable to update corresponding data in model class
Model classes
#Parcelize
class GetStockListData : ArrayList<GetStockListDataItem>(), Parcelable
#Parcelize
data class GetStockListDataItem(
var Qty:#RawValue Double,
var selectedQty: Double
): Parcelable
able to change recyclerview element using alertbox as follows
private fun showAlertDialog(stockListData: GetStockListData, position: Int) {
val layoutInflater = LayoutInflater.from(context)
val customView =
layoutInflater.inflate(R.layout.change_qty_dialog, null)
val myBox: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(context)
myBox.setView(customView)
val dialog = myBox.create()
dialog.show()
val etQuantity = customView.findViewById<AppCompatEditText>(R.id.et_quantity)
if (stockListData[position].Qty < args.getListDetailsByRNumberModelItem.ReqQty) {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
etQuantity.setText(df.format(stockListData[position].Qty).toString())
} else
etQuantity.setText(args.getListDetailsByRNumberModelItem.ReqQty.toString())
etQuantity.setSelection(etQuantity.text.toString().length)
etQuantity.requestFocus()
requireContext().showKeyboard()
customView.findViewById<Button>(R.id.btnDone).setOnClickListener {
if(!etQuantity.text.isNullOrEmpty()) {
val qtyStr = etQuantity.text.toString().trim()
var qtyDouble = qtyStr.toDouble()
stockListData[position].selectedQty = qtyDouble
adapter.notifyDataSetChanged()
dialog.dismiss()
}
}
}
for (i in 0 until stockListData.size){
sum += stockListData[i].selectedQty
}
here if user edit Recyclerview list item multiple times, each value added to list. Finally if i try to retrieve sum of all recyclerview elements getting wrong value because in model class values are added when i try to replace element.
Instead of passing whole list as parameter to showAlertDialog() method, you could just pass single item which has to be updated. And one more thing, you should not call adapter.notifyDataSetChanged() for single item updation, rather call adapter.notifyItemChanged(position). Look at below code, I am getting correct sum :
private fun showRecipeMeasureDialog(recipeItem: RecipeItem?,position: Int){
val dialogView = LayoutInflater.from(context).inflate(R.layout.add_recipe_measure_dialog, null)
val dialog = AlertDialog.Builder(context, R.style.RoundedCornersDialog).setView(dialogView).show()
dialog.setCancelable(false)
val displayRectangle = Rect()
val window = activity?.window
window?.decorView?.getWindowVisibleDisplayFrame(displayRectangle)
dialog.window?.setLayout(
(displayRectangle.width() * 0.5f).toInt(),
dialog.window!!.attributes.height
)
context?.resources?.let {
dialogView.findViewById<TextView>(R.id.recipe_measure_title).text = java.lang.String.format(it.getString(R.string.addRecipeMeasure), unitsArray[currentMeasurementUnits - 1])
}
val doneBtn = dialogView.findViewById<ImageButton>(R.id.recipe_measure_done_btn)
val closeBtn = dialogView.findViewById<ImageButton>(R.id.close_btn_add_recipe)
val conversionEditText = dialogView.findViewById<ClearFocusEditText>(R.id.recipe_conversion_tie)
doneBtn.isEnabled = false
if (recipeItem != null ){
conversionEditText.setText("${recipeItem.conversionRatio}")
}
closeBtn.setOnClickListener {
context?.hideKeyboard(it)
dialog.dismiss() }
doneBtn.setOnClickListener {
context?.hideKeyboard(it)
val conversionRatio = conversionEditText.text.toString().toFloat()
if (recipeItem != null){
recipeItem.conversionRatio = conversionRatio
recipeItemList[position] = recipeItem
recipeAdapter.notifyItemChanged(position)
}else{
recipeItemList.add(0,RecipeItem(0,0,conversionRatio,0)) // Use your data class in place of RecipeItem
recipeAdapter.notifyItemInserted(0) // new Item is added to index zero, so adapter has to be updated at index zero
}
// calculating sum
val sum = recipeItemList.map { it.conversionRatio }.sum()
Log.d("tisha==>>","Conversion ratio sum = $sum")
dialog.cancel()
}
}
I'm using AndroidStudio 4.1.1 and kotlin
I'm having issues trying to get the value of a selected item in a spinner view/item. My first attempt, and many threads say to do it this way, is:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
val selectedText = spinner.getSelectedItem().toString()
This does not work for me. selectedText shows nothing in a Toast or a println
I also tried this, which I also found many threads for:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
if (spinner != null) {
val adapter = ArrayAdapter( this, android.R.layout.simple_spinner_item, muscleGroups )
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val selectedText = muscleGroups[position]
println("Muscle Group selected is $selectedText") // <-- this works
}
override fun onNothingSelected(parent: AdapterView<*>) {
// write code to perform some action
}
}
}
// selectedText is not seen here:
println("Muscle Group selected is $selectedText")
This works and I can see selectedString in my println, in the onItemSelected function inside the block. But, how do I get this value to be seen outside of this block of code? I need to use this value in a class object and a database write. I've tried declaring selectedString outside/above the if (spinner != null), but that does not seem to work either.
Thanks for any help.
Your Spinner does not have a value selected by default. Hence calling spinner.getSelectedItem() returns null and null.toString() returns an empty String.
Your code will work only if the user has selected an option from the Spinner first. You can set a initial value by using spinner.setSelection(position).
If you want to use the selected value outside the selection, you can use a global variable as follows:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
var selectedText = muscleGroups.first() // as default
if (spinner != null) {
val adapter = ArrayAdapter( this, android.R.layout.simple_spinner_item, muscleGroups )
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
selectedText = muscleGroups[position]
}
override fun onNothingSelected(parent: AdapterView<*>) {
}
}
}
If you want to try something with selectedText, you should use it inside onItemSelected function.