Inserting n elements from xml layout to LinkedList (Android) - android

I have n CheckBox elements in my XML layout for a user registration page. My XML is as follows:
<CheckBox
android:id="#+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Option 1"/>
<CheckBox
android:id="#+id/checkBox2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Option 2" />
How can I add those elements to a LinkedList of type CheckBox in my java code? Ideally, I'd like to use a for-loop to find all elements containing ID "checkbox."
Thanks for any assistance.

You could traverse through the parent view (let's say it's called resultView).
List<CheckBox> boxes = new ArrayList<>();
for (int i = 0; i < resultView.getChildCount(); i++) {
if (resultView.getChildAt(i) instanceof CheckBox) {
// this is a check box for sure
boxes.add((CheckBox) resultView.getChildAt(i));
}
if (resultView.getChildAt(i).toString().contains("checkbox")) {
// this might be a checkbox, and may cause ClassCastException
boxes.add((CheckBox) resultView.getChildAt(i));
}
}

If your CheckBoxes are in the same parent view, you can try to loop for it's children like :
List<CheckBox> list = new LinkedList<>();
RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout);
for (int i = 0; i < layout.getChildCount(); i++) {
View child = layout.getChildAt(i);
//Some condition to get the view you want
//and make sure it's a CheckBox (maybe by tag?)
list.add((CheckBox)child);
}

Related

Error while duplicating a view: The specified child already has a parent

In my RecylcerAdapter, I want to duplicate a TextView.
I have a LinearLayout that contains a TexView. All I want is to dynamically duplicate this TextView inside the LinearLayout, so that I have 10 TextViews inside the LinearLayout.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tags_ll"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:gravity="right">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tags"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="عمومی"
android:layout_margin="5dp"
android:padding="5dp"
android:background="#drawable/border_with_background"
android:textSize="12dp" />
</LinearLayout>
MyViewHolder in RecyclerView:
public MyViewHolder(View view) {
super(view);
tags = (TextView) view.findViewById(R.id.tags);
tags_ll = (LinearLayout) view.findViewById(R.id.tags_ll);
for (int i = 0; i < 10; i++) {
TextView rowTextView = new TextView(view.getContext());
//Clone the new textview, get all the properties of the existing textview
rowTextView = tags;
rowTextView.setText("This is row #" + i);
tags_ll.addView(rowTextView);
}
}
I get the following error:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I want all the properties of the existing textview to be copied to the newly created TextViews.
The reason for this error is because,
tags = (TextView) view.findViewById(R.id.tags);
TextView rowTextView = new TextView(view.getContext());
rowTextView = tags;
tags_ll.addView(rowTextView); // tag.ll has already a child with id = tag
When you copy the reference of that object to your new TextView "rowTextView" now both tags, and rowTextView refer to same Object which is already present in tag.ll LinearLayout, Which is why its throws an error.
If your need is just to implement a list with recyclerViewAdapter, than you are making it very complex, no need to get a TextView from the context when you are just going to assign a new reference to that TextView variable.
If you have latest AndroidStudio installed you can just create a new fragment with list, and Android Studio will provide you with a good example how to use RecyclerView Adapter to populate List. or view this link
http://hmkcode.com/android-simple-recyclerview-widget-example/
Hope i helped.
What you're doing is wrong, you can't copy the TextView properties with rowTextView = tags;, you're just replacing rowTextView TextView with tags one.
You need to set the new TextView properties from your code:
for (int i = 0; i < 10; i++) {
TextView rowTextView = new TextView(view.getContext());
//set the new TextView properties from code
rowTextView.setText("This is row #" + i);
tags_ll.addView(rowTextView);
}
Or
You can create an xml layout containing just a TextView with the desired attributes, and inflate it in your for-loop.
eg:
my_text_view.xml :
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="عمومی"
android:layout_margin="5dp"
android:padding="5dp"
android:background="#drawable/border_with_background"
android:textSize="12dp" />
In your ViewHolder :
LayoutInflater inflater = LayoutInflater.from(context);
for (int i = 0; i < 10; i++) {
TextView rowTextView= (TextView) inflater.inflate(R.layout.my_text_view, null, false);
rowTextView.setText("This is row #" + i);
tags_ll.addView(rowTextView);
}
Your approach is wrong - this line:
rowTextView = tags;
will not copy the first TextView. This will make the new reference to point to the original textView and then you will find yourself adding the original textView in the layout again, causing the error.
What you should do is create your new textView and add its properties by using the original textView like this:
for (int i = 0; i < 10; i++) {
TextView rowTextView = new TextView(view.getContext());
rowTextView.setText(tags.getText());
rowTextView.setGravity(tags.getGravity());
//set all other properties like this: rowTextView.setOther(tags.getOther())...
tags_ll.addView(rowTextView)
}

