How can I make Android linearlayout refresh after addView some textview? - android

My res xml has a linearlayout and a button
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:gravity="center_horizontal"
android:orientation="horizontal"
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
</LinearLayout>
<Button
android:id="#+id/btn_add_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="84dp"
android:text="Button" />
click the button
some char array added to linearLayout one by one
val chars = "Hello".toCharArray()
btn_add_text.setOnClickListener {
linearLayout.removeAllViews()
chars.forEachIndexed { index, char ->
val tv = Textview(this)
tv.textSize = 36f
tv.text = char
tv.id = index
linearLayout.addView(tv)
linearLayout.invalidate()
}
After forEachIndexed loop has finished linearLayout refreshed and can see [H][e][l][l][o] five textviews.
But I want to make linearLayout refresh after each linearLayout.addView(tv).

As far as I know if you want a view to redraw you call invalidate and if you want to update the viewbounds you need to call requestLayout as well.

If you want to see step by step you can try this:
val handler = Handler()
btn_add_text.setOnClickListener {
linearLayout.removeAllViews()
chars.forEachIndexed { index, char ->
val tv = TextView(context!!)
tv.textSize = 24f
tv.text = char.toString()
tv.id = index
handler.postDelayed(Runnable {
linearLayout.addView(tv)
},500 * index.toLong())
}
}

I think linearlayout is refreshing so fast, you are not able to see intermediate refreshes, what you can do is, use a worker thread and make it sleep for 500 ms between each iteration, and post data to main thread via handler, your each change of charachter will be visible.

Related

Display the text of a button when clicked in Kotlin

I have a table made of buttons and each button has a text on it. However, I want that text to be invisible unless the button is clicked.
The buttons look like this:
<Button
android:background="#drawable/roundstyle"
android:backgroundTint="#color/c1"
android:id="#+id/btnOne"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:text="#string/i"
tools:ignore="UsingOnClickInXml"
android:onClick="displayText" />
In MainActivity, I tried to implement a function to display the text:
fun displayText(view: View) {
val b = view as Button
val buttonText = b.text.toString()
I think the easiest thing to do would be to use "if", so that if btnOne is not clicked, then the text should be invisible, else, the text should be visible. But I am not sure where to write this code in the Main Activity and how exactly, so that once the button has been clicked, the text remains on the screen.
Could someone help me with this, please?
Thank you.
can try this one by default set the button like this(the most easy solution)
<Button
android:background="#drawable/roundstyle"
android:backgroundTint="#color/c1"
android:id="#+id/btnOne"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:tag = "some text"
tools:ignore="UsingOnClickInXml"
android:onClick="displayText" />
and click handler
fun displayText(view: View) {
val b = view as Button
val btnTag= b.tag.toString()
if (b.text.isEmpty()) {
b.text = btnTag
}
}
You can do this simply by changing the font size of the button text. you can initially set the font size to 0 and then set the right value after user clicked on it.
<Button
android:onClick="displayText"
android:text="Sample Text"
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
android:textSize="0sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
To visible the text once
fun displayText(view: View) {
view.setTextSize(TypedValue.COMPLEX_UNIT_SP,12f)
}
This function will toggle the visibility of the text
fun displayText(view: View) {
if(view.textSize == 0f){
view.setTextSize(TypedValue.COMPLEX_UNIT_SP,12f)
}else{
view.setTextSize(TypedValue.COMPLEX_UNIT_SP,0f)
}
}

How do I update the Quantity when user press "+" or "-" button?

Note: This has to be done in Kotlin
I want to update the quantity when the user presses the "+" or the "-" button
enter image description here
I also want the "0" (Quantity) to be aligned between the two buttons.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="36dp"
android:layout_marginTop="36dp"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:id="#+id/Quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="QUANTITY"
android:textSize="23sp" />
<TextView
android:id="#+id/qtr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/Quantity"
android:layout_toRightOf="#+id/add"
android:text="#string/Qtr"
android:textSize="23sp" />
<Button
android:id="#+id/orderbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/add"
android:onClick="order"
android:text="Order" />
<Button
android:id="#+id/add"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:layout_below="#+id/Quantity"
android:layout_marginRight="16dp"
android:text="+" />
<Button
android:id="#+id/sub"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:layout_below="#+id/Quantity"
android:layout_marginLeft="16dp"
android:layout_toRightOf="#+id/qtr"
android:text="-" />
</RelativeLayout>
And this is the Kotlin file code (MainActivity.kt)
package com.example.demoapplicaltion
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Write code here
}
}
First create a counter above your main method:
var quantity: Int = 0
Next set the click listeners to your two buttons within your onCreate():
findViewById<Button>(R.id.add).setOnClickListener{
quantity++
updateValue()
}
findViewById<Button>(R.id.min).setOnClickListener{
quantity--
updateValue()
}
and finally create the updateValue() method:
fun updateValue(){
findViewById<TextView>(R.id.Quantity).text = quantity
}
I'll give you a step by step recepy instead of writing the whole code here.
Step 1
In your MainActivity you need some sort of reference to your two buttons and to the textview from the xml in order to do anything with them. The easiest way is to use the findViewById() fuction.
For example you would need a variable like
var addButton: Button? = null
in your Activity.
Step 2
To assgin the button from the xml to this varibale call
addButton = findViewById( R.id.add )
Step 3
Now that the button from the xml is assigned to your variable inside the activity you can access it to define what should happen if the button is clicked. Like for example:
addButton.setOnClickListener {
code that increases the quantity, sth like:
val oldQuantity = quantityTextView.text.toInt()
quantityTextView.text = oldQuantity + 1
}
To see findViewById work have a look at: https://www.tutorialkart.com/kotlin-android/access-a-view-programmatically-using-findviewbyid/
Note that there are better, but a bit more complex ways to link between xml and Activity like ViewBinding: https://developer.android.com/topic/libraries/view-binding
First get current quantity from shown textview, like this
String currentQuant = qtr.gettext().toString();
then parse into Integer
int quantity = Integer.parseInt(currentQuant);
now you have the current quantity as int just increment it, like this
quantity ++ ;
then
qtr.settext(String.valueOf(quantity));

