Collections AddAll Android - java

I'm just starting out in java & android.
Below is my code, to add all the buttons in an activity then hide them.
Question: is their anyway to automatically add all the buttons in the activity without having to list each of them, I have looked at listA.addall but didn't understand how to add the activity as the collection.
The rational for this is I may wish to change the number of buttons and still have the code work.
public void setup2(){
List<Button> listA = new ArrayList<Button>();
listA.add((Button)findViewById(R.id.button1));
listA.add((Button)findViewById(R.id.button2));
listA.add((Button)findViewById(R.id.button3));
listA.add((Button)findViewById(R.id.button4));
listA.add((Button)findViewById(R.id.button5));
for (Button item : listA)
item.setVisibility(View.INVISIBLE);
}

Yes, that is probably the cleanest way of doing it. But if your buttons are all similarly id named (button_1, button_2 etc) You could search via string instead of direct ID reference. The following is an example of fetching a button by string:
int resID = getResources().getIdentifier("button_%i", "id", getPackageName());
Button addButton = (Button) findViewById(resID);
Then you could loop around all your buttons.

Assuming that your buttons are in a view group e,g, LinearLayout:
for (int i = 0; i < layout.getChildCount(); i++) {
View v = layout.getChildAt(i);
if (v.getClass() == Button.class) {
listA.add(v);
}
}
layout is a reference to the layout containing the buttons.
This simply iterates over each child view in the layout, compares it's class type with Button and adds it to your collection if it is.

Related

Button (android.content.Context) in Button Cannot be Applied to (Java.lang.Object)

I am attempting to Dynamically Create Buttons to match Data Table. I was using this answer as a reference point however I keep getting this error code: Button (android.content.Context) in Button Cannot be Applied to (Java.lang.Object)
I tried multiple things to alleviate error code but I am at a loss of how to fix it I attempted to set the Map to an array but that isn't working either. The Code has successfully counted, and displayed the data but I cannot get it to add the Needed Buttons.
Backendless.Data.of( "Store" ).find( queryBuilder, new AsyncCallback<List<Map>>()
{
#Override
public void handleResponse( List<Map> response )
{
int numBrands = response.size();
Button brandButtons[] = new Button[numBrands];
System.out.println("The Count of Buttons:" + numBrands);
ArrayList<Brands> productList = new ArrayList<>();
Object[] arrayList = {response};
for(int i = 0; i < brandButtons.length; i++)
{
Button brans = new Button(productList[i]);
brans.setOnClickListener();
add(brans);
brandButtons[i] = brans;
//Object element = thisIsAStringArray[i];
System.out.println( "List of Brands" + response );
}
}
Your error is here in this line:
Button brans = new Button(productList[i]); // here
Button class expects Context passed to it's constructor invocation & you're passing Object type instead.
Use like this,
Button brans = new Button(context); // here context can be activity or fragment.
//now use this brans object to set property to your programmatically created Button,
//don't forget to add it to your parent view afterwards
As you can see in Button documentation, to create a button object you need to pass a Context object. In your code your passing an object of Brands which is causing the problem.
The solution would be to pass a context to the Button(Context) constructor. If your in an Activity it would be something like new Button(YourActivity.this), in a fragment you could use new Button(getContext())

"Cannot resolve method" unable to access object methods inside a loop (passing object reference to function)

I'm new to Android and JAVA,... my Activity have many widgets that are inside separated LinearLayouts. I want to toggle them on and off accordingly. I have some radio buttons which will hide or show certain LinearLayouts as required. It makes more sense to me having the widgets grouped as sections for this case.
I'm having a problem accessing the methods "getVisibility" and "setVisibility" from inside a "for" loop. I'm using an array of Object type. I thought in maybe just pass the layouts id's as strings but something tells me it will not work.
As a side question : I have 13 total Linear Layouts in a single activity is it bad practice? I could not find a better way to horizontal align elements, maybe I took the short route? :p Thanks in advance.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_job);
...
LinearLayout monthlyContainer = (LinearLayout) findViewById(R.id.monthlyContainer);
LinearLayout weeklyContainer = (LinearLayout) findViewById(R.id.weeklyContainer);
LinearLayout fortnightlyContainer = (LinearLayout) findViewById(R.id.fortnightlyContainer);
LinearLayout fourweeklyContainer = (LinearLayout) findViewById(R.id.fourweeklyContainer);
LinearLayout twiceMonthlyContainer = (LinearLayout) findViewById(R.id.twiceMonthlyContainer);
RadioGroup earningsContainer = (RadioGroup) findViewById(R.id.earningsContainer);
///create a list of views to hide
Object[] viewsToToggle={monthlyContainer, weeklyContainer, fortnightlyContainer, fourweeklyContainer, twiceMonthlyContainer, earningsContainer};
//pass object array to hideView method
this.hideView(viewsToToggle, monthlyContainer);
....
}
private void hideView(Object[] viewsToToggle, Object excludeMe){
///// create array to contain elements to toggle visibility
Object[] viewstoHide = new Object[4];
for(int i = 0; i < viewsToToggle.length; i++){
if(viewsToToggle[i] != excludeMe){
viewstoHide[i] = viewsToToggle[i];
}
}
for(int j = 0; j < viewstoHide.length; j++ ){
if(viewstoHide[j].getVisibility() == View.VISIBLE){ //// syntax error on this line
viewstoHide[j].setVisibility(View.GONE); //// syntax error on this line
}
}
System.out.println("VIEWS TO HIDE : " + Arrays.toString(viewstoHide));
}
Your viewstoHide array does not contain ui elements, so you cannot use those methods. In order to use those methods, change the type of your array or add ui elements like LinearLayout or Radiogroup.
It's not a very good practice to add different types of ojects in your array because when you loop through the array of objects and you if want a to use a specific method on all elements, you can have only one different element and your loop will break. So in order to solve your problem, please use specific type for each array or add only ui elements. Good preactice is to verify if your elements are instanceof desired classes. Hope it helps.
Try making viewsToToggle an Array of LinearLayout instead of an Array of Object.
Same goes for viewsToHide.

