Dynamic array of views in Kotlin - android

I am trying to create dynamic TextView by creating an array of TextViews but getting error :
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
My Code:
var txtViews = arrayOfNulls<TextView>(3)
for (i in txtViews.indices) {
txtViews = arrayOfNulls(i)
txtViews[i]?.textSize = 24.0F
txtViews[i]?.text = "Hello"
txtViews[i]?.setTextColor(ContextCompat.getColor(this,
R.color.colorAccent))
layout.addView(txtViews[i])
}

You never initialized those null references inside your array:
This should work for what you are trying to achieve:
val txtViews = arrayOfNulls<TextView>(3)
for (i in txtViews.indices) {
txtViews[i] = TextView(context).apply {
textSize = 24.0F
text = "Hello"
setTextColor(
ContextCompat.getColor(context,
R.color.colorAccent))
}
layout.addView(txtViews[i])
}

There was no need to create arrayOfNulls
I did this way:
for (i in size) {
val txtView = TextView(this).apply {
textSize = 24.0F
text = Html.fromHtml("&#8226")
setTextColor(
ContextCompat.getColor(
context,
R.color.colorAccent
)
)
}
layout.addView(txtView)
}

Related

val cannot be reassigned while trying to update Polyline

In the code below I get an error Val cannot be reassigned, I dont know how can I recreate the object ? i am new to kotlin and I am just trying to update a code that i found somewhere... trying to understand how to modify it.
I understand it is final and it is being called from another class like this
another class
val polyLine = RoadManager.buildRoadOverlay(road)
PanRoad = newRoad(
polyLine = polyLine,
colorRoad = colorRoad,
roadWidth = roadWidth,
showPoiMarker = showPoiMarker,
listInterestPoints = listInterestPoints,
)
I tried changin it to val to var like this var polyLine = RoadManager.buildRoadOverlay(road) still nothing.
Below is the class that is giving errors
private fun newRoad(
polyLine: Polyline,
colorRoad: Int?,
showPoiMarker: Boolean,
listInterestPoints: List<GeoPoint>,
roadWidth: Float,
bitmapIcon: Bitmap? = null,
): PanRoad {
print(message = "pannam createRoad called")
polyLine.setOnClickListener { _, _, eventPos ->
methodChannel.invokeMethod("receiveSinglePress", eventPos?.toHashMap())
true
}
/// set polyline color
val polygonPaint = Paint().apply {
color = Color.BLUE
style = Paint.Style.FILL
}
val outlinerPaint = Paint().apply {
color = Color.DKGRAY
style = Paint.Style.STROKE
strokeWidth = 2f
}
polyLine.outlinePaint = Paint().apply {
color = colorRoad ?: Color.GREEN
style = Paint.Style.STROKE
strokeWidth = 2f
strokeCap = Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
val iconsRoads = customRoadMarkerIcon
when {
(iconsRoads.isEmpty() && bitmapIcon != null) -> {
iconsRoads[Constants.STARTPOSITIONROAD] = bitmapIcon
iconsRoads[Constants.MIDDLEPOSITIONROAD] = bitmapIcon
iconsRoads[Constants.ENDPOSITIONROAD] = bitmapIcon
}
iconsRoads.isNotEmpty() && bitmapIcon != null -> {
iconsRoads[Constants.MIDDLEPOSITIONROAD] = bitmapIcon
if (!iconsRoads.containsKey(Constants.STARTPOSITIONROAD)) {
iconsRoads[Constants.STARTPOSITIONROAD] = bitmapIcon
}
if (!iconsRoads.containsKey(Constants.ENDPOSITIONROAD)) {
iconsRoads[Constants.ENDPOSITIONROAD] = bitmapIcon
}
}
}
val PanRoad = PanRoad(
context,
map!!,
interestPoint = if (showPoiMarker) listInterestPoints else emptyList(),
showInterestPoints = showPoiMarker
)
PanRoad.let { roadF ->
if (showPoiMarker) {
roadF.markersIcons = iconsRoads
}
polyLine.outlinePaint.strokeWidth = roadWidth
roadF.road = polyLine
folderRoad.items.add(roadF)
}
return PanRoad
}
The error occurs at polyLine.outlinePaint
I assume the Polyline class you're working with is from org.osmdroid.views.overlay, which only provides a getOutlinePaint as can be seen in its JavaDoc. However, there is no setOutlinePaint. From Kotlins point of view outlinePaint is therefore a val which cannot be reassigned.
It think instead of reassigning the outlinePaint field you instead want to retrieve a reference to the Paint object stored in the field and modify it directly. Something like the following might work, however I'm unable to verify this at the moment.
val outlinePaint = polyLine.outlinePaint
outlinePaint.color = Color.GREEM
outlinePaint.style = Paint.Style.STROKE
or if using apply is preferred
polyLine.outlinePaint.apply {
color = Color.GREEM
style = Paint.Style.STROKE
}

Composable does not update when mutablestateflow in viewmodel

I have Viewmodel where I keep reference to post. When i want to translate post i run function to update state flow and post and if I put logs there I see that value is changed but my composable did not get any new value. Here is part of code from viewmodel that doing this magic
private var originalText = tile.text?.originalText
private var text = tile.text?.text
private var _postTileState = MutableStateFlow(tile)
val tileState = _postTileState.asStateFlow()
fun translateText() {
val newText = if (_postTileState.value.text?.isTranslated == true)
originalText
else text
val postText = PostText(
text = newText,
isTranslated = !_postTileState.value.text?.isTranslated!!,
originalText = tile.text?.originalText
)
_postTileState.value.text = postText
}
Tile here is one post. And here is parent composable
#Composable
fun PostTileView(
tile: PostTile,
content: #Composable (
tile: PostTile,
) -> Unit
) {
val postTileViewModel = postTileViewModel(
tile,
id = tile.id
)
val postTile = postTileViewModel.tileState.collectAsState().value
Column(
modifier = Modifier
.background(Style.colors.content)
.padding(bottom = 10.dp)
) {
PostTileHeaderView(postTile.author, createdDate = postTile.createdDate)
content(postTile)
if(postTile.text?.originalText != null) {
Button(onClick = {
postTileViewModel.translateText()
}) {
val buttonTitle = if(postTile.text!!.isTranslated == true)
"Show original" else "Translate"
Text(text = buttonTitle)
}
}
PostTags(tags = postTile.tags)
}
}
If i put some other state with this one in viewmodel like some boolean and get reference to it in composable it works fine but with updating post it does not work. What I am missing?
The problem is with your translateText() function, you can't update just a single variable of the object inside the state flow like that _postTileState.value.text = postText, but instead you need to update the hole object so your function should look like that:
fun translateText() {
val newText = if (_postTileState.value.text?.isTranslated == true)
originalText
else text
val postText = PostText(
text = newText,
isTranslated = !_postTileState.value.text?.isTranslated!!,
originalText = tile.text?.originalText
)
_postTileState.value = _postTileState.value.copy(text = postText)
}
Now the state flow will notice that you set a new object.