onBindViewHolder binding view inconsistently

I have a ViewHolder that is meant to appear differently depending on whether it is on the left or right side of a two-column RecyclerView with a GridLayoutManager. Note the connector lines on either side of the view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_marginTop="12px"
android:layout_marginBottom="12px"
android:layout_gravity="center"
android:gravity="center_vertical"
android:layout_height="wrap_content"
android:id="#+id/citation_select_holder">
<ImageView
android:src="#drawable/connector_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="#+id/citation_select_connector_right"/>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="348px"
android:layout_height="104px"
android:layout_weight="1"
android:background="#drawable/button_background_white"
android:id="#+id/citation_select_citation_holder">
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="28px"
>
<TextView
tools:text="123456"
android:textAppearance="#style/citation_select_item_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/citation_select_citation_number_text"/>
<TextView
tools:text="Pay by: Nov 18th, 2019"
android:textAppearance="#style/citation_select_item_due_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/citation_select_due_date_text"/>
<TextView
tools:text="a category label"
android:textAppearance="#style/citation_select_item_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/citation_select_category_text"/>
</LinearLayout>
<TextView
tools:text="$10.00"
android:textAppearance="#style/citation_select_item_cost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:id="#+id/citation_select_cost_text" android:layout_marginRight="28px"/>
</RelativeLayout>
<ImageView
android:src="#drawable/connector_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="#+id/citation_select_connector_left"/>
</LinearLayout>
The connector line far from the side that the view appears on is meant to disappear when onBindViewHolder is called, and the margins updated accordingly.
if (position % 2 == 0) {
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_left).visibility = View.GONE
val marginLayoutParams1 = holder.citationHolder.layoutParams as GridLayoutManager.LayoutParams
marginLayoutParams1.setMargins(0, 12, 12, 12)
holder.itemView.findViewById<LinearLayout>(R.id.citation_select_holder).layoutParams =
marginLayoutParams1
} else {
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_right).visibility = View.GONE
val marginLayoutParams2 = holder.citationHolder.layoutParams as GridLayoutManager.LayoutParams
marginLayoutParams2.setMargins(12, 12, 0, 12)
holder.itemView.findViewById<LinearLayout>(R.id.citation_select_holder).layoutParams =
marginLayoutParams2
}
Scrolling is done exclusively via on-screen buttons in increments of six. The first two pages load normally:
But the pattern begins to break down at citation #14. Keep in mind that the citation numbers correspond are the view's position within the RecyclerView:
What is happening to change the behavior?
I think I know what can help you fix this. I presume that it is reusing the old view, as a RecyclerView should and nowhere in your code is there a line to set the visibility of the connector lines back to visible.
You should add to both your GONE visibilities also the code to set the other to visible:
if (position % 2 == 0) {
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_right).visibility = View.VISIBLE
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_left).visibility = View.GONE
val marginLayoutParams1 = holder.citationHolder.layoutParams as GridLayoutManager.LayoutParams
marginLayoutParams1.setMargins(0, 12, 12, 12)
holder.itemView.findViewById<LinearLayout>(R.id.citation_select_holder).layoutParams =
marginLayoutParams1
} else {
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_left).visibility = View.VISIBLE
holder.itemView.findViewById<ImageView>(R.id.citation_select_connector_right).visibility = View.GONE
val marginLayoutParams2 = holder.citationHolder.layoutParams as GridLayoutManager.LayoutParams
marginLayoutParams2.setMargins(12, 12, 0, 12)
holder.itemView.findViewById<LinearLayout>(R.id.citation_select_holder).layoutParams =
marginLayoutParams2
}
Additional explanation
The RecyclerView will reuse some old view, right? Well since both lines are VISIBLE at the start, you assume that's their default state. But when you set the lines to GONE you never put them back to visible, and thus if RecyclerView reuses that view, it'll not add the margin there and it will just be missing the connector line. You always want to have EVERY line of code in onBindViewHolder to have a matching line that reverts it.
Vucko's answer is good, and the overall point (always update every component of your viewholder) is something you should absolutely do.
I wanted to add, however, that it appears as though you are not following the ViewHolder pattern correctly: your onBindViewHolder() method should never call findViewById(). Instead, your ViewHolder class should find each view once and then save references to them.
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val connectorRight: ImageView = itemView.findViewById(R.id.citation_select_connector_right)
val connectorLeft: ImageView = itemView.findViewById(R.id.citation_select_connector_left)
// ...
}
And then you can use these fields directly inside onBindViewHolder():
if (position % 2 == 0) {
holder.connectorRight.visibility = View.VISIBLE
holder.connectorLeft.visibility = View.GONE
// ...
} else {
holder.connectorLeft.visibility = View.VISIBLE
holder.connectorRight.visibility = View.GONE
// ...
}