Android Toolbar item OnClickListener

I have a Toolbar and an item (add) which, when clicked, adds a view in listView below. However, the onOptionsItemSelected gives you the effect of a single click so it only adds one view, and in my case, I need multiple views, thus multiple clicks are required. How do I set up everything so that the item behaves as an onClickListener rather than a single click?
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.addButton){
final TextView noProject = (TextView) findViewById(R.id.NOPROJECT);
final ArrayList<String> listItems=new ArrayList<String>();
final ListAdapter addAdapter = new ArrayAdapter<String>(this,
R.layout.list_item, R.id.listFrame, listItems);
final ListView lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(addAdapter);
noProject.setVisibility(View.GONE);
lv.setVisibility(View.VISIBLE);
listItems.add("New Project");
((ArrayAdapter) addAdapter).notifyDataSetChanged();
}
if (id == R.id.addPeople) {
return true;
}
return super.onOptionsItemSelected(item);
}
Android is always listening for menu item clicks. And on click your action will happen, so you'll need to click multiple times anyways if you want this add feature in the menu.
I usually setup my list adapter in onCreate or onCreateView. Once it's established you can do addAdapter.clear() and addAdapter.add(item). You shouldn't need to reference your listitems directly since the ArrayAdapter.add() method is setup to append to that list anyways and then if i'm not mistaken you can get rid of notifyDataSetChange() - I've never had to use this method with any of the default list adapters or the custom adapters I've written. .clear(), .add(), .insert(), and .remove() should be sufficient.
My listview is usually filled out using a for loop. If you want multiple views added then could you just setup a loop instead of waiting/requiring for more clicks?
Maybe I'm not fully understanding the usecase but a basic for loop seems like the answer here.
Edit:
//For Each Loop - "For each individualItem in itemHolder"
listadapter.clear();
for(ItemType individualItem : itemHolder){
listAdapter.add(individualItem.getText());
}
or you can do a traditional for loop
//"For i(index) starting at index 0, run until index < itemHolder.getItemCount() is false"
//for(initialize index variable : condition check : increment after each iteration)
for(int index =0; index<itemHolder.getItemCount(); index++)
{
listAdapter.add(itemHolder.getItemAt(index));
}
Something like that. I made up method names obviously it's going to depend on your data structures.

