Incorrect alignment creating button in Java vs XML - android

I have this XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/button_bar"
style="?android:buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#color/md_green_400" />
<Button
android:id="#+id/action_button"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#color/md_green_400" />
</LinearLayout>
It´s just a buttonBar with two borderless buttons. It works. However, I don't want that, I need to inflate these buttons from a JSONArray. So I did this:
for (int b = 0; b < buttons.length(); b++) {
final JSONObject button = buttons.getJSONObject(b);
LinearLayout buttonBar = (LinearLayout) child.findViewById(R.id.button_bar);
View buttonChild = getLayoutInflater().inflate(R.layout.flat_button, null);
Button action = (Button) buttonChild.findViewById(R.id.action_button);
action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {}
});
action.setText(button.getString("descricao"));
action.setTextColor(Color.parseColor(button.getString("text_color")));
buttonBar.addView(buttonChild);
}
It works too, but the buttons get a left alignment. I want they justified.
Why it works when I let them fixed but not when I inflate them?
OBS: The "button_bar" is A XML just with a LinearLayout and the "ActionButton" is just a XML with a Button.

This is the root of your problem:
View buttonChild = getLayoutInflater().inflate(R.layout.flat_button, null);
If you don't provide the parent view to the inflate() method, any LayoutParams attributes (e.g. layout_gravity) will be discarded since the parent is the one to interpret those attributes.
You can fix this by changing it to:
View buttonChild = getLayoutInflater().inflate(
R.layout.flat_button, buttonBar, false);
Which will give it the parent you're attaching it to, but not attach it to the hierarchy yet (you do that below with addView()).

Related

Removing Views dynamically

I search a lot for this, but I can't solve it. I have LinearLayout with two textviews and a button (to add others LinearLayout) like this:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<EditText android:id="#+id/ingredientsField"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="#dimen/boxes_margin"
android:hint="#string/ingredients"
android:inputType="text"
xmlns:android="http://schemas.android.com/apk/res/android" />
<EditText
android:id="#+id/quantityField"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="#dimen/boxes_margin"
android:hint="#string/quantity"
android:inputType="number"
/>
<com.google.android.material.button.MaterialButton
android:id="#+id/add_ingredient_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/add"
android:layout_margin="#dimen/boxes_margin"
app:icon="#drawable/ic_add_ingr_btn"
/>
</LinearLayout>
The layout added is like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="50dp">
<EditText android:id="#+id/ingredientsField"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="#dimen/boxes_margin"
android:hint="#string/ingredients"
android:inputType="text"
xmlns:android="http://schemas.android.com/apk/res/android" />
<EditText android:id="#+id/quantityField"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="#dimen/boxes_margin"
android:hint="#string/quantity"
android:inputType="number"
xmlns:android="http://schemas.android.com/apk/res/android" />
<ImageButton
android:id="#+id/remove_ingredient_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="#dimen/boxes_margin"
android:src="#drawable/ic_remove_ing_qnt"/>
</LinearLayout>
In the Activity, I created a method to add new Layouts (and it works), and inside of it a method to delete the corresponding Layout with the Delete Button. Delete Button works only one time and only if it's in the first layout added. Here's the code:
add_ingredient.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView = inflater.inflate(R.layout.ingredient_quantity_layout, null);
// Add the new row before the add field button.
parentIngredientLayout.addView(rowView);
ImageButton removeChildIngredient = findViewById(R.id.remove_ingredient_btn);
removeChildIngredient.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
parentIngredientLayout.removeView((View) v.getParent());
}
});
}
});
You have to set the OnClickListenerevent on the ImageButton from the last inserted layout.
To do that, just change this line
ImageButton removeChildIngredient = findViewById(R.id.remove_ingredient_btn);
to
ImageButton removeChildIngredient = rowView.findViewById(R.id.remove_ingredient_btn);
rowView.findViewById search the ImageButton on the last inserted layout and not the whole layout which contains other layouts.
In this line :
parentIngredientLayout.removeView((View)
v.getParent());
You are trying to remove the parent of the removeChildIngredient ImageButton, which is probably parentIngredientLayout, which i think is not what you want,
You could try this :
parentIngredientLayout.
removeView(rowView);
But in your implementation, you could encounter issues when you will add multiples ingredients, because you are setting a new onClickListener to each new ingredient, and The ImageButton will only delete the last one you have added(the last onClickListener set),
Instead, you could use a List/RecyclerView or search for another implementation, eg. put the ImageButton inside the Inflated Layout so you'll have one Remove Button in each Layout you add,
Then you should replace the findViewById of your ImageButton by rowView.findViewById
And this line should stay unchanged
parentIngredientLayout.removeView((View) v.getParent());