How to dinamically add ImageView/textView at the right of others ImageView/textView in a same layout

So in my code I have 6 arrays (the 5 last could be empty) of objects. Each objects has a name and the array could have many of each object (every array are sorted so every item are grouped).
First, I have this xml file:
<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:background="#drawable/fond4"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:background="#color/white"
android:gravity="center"
android:text="#string/commentOpti"
android:textSize="20sp" />
<Button
android:id="#+id/choisirTroupe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:onClick="soumission"
android:text="#string/lancer" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:background="#color/white"
android:gravity="center"
android:text="#string/casernes"
android:textSize="20sp" />
<!-- Caserne 1 -->
<LinearLayout
android:id="#+id/caserne1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#color/white"
android:orientation="horizontal" >
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:background="#drawable/caserne" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="#string/deuxPoints"
android:textSize="25sp" />
</LinearLayout>
//Then 5 other like this 1st linearLayou
//The ids are incremented each time like caserne2 for the 2nd etc...
</ScrollView>
It look like this: https://gyazo.com/17a1276dfff5521d540fb6dc953df424
What I want to do is, for each object in each array (one array: one linear layout), to add a textView with the number of Item and an imageView which represent the object.
Next, you will find how I sort everything, that's not really important I think, but if you want to understand everything you'll have to give a look :p
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_optimisation);
LinearLayout caserne1 = (LinearLayout) findViewById(R.id.caserne1);
//...Doing this for the 5 others...
Intent intent = getIntent();
//Instanciation of my object
OptiClashOfClans o = new OptiClashOfClans();
//In fact, the number of linearLayout i'll have to work with
o.setNbCasernes(this.nbCaserne);
if (this.nbBarbares > 0)
o.ajouterFormation(1, this.nbBarbares);
//...Adding each object in on array...
o.setAFormer(o.triTroupe());
//And finally here i'll put each object in the good array
o.orgaCaserne(o);
Now we go for my problem, this portion of code is just next to the one I put previously, here is how I pick up the number of the same object in each array
for (int cptCaserne = 0; cptCaserne < this.nbCaserne; cptCaserne++) {
// Here I pick up the array of object I'll work with
Caserne casTmp = o.getCaserneNum(cptCaserne);
// Here I pick every object which are in the previous array
ArrayList<Troupe> enFormTmp = new ArrayList<Troupe>();
enFormTmp = casTmp.getEnFormation();
// To count where I am in the array of object
int cptAFormer = 0;
//To know if the next object is different from the one I'm working with
Troupe troupTmp = enFormTmp.get(cptAFormer);
int cptTroupTmp = 0;
//For the object t in the array of object
for (Troupe t : enFormTmp) {
cptTroupTmp = 0;
//While the object is the same from the one we're working with
while (!troupTmp.equals(t)) {
//Incrementing the previous counter
cptTroupTmp++;
cptAFormer++;
}
And finally here is how I don't really know how to do:
ImageView iView = new ImageView(Optimisation.this);
//To know which background i'll add to the image view
//I'll do this for each different object
if (t.getNom().equals("Barbare"))
iView.setImageResource(R.drawable.barbare);
//...
//The text view with the number of object I found
TextView tView = new TextView(Optimisation.this);
tView.setText("" + cptTroupTmp);
//And now it's here where I want to add the different views
switch (cptCaserne) {
case 0:
caserne1.addView(tView);
caserne1.addView(iView);
case 1:
caserne2.addView(tView);
caserne1.addView(iView);
case 2:
caserne3.addView(tView);
caserne1.addView(iView);
case 3:
caserne4.addView(tView);
caserne1.addView(iView);
}
troupTmp = enFormTmp.get(cptAFormer);
}
}
With this code I have an insane black screen when I'm going on this activity.
Here is what I want to do with in red the textView with the number of objet and in green the imageView of the object...
https://gyazo.com/31b16982ce30b66391bafdd2cd4d86fc
I've found some stuff to do with LayoutInflater but I haven't been successfull with these... Thanks a lot if you could help me.
PS: sorry for the mistakes, I think there are a lot, but in long post like this one, my school english isn't very effective ^^
Thanks again :)
Correct me if I'm wrong. But from what I understood you just need to accomplish what is being shown here https://gyazo.com/31b16982ce30b66391bafdd2cd4d86fc?
Base on your code you just have to add an additional LinearLayout having an horizontal orientation on each LinearLayout before adding the TextView and Image View.
Here's an example using your code:
LinearLayout innerLayout = new LinearLayout(Optimisation.this)
innerLayout.setOrientation(LinearLayout.HORIZONTAL);
ImageView iView = new ImageView(Optimisation.this);
//To know which background i'll add to the image view
//I'll do this for each different object
if (t.getNom().equals("Barbare"))
iView.setImageResource(R.drawable.barbare);
//...
//The text view with the number of object I found
TextView tView = new TextView(Optimisation.this);
tView.setText("" + cptTroupTmp);
innerLayout.addView(tView);
innerLayout.addView(iView);
//And now it's here where I want to add the different views
switch (cptCaserne) {
case 0:
caserne1.addView(innerLayout);
case 1:
caserne2.addView(innerLayout);
case 2:
caserne3.addView(innerLayout);
case 3:
caserne4.addView(innerLayout);
}
Feel free to adjust it if the Layout that I'm adding the innerLayout in is wrong. But basically, that's the idea.