Using findViewById() inside a for loop for multiple checkboxes

If I have too many checkboxes ( more than 50 ) , is there a way i could use the mapping of the checkboxes , inside for loop ? and how will i assign the int inside the findViewById(int).
Something like this : - (array of checkboxes)
for(int i=0 ; i<=99; i++)
checks[i] = (CheckBox)findViewById(what-about-this-int-id);
You can look up resource id's dynamically too using getResources().getIdentifier(..):
https://stackoverflow.com/a/14058142/1715829
If you have a container element where all those checkboxes reside then you can simply get all its checkbox children by casting it to ViewGroup
ViewGroup container = (ViewGroup)findViewById(R.id.container);
for (int i = 0; i < container.getChildCount(); i++){
CheckBox cb = (CheckBox)container.getChildAt(i);
// attach listener etc
}
I know you might have found your solution but just in case others couldn't find a proper one, i'll post mine here.
Let's say you labelled your "findViewById" like this:
<CheckBox
android:id="#+id/checkbox0"
android:layout_width="0dp"
android:layout_weight="1"
android:padding="5dip"/>
<CheckBox
android:id="#+id/checkbox1"
android:layout_width="0dp"
android:layout_weight="1"
android:padding="5dip"/>
.
.
.
<CheckBox
android:id="#+id/checkbox50"
android:layout_width="0dp"
android:layout_weight="1"
android:padding="5dip"/>
You can do something like this to "findViewById" using a few lines instead of
writing 50 "findViewById" lines:
CheckBox[] cb = new CheckBox[51];
for (int i = 0; i < 51; i++) {
String idCheckBox = "checkbox"+i;
cb[i] = (CheckBox) findViewById(YourActivity.this.getResources().getIdentifier(idCheckBox, "id", getPackageName()));
}
where "YourActivity.this" refers to the context.
1) What for are there 50+ checkboxes?
If you have a list with checkboxes you should use ViewHolder to store info about each row.
2) Try to avoid findViewById each time when you need an item.
findViewById is an expensive operation so you should cache you items (for this very purposes ViewHolder was created).

Get getCheckedItemPositions() and getCheckedItemIds() always returns null

I have a listview in an android app with checkboxes and I'm trying to get a list of the items that are checked. I have tried both setting the checked state in the getView() method with setChecked(true) and by checking it manually by tapping on the item. I've tried two different methods for getting the checked items and both return null. What am I doing wrong?
Greg
//Called from a menu
//First attempt - checked is always null
//I also set setChoiceMode = CHOICE_MODE_MULTIPLE before setting adapter
//and set no setChoiceMode
String ItemsChecked = null;
ListView listview = (ListView) findViewById(R.id.ListLists);
SparseBooleanArray checked = listview.getCheckedItemPositions();
for (int i = 0; i < checked.size(); i++) {
if (checked.get(i)) {
ItemsChecked += Integer.toString(i) + ",";
}
}
//I then tried this and checked[] is empty
//I also set setChoiceMode = CHOICE_MODE_NONE before setting adapter
long checked[] = listview.getCheckedItemIds();
for (int i = 0; i < checked.length; i++) {
ItemsChecked += "" + checked[i] + ",";
}
//Layout for the ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="4dp"
android:src="#drawable/ic_listit" >
</ImageView>
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
<TextView
android:id="#+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="22sp" >
</TextView>
</LinearLayout>
I am not sure you have provided enough information to solve the problem. But here are some troubleshooting steps that may help point you in the right direction:
1) Instead of getting an array based on the number of checked items in the listView, see if you can pull the array of items in the entire list, or at least the first 100 if the list is very large. Then output the index number of each item in a string like you had in your first attempt. You could also try and output whether the current item is checked or not.
this will tell you if you have a populated list to pull from. If you don't, well there's your problem.
2) I would also check to make sure that your listView's name is also correct. I would assume the compiler would catch this but you never know.
3) Finally, I can't see where or how the list is populated. It may be a good idea to check and see the rest of the code to see if maybe something is happening somewhere else.
Sorry if this is not particularly helpful. If all of this checks out and the problem is not being created in one of those areas this link may help:
Android: list.getCheckedItemPositions() always returns null
Good Luck and I hope this helps a little.
Max,
Well, you pointed me in the right direction for a 'solution'. This may not be the proper way to do it, but given this is my my first android app, I am ready to move on after spending the entire morning trying to get a list of just those items that are checked with a built-in method. I modified code from the link you posted and came up with the code below. It seems to work.
I wonder if I will have problems with lists that don't show everything at once. My test only has two items in the list. If items are checked and then scrolled out of view, will this work. More testing needs to be done.
Thanks,
Greg
ListView listview = (ListView) findViewById(R.id.ListLists);
View v;
CheckBox ck;
TextView tv;
for (int i = 0; i < listview.getCount(); i++) {
v = listview.getChildAt(i);
ck = (CheckBox) v.findViewById(R.id.checkBox1);
tv = (TextView) v.findViewById(R.id.label);
if (ck.isChecked()) {
Toast.makeText(getApplicationContext(), tv.getText() + "Checked" , Toast.LENGTH_LONG)
.show();
}
else {
Toast.makeText(getApplicationContext(), tv.getText() + "Not checked" , Toast.LENGTH_LONG)
.show();
}
}