how can i refer to a view that is not yet created in the xml file?

//first i have this method , below is my question
public void addrows(){
TableRow fila;
tabla = (TableLayout)findViewById(R.id.tabla);
TextView txtNombre;
for(int i = 0;i<id;i++){
String x[] = helper.leer();
layoutFila = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT);
caja= new CheckBox(this);
fila = new TableRow(this);
fila.setLayoutParams(layoutFila);
txtNombre = new TextView(this);
txtNombre.setId(i);
txtNombre.setTextSize(17);
txtNombre.setText(x[i]);
txtNombre.setGravity(Gravity.LEFT);
// txtNombre.setLayoutParams(layoutTexto);
caja.setText("");
caja.setId(i);
fila.addView(txtNombre);
fila.addView(caja);
tabla.addView(fila);
}
}
i know that when the oncreate() method start the checkboxes objects are created and then i assign an numerical id from 0 to wherever the for cycle stop , but later in the program i need to retrieve what checkboxes were clicked so first i need the id but eclipse wont let me put the numerical id, please help! and sorry for my English i'm a noob in android and the English language
this.CheckBox = (CheckBox)this.findViewById(R.id.?);
As You may read in View class documentation ID should be unique within a tree You search.
You set same id for TextView and Checkbox.
If You know You are going to access them all later after creation keep references to them in array instead of trying to retrieve them later using findViewById.
But even better solution would be to set onClick event listener for them and keep track of checking/unchecking them.
In #HalR's answer You may read how to set onCheckedChanged event listeners for Your checkboxes. Folowing his solution will have an ArrayList of checked checkboxes.
Next step, You have to increment values of correct TextView so You need to couple CheckBoxes and TextViews.
I think best for this would be to set Tag for CheckBox with value of TextView id.
So after user submits You iterate over List of checkboxes, getTag and use it in findViewById to get TextView and update its value.
Id (short for IDentifier) is an integer to uniquely identify elements, You can use it in findViewById to get view elements. You can read more about ID in this answer
Tag is used to associate View element with some extra data as You may read in getTag documentation. It takes as parameter Object type so You set as tag anything not only numbers. In Your case You could set as ChechBox's tag a TextView instead of its id and it will work too.
You are manually setting your id to the index of the row, which is something I don't think I'd do. I'd normally use setTag() to identify my object.
I think it would be easier to use a listener to detect when the checkboxes have been checked, and you can track the changes when the check happens.
use something like this:
In your Activity, create a ArrayList
ArrayList<CheckBox> checkedBoxes = new ArrayList<CheckBox>();
then in your creation:
caja= new CheckBox(this);
caja.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
int index = buttonView.getId();//pulling back the number you set originally, if that is what you like. I would get the tag I had set, and maybe do something here.
//do something in here!
if (buttonView.isChecked()) {
//including this checkbox in the list of checked boxes
checkedBoxes.addObject(buttonView);
} else {
//take it out of the list of checked boxes
checkedBoxes.removeObject(buttonView);
}
}
};
Some info on Id vs Tag
Id is a numeric value that identifies the view in the view hierarchy. If you are using things in your layout, like aligning one view with another, they look for and expect a view with a specific id. So in layout, you'll have android:id="#+id/bigBox" and that will create some number that it associates with bigBox. When you find that view, with findViewById() that is the number it is looking for. When you manually set those numbers, it seems like you are asking for trouble. If you set a view's id to 2, then you should be able to find it with myView = findViewById(2).
Tag is a nicely little object pointer that you can pass along with your view. Quite often it will be a row number:
Integer saveMe = new Integer(i);
checkBox.setTag(saveMe);
Or it can even be a pointer to your original data object that you used to create that row. If you had created each row using a contact, you could use
myRow.setTag(contact)
and later when you clicked on that row, you would just use
contact = (Contact)myRow.getTag()
and you would have your original contact back. Its way cleaner than keeping big arrays of your rows or checkboxes, or whatevers. Just use listeners that detect when you do something, that is a much better way.
Oh, and if you if you do have an onClick(View view) that is triggered by your CheckBox, that view IS your CheckBox.
CheckBox theBoxIJustChecked = (CheckBox)view;
You don't need to look it up with some id. It's right there.
If you want to go this way than you should just do the apposite operation i.e.:
for(int i = 0; i < n; ++i){
...
...(CheckBox))this.findViewById(i);
...
}
It should work for you
However be careful as if you have number of views with the same id inside the view-tree than findViewById(i) can return an unexpected result such as returning the first view in view-tree with given id (it can be not of CheckBox type which can lead to ClassCAstException)
Update in reply to comment
If you want to make some sort of logical connection CheckBox-TextView there are several options:
You can make a sort of function like the following (assuming that there is the limit of CheckBoxes and TextViews quantity):
Code:
private static int CHECK_BOX_MAX_NUMBER = 10000;
public void int getTextVieIdByCheckBoxId(int checkBoxId){
if(checkBoxId >= CHECK_BOX_MAX_NUMBER){
// you can throw an exception here for example
}
return CHECK_BOX_MAX_NUMBER + checkBoxId;
}
And then you should set id's to your TextViews with that function.
checkBox.setId(i);
textView.setId(getTextVieIdByCheckBoxId(i));
....
// add Views to your layout
....
(CheckBox)this.findViewById(i);
TextView)this.findViewById(getTextVieIdByCheckBoxId(i));
or
2.I think there is a little bit more accurate method:
Just use setTag() of CheckBox instances to set appropreate TextView inside in order to create interconnection. In thiscase you have to store all the created checkBoxes in some List or array:
List<CheckBox> checkBoxList = new ArrayList<CheckBox>();
for(int i = 0; i < n; ++i){
...
CheckBox checkBox = new CheckBox();
TextView textView = new TextView();
checkBox.setTag(textView);
checkBoxList.add(checkBox);
}
Then you can achieve what you want like this:
int textBoxListSize = checkBoxList.size();
for(int i = 0; i < textBoxListSize; ++i){
CheckBox checkBox = checkBoxList.get(i);
if(chechkBox.isChecked()){
TextView textView = (TextView)checkBox.getTag();
//do whatever with textView
}
}
Here you don't need to generate id's and worry about collisions which could accure