Need to add layout dynamically

This is my Layout , I have nested Linear layout inside another linear layout which is nested inside an Scroll view. Now i want to add an Linear layout dynamically (I may even add upto 10) inside android:id="#+id/formLayout" i.e beneth android:id="#+id/secondLayout"
Original Layout :
<RelativeLayout 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">
<ScrollView
android:layout_width="match_parent"
android:layout_height="420dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<!-- LinearLayout Inside ScrollView -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/formLayout"
android:orientation="vertical">
<!-- Serial Layout -->
<LinearLayout
android:id="#+id/secondLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:weightSum="2">
<android.support.design.widget.TextInputLayout
android:id="#+id/serialno_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:paddingEnd="10dp"
android:paddingLeft="10dp"
android:paddingStart="10dp">
<AutoCompleteTextView
android:id="#+id/fieldSerial"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:hint="#string/txt_sno_text"
android:singleLine="true"
android:textIsSelectable="false"
android:textSize="15sp" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
Dynamic Layout needs to be added :
<LinearLayout
android:id="#+id/sixthLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:weightSum="2">
<android.support.design.widget.TextInputLayout
android:id="#+id/attr2_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:paddingEnd="10dp"
android:paddingLeft="10dp"
android:paddingStart="10dp">
<EditText
android:id="#+id/fieldAttr2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:hint="Attribute 2"
android:textSize="15sp" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
Can some one help me with this ?
Use the LayoutInflater to create a view based on your layout template, and then inject it into the view where you need it.
public static NavigableMap<Integer, String> navigableMap = new TreeMap<Integer, String>();
public static int count = 0; // to count no of views added
public static void add_new(final Activity activity)
{
final LinearLayout linearLayoutForm = (LinearLayout) activity.findViewById(R.id.formLayout);
final LinearLayout newView = (LinearLayout) activity.getLayoutInflater().inflate(R.layout.view_to_add, null);
newView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
final EditText edit_new = (EditText) newView.findViewById(R.id.fieldAttr2);
edit_new.setId(id++); // It will assign a different id to edittext each time while adding new view.
Log.i("actv id",edit_new.getId()+""); // You can check the id assigned to it here.
// use a Hashmap or navigable map (helpful if want to navigate through map)
// to store the values inserted in edittext along with its ids.
edit_new.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
navigableMap.put(edit_new.getId(), edit_new.getText().toString());
Log.i("navigablemap", navigableMap.toString());
}
});
// you can get values directly through map by referencing its ids.
// OR
EditText actv_uc = (EditText) linearLayoutForm.findViewById(navigableMap.lastKey());
// Provide the id of edittext you want to access
actv_uc.getText(); // to get value of EditText
actv_uc.setText("");
linearLayoutForm.addView(newView);
count++;
}
Call this function whenever you want to add new view. If you are calling this in Activity, then there is no need to pass Activity object as parameter. but if you are using this in fragment, then need to pass a Parent Activity object to function.
Very easy and helpful tutorial for adding views dynamically :-
http://android-er.blogspot.in/2013/05/add-and-remove-view-dynamically.html
Hope this will help you. Thank you
Try this:
LinearLayout myRoot = (LinearLayout) findViewById(R.id.formLayout);
LayoutInflater inf = LayoutInflater.from(yourContext);
View child;
for (int i = 0; i < 10; i++) {
child = inf.inflate(R.layout.your_added_layout, null);
child.setId("textView"+i);
// can set layoutparam if needed.
myRoot.addView(child);
}

Listener not working on linearlayout which contain Edittext