Android using if statement on textview and imagebutton

Hello guys i am making simple game that can take point if i click right button.
so there is 5 imagebutton and 1 textview. textview will generate random number 1-5 . and those 5 imagebuttons has 5 different id , so my point is if textview generates 1 number how can i check it its right button using if statement.
if ( textview(current generated number ) == imagebutton(id) ) {
counter++)
something like this can you help me guys? example code would be nice :D
Set the tag value for the buttons
either from xml set Tag attribute
Tag = "1"
or
btn.setTag("1");
Add the buttons corresponding value to its tag and then compare it with tags value
in onClick method you get id of button clicked
Button btn = (Button) findViewById(id);
string valu = btn.getTag();
Now compare the textView value with this tag value.
string txt = textView.getText();
if(txt.equals(valu))
{
// do what you want
}
You could store the button resource IDs an array of int. Then in a common click handler, you could test whether the button clicked was the same as the one randomly selected. Here's a simplistic, minimal example. It assumes you've set and displayed the random number before you get the button clicks.
In your class, define these fields:
private int myButtons[] = null;
private int randomNumber = 0;
In onCreate(), add the following:
myButtons = new int[] {R.id.btn0, R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4};
Add the method:
public btnClick(View v) {
if (findViewById(myButtons[randomNumber]) == v)
Log.i(TAG, "Correct!");
else
Log.i(TAG, "Incorrect!");
}
Then in your layout XML, define the buttons with your click handler:
<Button
android:id="#+id/btn0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="#string/btn0" />
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="#string/btn1" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="#string/btn2" />
<Button
android:id="#+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="#string/btn3" />
<Button
android:id="#+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="#string/btn4" />

Categories

Resources