Retrieve button by findViewWithTag not working?

In the onCreate() method of my class I make a grid of buttons, and give them tags to identify them, for example:
button.setTag("one four");
This is working fine. Now I want to make a new temporary button within a method, and I'm using this code:
String s = "one four";
Object o = s;
View view = new View(this);
Button button = (Button)view.findViewWithTag(o);
But button always comes out as "null". And I don't know why.
You must call view.addChild(button); before view.findViewWithTag(o);
And you dont need to do this Object o = s;, view.findViewWithTag(s); will do the same.
View view = new View(this); - you create a new instance of View.
Object view does not have any children. You must call findViewWithTag(s) method from layout which contains your Button object.
Try not assigning the string to the object variable and set the tag directly to be your string.
Mavix, findViewWithTag traverse all child views and works fine in ViewGroup. Try this:
// after button.setTag("one four");
ViewGroup v = (ViewGroup) findViewById(R.id.myFirstLayoutIdInXmlLayoutFile);
Button b = (Button) v.findViewWithTag("one four");
I had the same doubt. In my situation, I have a Main Layout and a Secondary Layout (inside the Main) - the two were RelativeLayout's - and I want to get the components I had added on the screen.
But I had to use dynamic keys (which could be repeated)and were the unique parameter I could use to Identify the components.
Like Natali, in her response, I use "TAG" in the components and worked for me. See below (using Button as example):
Step 1: Declare a button-type variable. Button btn = new Button(this); // this is Context of my Activity
Step 2: Set any key. String any_key = "keyToGetButton";
Step 3: Set tag (key setted in step 2) to your button. btn.setTag(any_key);
Step 4: Get your button by tag (in other method, for example). Button button = (Button) your_layout_where_is_button.findViewWithTag(any_key);

Categories