I have an EditText contained in a LinearLayout. For My project I have set an OnclickListener on the LinearLayout. When I launch application nothing happened on click to layout. Maybe It due to the EditText but need that OnCliclistener to be work on LenearLayout.
MyCode:
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="#+id/lnlabelnameuniteholder"
android:id="#+id/choix_decategorie"
android:layout_marginTop="10dp" >
<EditText
android:text="#string/choix_de_categorie"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="italic"
android:textSize="18sp"
android:textColor="#000" />
</LinearLayout>
CODE
maCategorie = (LinearLayout) findViewById(R.id.choix_decategorie);
maCategorie.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
MyDB db = new MyDB(MyActivityCategorie.this);
ArrayList<Category> categoryList = db.getCategory();
ChoiceCategoryDialog categoryDialog = new ChoiceCategoryDialog(MyActivityCategorie.this, R.string.add_category, mCategoryTextView.getText().toString(), categoryList, MyActivityCategorie.this, true);
categoryDialog.show();
}
});
Thanks
In your code, you are referring to R.id.choix_decategorie (which is not shown in your code, is this a LinearLayout you want to set onClickListener on?
For a LinearLayout that has child elements (like yours does) - may need to prevent the child elements from receiving focus - you can set android:descendantFocusability="blocksDescendants" like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="#+id/choix_decategorie"
android:id="#+id/lnpriceholderlabel"
android:descendantFocusability="blocksDescendants"
android:layout_marginTop="10dp" >
For a good measure you may also set android:clickable="false" on each of the child elements. So your layout would look something like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="#+id/choix_decategorie"
android:id="#+id/lnpriceholderlabel"
android:descendantFocusability="blocksDescendants"
android:layout_marginTop="10dp" >
<EditText
android:text="#string/choix_de_categorie"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="italic"
android:clickable="false"
android:textSize="18sp"
android:textColor="#000" />
</LinearLayout>
Give it a try and let us know if this works.
Try this example:
LinearLayout yourLayout = (LinearLayout) findViewById (R.id.yourID);
yourLayout.setOnClickListener(new View.OnClickListener() { // remember to use "View."
#Override
public void onClick(View v) {
Toast.makeText(this, "hello", Toast.LENGTH_LONG).show();
}
});
set LinearLayout attribute android:clickable="true"
if you have button or textview in layout set android:clickable="false" for all of them
You must have to set the LinearLayout clickable="true"
<LineartLayout....
android:clickable="true"...>
This will work
And you need to put some margins in EditText, because EditText comes upside on LinearLayout and space doesn't remain for LinearLayout to be clickable.
put
<EditText
android:layout_margin="5dp".../>
your click listener will work but your edit text hide the linear layout , if you remove the edit text it will work or you can set height and width not equal to linear layout.
As a workaround you could do something like this (kotlin code):
editText.inputType = InputType.TYPE_NULL
editText.setOnClickListener { linearLayout.performClick() }
In that case the editText won't pop up the keyboard and the linearLayout will receive the a click event.

android - spacing of items added to linear layout changes

I am adding pictures to a linearlayout programmatically. This linearlayout is surrounded by a horizontalscrollview and part of a item layout for a listview. When I have the pictures inline with the other view items, they are spaced next to eachother correctly:
However if I move the horizontalscrollview/linearlayout under the other view items, I get some weird spacing that android seems to do automatically:
So far I have tried relativelayouts, embedded linearlayouts, changing padding, changing margins, changing the width property of the linearlayout between match_parent, fill_parent, and wrap_content, but nothing changes this spacing. It is always the same.
Here is the relevant code:
LinearLayout tmpLL = (LinearLayout) convertView.findViewById(R.id.llUpgrades);
//remove previous list contents first
tmpLL.removeAllViews();
for(int i = 0; i<= tmpUpgradeList.size()-1; i++){
ImageView tmpIB = new ImageView(getContext());
Upgrade tmpUpgrade = tmpUpgradeList.get(i);
Upgrade.setUpgradePic(tmpIB, tmpUpgrade, tmpUpgrade.Title()==null);
tmpIB.setTag(position + ":" + i);
tmpIB.setPadding(5, 0, 0, 0);
tmpIB.setMaxWidth(50);
tmpLL.addView(tmpIB);
tmpIB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String[] split = ((String) v.getTag()).split(":");
runUpgradePopup(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
}
});
tmpIB.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
String[] split = ((String) v.getTag()).split(":");
clearUpgrade(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
return true;
}
});
}
Layout of the one causing the error. The other layout puts the cards next to each other correctly but all I have different is that it is a linear layout and removed the relevant relative placement calls:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<Button
android:layout_width="100dp"
android:layout_height="60dp"
android:id="#+id/btnFRemoveShip"
android:text="Remove"/>
<ImageView
android:id="#+id/ivFRowShipIcon"
android:layout_height="60dp"
android:layout_width="75dp"
android:src="#android:drawable/ic_delete"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/btnFRemoveShip"/>
<TextView
android:layout_height="wrap_content"
android:ems="10"
android:layout_width="wrap_content"
android:id="#+id/tvFRowShipTitle"
android:text="error"
android:textSize="20dp"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/ivFRowShipIcon"/>
<HorizontalScrollView
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginTop="5dp"
android:layout_below="#+id/btnFRemoveShip">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/llUpgrades">
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
Any help is greatly appreciated!
Took a couple days of rewording the question but finally found the answer.
Had to add this line before adding the image to the layout.
tmpIB.setAdjustViewBounds(true);
Thread is here: found answer