How to get all Buttons ID's in one time on Android

I have 16 Buttons in my Activity and I have to initialize those inside onCreate().
Is there any way to initialize all buttons in one single line code?(loops etc.)
Code should take all buttons R.id. from XML Layout and process....
Let's say you named your button button_0, button_1, .. button_15. You can do:
for (int i = 0; i < 16; i++) {
int id = getResources().getIdentifier("button_"+i, "id", getPackageName());
button[i] = (Button) findViewById(id);
}
Well, if all 16 of those buttons are inside one view or layout, then you could do the following.
ArrayList<View> allButtons;
allButtons = ((LinearLayout) findViewById(R.id.button_container)).getTouchables();
This assumes that your container (in this example a LinearLayout) contains no Touchable that is not a Button.
use Butterknife view injections library
Download Android ButterKnife Zelezny plugin for Android Studio or Intellij IDEA
and initialize all your views from current layout by 1 click
For xamarin android :
List<Button>() allButtons = new List<Button>();
for (int i = 1; i < 15; i++)
{
int id = this.Resources.GetIdentifier("btn" + i.ToString(), "id", this.PackageName);
Button btn = (Button)FindViewById(id);
allButtons.Add(btn);
}
This method takes all buttons inside the layout, hope it helps. Easy to implement & you can use it for almost every project, no libraries required.
public List<Button> getAllButtons(ViewGroup layout){
List<Button> btn = new ArrayList<>();
for(int i =0; i< layout.getChildCount(); i++){
View v =layout.getChildAt(i);
if(v instanceof Button){
btn.add((Button) v);
}
}
return btn;
}
Example
List<Button> btn_list = getAllButtons(myRelativeLayout);
Button my_btn = btn_list.get(0);
my_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("btn_test", "onClick: hello");
}
});
If you are using Kotlin, and your buttons have ids in the form of button1, button2... button16, you can do something like this:
var btn = ArrayList<Button>(16)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game_screen)
for(i in 0 until 16) {
var id = resources.getIdentifier("button"+(i+1), "id", packageName)
btn.add(findViewById<View>(id) as Button)
btn[i].setText("something") //or do whatever now
}
}
If you only know the container id or the button ids are all different try this:
Activity(on create method before setContentView)
List<Integer> idButtons= new ArrayList<>();
//container_button is my button container
RelativeLayout containerButton = findViewById(R.id.container_button);
for(int i =0; i < containerButton.getChildCount(); i++){
View v = containerButton.getChildAt(i);
if(v instanceof Button){
idButtons.add(((Button) v).getId());
}
}
Layout
<RelativeLayout
android:id="#+id/container_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_weight="1"
android:layout_marginEnd="0dp">
<Button
android:id="#+id/buttonac"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/red_button"
android:textColor="#android:color/white"
android:text="AC"
android:onClick="pulsacion" />
<Button
android:id="#+id/buttondel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/buttonac"
android:layout_alignBottom="#+id/buttonac"
android:background="#drawable/red_button"
android:textColor="#android:color/white"
android:text="DEL"
android:onClick="pulsacion" />
[...]
</RelativeLayout>

Unable to set background resource on a Button