How to update recyclerview element and retrieve sum all updated elements

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()
}
}

How to set a list/array to a TextView

I have a mutable list that changes each time the generate() function is called. What I'm trying to do is convert it to a string and set it to a TextView. The way I set the TextView below works for Integers but not for lists. It just does not display the contents of the list and I have no idea why it won't work. Instead the TextView2 does this: Genereated Numbers: []
val text = findViewById<TextView>(R.id.textView)
val text2 = findViewById<TextView>(R.id.textView2)
var possibleInputs = mutableListOf(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
fun generate() {
var num = (0..20).shuffled().last()
when {
possibleInputs.size == 0 -> text.text = "Done"
num in possibleInputs -> {
text.text = "$num"
text2.text = "Generated Numbers: $possibleInputs"
possibleInputs.remove(num)
}
else -> generate()
}
}
This is the code I used to fix it
for (i in 0 until possibleInputs.size) {
text2.append(possibleInputs[i].toString())
}

How can i set color in PieChart of MPAndroidChart

I try to set color in PieChart of MPAndroidChart.But its not set it.I want to add custom color in my partition . Here is my code :-
fun setupPieChartView() {
mPie = findViewById(R.id.piechart)
mPie?.setUsePercentValues(true)
val desc: Description = Description()
desc.text = "PieChart"
mPie?.description = desc
val legend: Legend? = mPie?.legend
legend?.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
val value = Arrays.asList(trueAns.toFloat(), wrongAns.toFloat(), noAns.toFloat())
val label = Arrays.asList("True", "false", "Not")
val entry = ArrayList<PieEntry>()
for (i in value.indices) {
entry.add(PieEntry(value.get(i), label.get(i)))
}
val dataSet = PieDataSet(entry, "Result")
dataSet.setDrawValues(true)
val pieData = PieData(dataSet)
pieData.setValueFormatter(PercentFormatter())
pieData.setValueTextSize(10f)
pieData.setValueTextColor(Color.WHITE)
mPie?.data = pieData
}
Instead of this
dataSet.colors = ColorTemplate.COLORFUL_COLORS.toList()
it should be
dataSet.setColors(Color.RED, Color.GREEN, Color.BLUE);
Because first one gives default colors, that's why you can't override colors. Here is result of your code :

Categories

Resources