Android: setting text in each new view within a for loop

So I have an XML layout1 which is just a LinearLayout with three text views. I also have another XML layout2 with ScrollView and a LinearLayout inside it. I'm using this for loop to create several of the layout2 inside the LinearLayout of the ScrollView. It's working fine but I want to be able to set the text of each of the TextViews within the for loop. I'm not sure how to access these TextViews as I can only set one id within the XML file, will that not cause problems if I tried to access their id inside the for loop?
private void setUpResults() {
for (int i = 1; i < totalQuestions; i++) {
parent.addView(LayoutInflater.from(getBaseContext()).inflate(
R.layout.result_block, null));
}
}
Here is the result_block xml file (layout1) :
<?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="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/layoutSelectedAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/border"
android:orientation="horizontal"
android:paddingBottom="#dimen/option_padding_bottom"
android:paddingTop="#dimen/option_padding_top" >
<TextView
android:id="#+id/tvOptionALabel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="#string/option_a"
android:textColor="#color/white"
android:textSize="#dimen/option_text_size" />
<TextView
android:id="#+id/tvSelectedAnswer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="#string/option"
android:textColor="#color/white"
android:textSize="#dimen/option_text_size" />
</LinearLayout>
<LinearLayout
android:id="#+id/layoutCorrectAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/border"
android:orientation="horizontal"
android:paddingBottom="#dimen/option_padding_bottom"
android:paddingTop="#dimen/option_padding_top" >
<TextView
android:id="#+id/tvOptionBLabel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="#string/option_b"
android:textColor="#color/white"
android:textSize="#dimen/option_text_size" />
<TextView
android:id="#+id/tvCorrectAnswer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="#string/option"
android:textColor="#color/white"
android:textSize="#dimen/option_text_size" />
</LinearLayout>
</LinearLayout>
Let's say I wanted to set the TextView with the id as tvCorrectAnswer to a different String value in each loop, how should I access it?
Sure, you can do it like this:
private void setUpResults () {
LayoutInflater i = LayoutInflater.from(getBaseContext());
for (int i = 1 /* should be zero? */; i < totalQuestions; i++) {
View view = i.inflate(R.layout.result_block, parent, false);
TextView correctAnswer = (TextView) view.findViewById(R.id.tvSelectedAnswer);
correctAnswer.setText("My Answer Text");
parent.addView(view);
}
}
The key is, inflate using the parent as the container, but don't attach it (the false parameter). Then you'll get a reference to the inflated view, which you can then directly reference to do your findViewById() calls (which will limit the search to that particular ViewGroup). Then add it to the parent and continue to the next item.
Once you have added all your views in your ViewGroup you can use ViewGroup.getChildAt(int) to get a one of the views you have inserted. Once you get one of the views you can access any of its inner views. Something like this.
for(int i = 0; i < parentView.getChildCount();++i) {
View v = parentView.getChildAt(i);
Textview tv = (TextView) v.findViewById(R.id.tvOptionALabel2);
//And so on...
}

Categories

Resources