I have an application on which I apply some resources to buttons to modify their backgrounds.
All work well, but when my application goes to onResume after onPause, I'm not able to set the background anymore.
I have a set of 18 buttons, and when I am in onResume, i call:
for (int i = 0; i < max; i++) {
Button b = l.get(i);
b.setBackgroundResource(R.color.green);
}
In l i have the list of all buttons got from findViewById().
This works only for the last element of the for, but not for the others.
Any idea?
** Edit **
This is the code I use for populating the array
btn_1 = (Button)findViewById(R.id.btn_1);
btn_1.setOnClickListener(this);
l.add(btn_1);
this is repeated for all my buttons.
** Second edit **
public void onResume() {
btn_1 = (Button)findViewById(R.id.btn_1);
btn_1.setOnClickListener(this);
l = new ArrayList<Button>();
l.add(btn_1);
...
for (int i = 0; i < max; i++) {
Button b = l.get(i);
b.setBackgroundResource(R.color.green);
}
}
The same is done in onCreate().
try the d following.. this will works fine.
List<Button> mButtonList = new ArrayList<Button>();
onCreate() {
mButtonList.add((Button) findViewById(R.id.btn_1));
mButtonList.add((Button) findViewById(R.id.btn_2));
mButtonList.add((Button) findViewById(R.id.btn_3));
....
for(Button b : mButtonList) {
b.setOnClickListener(this);
}
}
onResume() {
for(Button b : mButtonList) {
b.setBackgroundResource(R.color.green);
}
}
Simple example:
Activity
public class StackOverFlowActivity extends Activity {
private ArrayList<Button> myArray = new ArrayList<Button>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myArray.add((Button)findViewById(R.id.btn_1));
myArray.add((Button)findViewById(R.id.btn_2));
myArray.add((Button)findViewById(R.id.btn_3));
myArray.add((Button)findViewById(R.id.btn_4));
myArray.add((Button)findViewById(R.id.btn_5));
}
#Override
protected void onResume() {
super.onResume();
for (Button b : myArray) {
b.setBackgroundColor(getResources().getColor(R.color.blue));
}
}
}
XML main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/btn_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1" />
<Button
android:id="#+id/btn_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2" />
<Button
android:id="#+id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 3" />
<Button
android:id="#+id/btn_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 4" />
<Button
android:id="#+id/btn_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 5" />
</LinearLayout>
My color in the Strings.xml
<color name="blue">#0099CC</color>
Use this instead:
for (int i = 0; i < max; i++) {
Button b = l.get(i);
b.setBackgroundColor(getResources().getColor(R.color.green));
}
If max is really big you might want to cache the getColor result before the loop.
EDIT:
According to the docs: setBackgroundResource is to be used with drawable ids only, and setBackgroundColor seems to be exactly what you need, so maybe another part of your code isn't working well, maybe the loop, the above line for setBackgroundColor works well on my app.
You've said:
": the ... code is the same for btn_1, just swap btn_1 with btn_2, btn_3 and so on. "
if so, than these lines are resetting your Array every time you try and add a new button.
l = new ArrayList<Button>();
l.add(btn_1);
P.S. you should avoid using a manual creation of buttons array - instead use some Parenting Layout such as LinearLayout and then fetch his button son's using getChildAt(i), It's much cleaner. Example:
// Register all the buttons in the layout to the OnClickListener
LinearLayout lin = (LinearLayout)findViewById(R.id.linear_buttons);
int childcount = lin.getChildCount();
for (int i=0; i < childcount; i++){
View v = lin.getChildAt(i);
v.setOnClickListener(this);
}
Try this --
for (int i = 0; i < l.getChildCount(); i++)
{
Button b = (Button) l.getChildAt(i);
b.setBackgroundResource(R.color.green);
}
try this. its working for me
for (int i = 0; i < count; i++) {
btn_title[i] = new Button(ActivityName.this);
btn_title[i].setText(menu.menu_title[i]);
btn_title[i].setId(i);
btn_title[i].setTextColor(Color.BLACK);
btn_title[i].setBackgroundColor(Color.parseColor(dataxml
.getMenucolor()));
btn_title[i]
.setTextSize(Integer.parseInt(dataxml.getFontsize()));
btn_title[i].setGravity(Gravity.CENTER_VERTICAL
| Gravity.CENTER_HORIZONTAL);
btn_title[i].setSingleLine();
btn_title[i].setEllipsize(TruncateAt.END);
btn_title[i].setOnClickListener(new ButtonListner());
}
hope this will help
why don't extend Button class, set its color, then use that new class?
It wont work obviously , let me explain why it has set last value of button .
you are using of one button reference (whatever u got from (Button)findViewById(R.id.btn_1) )
and untimely there is a one button reference and u just change its value using l.add(btn_1);
what you need to do is , do create a new button instance for each button and inflate it in proper view .
here is the small tick for that
for (int i==0 ; i < length; i++ ){
Button button = new Button(context);
collectionOfButton.add(button) ;
}
use that buttons collection using inflate if u try to integrate in some xml layout file .

Categories

Resources