Lets say that I have two different types of RelativeLayouts. That is to say these 2 RelativeLayouts differ because they contain different views. One might have textviews, an image view etc and the other might have also have some textviews which mean something completely different than the other set of textviews in the other relativelayout. Lets say however that both have a Submit Button. So to make my point more clear here is some code:
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ViewParent parent = v.getParent();
if(parent instanceof CustomRelativeLayout){
CustomRelativeLayout aRelativeLayout = (CustomRelativeLayout)parent;
for(int childrenIndex = 0; childrenIndex < r.getChildCount(); childrenIndex++){
View childView = aRelativeLayout.getChildAt(childrenIndex);
}
}
}
The problem here is is that we don't know which CustomRelativeLayout aRelativeLayout is referring to. Depending on which CustomRelativeLayout it is will depend on what specific childViews i will want to search for and what logic I implement relevant to those views. I would like to be able to have a switch statement to check which type of CustomRelativeLayout is the parent.
So the questions that i would like to ask is:
how do i get more information about which instance of CustomRelativeLayout refers to the button that was clicked? Is there a way to get the instance variable name?
Once i have found out that information how do i get specific information about the children of the parent view that i am working on? The thought is, is that i might have 30 child views in the parent but i am only interested in one specific view(i might want to get the text of one specific textview as an example). I will know to look for it specifically because i would have done a switch statement on the different instances of my CustomRelativeLayouts(the first question) and therefore i know which view i want to look at, which logic to perform or what other methods that i need to call.
Would appreciate any thoughts or help with this.
For your first question, there are couple options:
Use separate OnClickListeners for each button. Then, each button will only trigger its own listener's onClick() method.
You can give each button a different id either in XML (via the android:id property) or in code (via setId(int id)). Then in onClick() you can check the id of the View that was passed as the argument.
For your second question:
Since you have the parent ViewGroup, you can find specific views within it by using:
TextView interestingView = (TextView) parent.findViewById(R.id.interesting);
This will only search the children of the parent view.
If you need to get an unknown number of views the best strategy is probably iterating through them like you are now. You can identify groups of views by setting a tag either in XML (android:tag) or code (setTag(Object tag) and check them as you iterate. For example, if you have a set of TextViews and in each one is either a color or an animal, you might handle that like this:
// defined elsewhere
private static final String TAG_COLOR = "color";
private static final String TAG_ANIMAL = "animal";
...
int count = parent.getChildCount();
for (int i = 0; i < count; i++){
View view = parent.getChildAt(i);
if (TAG_COLOR.equals(view.getTag()) {
// handle color
} else if (TAG_ANIMAL.equals(view.getTag()) {
// handle animal
}
}
There are several ways to do this.
Use "id" to identify views. You can give different id to different views, and then it will be possible to identify them. See http://developer.android.com/reference/android/view/View.html#getId() (the API documentation of View.getId()) for more information.
Mark each view with different tags, and identify them through tags. See http://developer.android.com/reference/android/view/View.html#getTag() (the API documentation of View.getTag()) for more information.
If you want to customize more, just inherit default Android views, and use "instanceof" to identify them.
Related
How can I monitor multiple views in my Android application. The reason I'm interested in this, is cause, my app has a view that has lot of fields EditTexts, Spinners, CheckBoxes, RadioButtons and some EditTexts are hidden unless a particular Spinner Item is selected or a Radio Button is checked. All I want the observer to do is to check all fields are filled before the submit Button is enabled and if any View was un-hidden it must check if the Fields have been filled too. This is where I'm stuck on what to do: I have a four boolean checks that check for the four hidden Views, but then I don't want to write a long if/else statement. Thanks
The following code will help you to check an unknown number of Views of different types contained in a single ViewGroup. In your case with just four views, I think you are likely prefer four 'if' clauses.
You could mark all Views which you want to check by adding a tag in the layout file:
android:tag="CheckMe"
Tags don't have to be unique, so you can use the same tag for all Views.
In addition to that, give an id to the ViewGroup containing your Views (this could be a LinearLayout)
android:id="#+id/myLayout"
Then in your activity you can first get the ViewGroup
ViewGroup myLayout = (ViewGroup) findViewById(R.id.mylayout);
and then cycle over the child Views:
for (int i = 0; i < myLayout.getChildCount(); i++)
{
View v = myLayout.getChildAt(i);
if (v.getTag().toString().equals("CheckMe")
{
if (v instanceof EditText)
{ // do something
}
else if (v instanceof SomeOtherView)
{ // do something else
}
}
}
I have been experiencing a problem with my custom adapter and have located the problem solution. However I do not know how to go about it. I have researched and seen a few examples of a listview custom adapter at which buttons are given tags like viewHolder.button.setTag(Tag) and I understand what the tag does but I am unsure as to how to use it. My questions are: When I set the tag on a button, how does the application differentiate my buttons from another if all the tags are set the same? Also, say I have an onClick method in my custom adapter, how do I use the tag that I set to the button to identify the button that was clicked? I've kind of seen similar adapters on the internet but not exactly , a link to an example would be greatly appreciated also.
I am unsure as to how to use it
tag is a mechanism to make your views remember something, that could be an object an integer a string or anything you like.
My questions are: When I set the tag on a button, how does the
application differentiate my buttons from another if all the tags are
set the same?
i do not understand this question but i think if you notice that your button has a memory and it calls tag you can use it in a better way. if all of your buttons memory(tags) are the same so you can not use tags to distinguish the buttons you must use ids.
say I have an onClick method in my custom adapter, how do I use the
tag that I set to the button to identify the button that was clicked?
you must set different tags for your buttons or grouped them logically and set different tags for each group then in your onClick method use the tags to identify your buttons group:
OnClickListener myButtonListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
Object obj = arg0.getTag();
if(obj instanceOf groupOneTagObject){
// do action for group 1
}else if(obj instanceOf groupTwoTagObject){
// do action for group 2
}
}
});
Not sure if the head line describes its well, what I want is that:
I have let's say 9 TextViews in my layout, named tv1, tv2, ..., tv9.
Of course I can access each of them with
TextView tv11 = (TextView) findViewById(R.id.tv1)
Lot's of typing, so I rather would have a loop and loop through these items, but how can include the findViewbyId into a loop that I can change the value accordingly?
Is there any reason why you can't iterate over the children of the containing ViewGroup? So you get the number of children with getChildCount and then you can access each individual child with getChildAt.
You may have to test whether a particularly child is an instance of TextView if you have other views in the layout, but the basic concept is fairly straightforward.
You could make an array of the IDs you want to loop through.
IE:
public static final int TEXTVIEW_IDS = { R.id.tv1, R.id.tv2, R.id.tv3, etc.. };
In your view code:
for (int id : TEXTVIEW_IDS) {
((Textview) findViewById(id)).CallYourMethod();
}
If you cannot do what #James Holderness suggested, this may be a suitable alternative.
i would like to ask a lot of questions about how this whole id system works in android. I looked up the View documentation, but the description was too shallow for my taste.
Is there a pattern, how the IDE (Eclipse/Netbeans) generates the ids
when i use android:id="#+id/..."? Or is it completely random?
If i set ids programmatically, then will it be found by the Context
classes findViewById() function?
If the answer for the previous question is yes, then if i want to
create a large amount of Views, but i want them to have distinct ids
for later identification, then wich one is better to use? (To answer
this question, it would be really useful to know the answer for the
first two)
For example generating random ids in the largest possible range:
Random random = new Random();
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(random.nextInt(Integer.MAX_VALUE));
}
Or setting the ids in some sort of order, for example:
final int addToId = 5670;
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(i+addToId);
}
Also i would like to know, what happens, when you use a
LayoutInflater for example to populate a ListView using a
pre-defined xml layout for every item in the list. Then you get your
sub-views in the getView() function by the findViewById(). So i
assume, that all the identical Views across your listitems have the
same id. If so, then is it a good practice to use the tag
attribute to distinguish the items in an inflated layout?
Any clear explanation for these question would be highly appreciated!
#+id/.... creates an id value that lives within the applications namespace. Contrast this with #android:id/.... which lives in the android namespace.
When you set the id in code and add the view element to the layout it will then become available to access through the code. You won't be able to reference it from the xml
Not sure you want to be using random to generate your ids? think sequential would be better but even then what is the point of a random id? How do you know which view you are referring to?
Definitely use the tag option and look to use the ViewHolder pattern for smoother list scrolling. You could add the id to the view holder class if you need access to it but it would be available anyway through the data set being used to populate the list. A quick search will give you plenty of examples for this.
i have a row of buttins created like this
i want to change the background colour at runtime in code.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout track1 = (LinearLayout)findViewById(R.id.my_toggle_container);
for (int i = 0; i<32; i++) {
ToggleButton tgl = new ToggleButton(this);
tgl.setId(i);
...
track1.addView(tgl);
this names the id of the togglebuttons 1, 2, 3... (i presume?)
i have an int variable called 'xBtn' that changes 1, 2,..
this is how i get a reference to the button using xBtn
String buttonID = ""+xBtn;
int resID = getResources().getIdentifier(buttonID, "id", "com.thing");
//find the button
ToggleButton tb = (ToggleButton) findViewById(resID);
//change its colour
tb.setBackgroundColor(Color.BLUE);
it crashes on the setBackgroundColor line.
it may be obvious to someone whats wrong and thats what im hoping
any help would be totaly ace ta
thanks
main.xml
<LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:id="#+id/my_toggle_container" android:orientation="vertical">
The id of your togglebuttons is gonna be a number from 1 to 32... However, trying to find the toggle button by id will return null because simply instantiating a new toggle button and giving an id wont help you. findViewById looks in the parent view for a child view with the specified id. If you havent added that toggle button with that id to the view, then findViewById will return null. I am 99.99% sure even without looking at the log, that it crashes because you are calling setBackgroundColor on a null object.
In other words, the id that you set a view to is only relevant once the view is actually added to a parent view. In your case you are probably trying to add these toggle buttons to your main content view, in which case you need grab hold of that view that you used for setContentView and call addView on that view and pass in each new toggle button. Note that this will probably not look right unless you also specify layoutparams for the togglebuttons.
EDIT
If thats your entire main.xml, then you've got other issues. Post the full xml file. In any event, you still are going to have to do what I've said, which is to grab hold of the view or a child view of that view and then add the toggle buttons to it via addView (after giving the togglebuttons their proper ids). Once the button has been added, then you can find it. Note though that if you're gonna add the toggle buttons to a child view of your main view, then you'll likely have to grab hold of that child view and call findViewById on THAT.
For example, you can do a nested call like this. findViewById(1) <--- gets you the LinearLayout or whatever inside of your main content view, then once you have that you can call addView on it. So LinearLayout ll = (LinearLayout)findViewById(someNumber); ll.addView(tb);
Try to use the method setTag() , and then you can get all your ToggleButton by using : findViewByTag();
Perhaps tb is null? Could you check that out?
To expand on what LuxuryMode said... What gets an ID INTO your java is inflating it via setContentView and setting it as content. That's why it's ok to have overlapping (duplicate) IDs in different layouts. You can have #+id/submit_button in layout1.xml and in layout2.xml and the Activity will get you the object via findViewById(R.id.submit_button) based on which one you have loaded into setContentView() at any given moment.
So, we're all guessing that you're probably not setting the content view and hoping that the code will find your object in your non inflated XML, which it won't. Which would lead (as everyone has guessed) to you now dealing with a null object, which you obviously can't set a background color on.
I know it gets confusing cause you have the XML RIGHT THERE!!! But the reality is that the xml isn't "alive". It's just stuff for you to look at until you have tasked the Application with inflating it and converting all of it into Android objects of some kind. A lot of the time this is done mostly transparently to you, so, it's easy to forget that none of these things really exist.
It's very likely that tb is null, because findViewById() didn't go as you expected.
You can verify this by surrounding the erroneous line with try.. catch block:
try {
tb.setBackgroundColor(Color.BLUE);
} catch (Exception e){
}
and watch for the message of e. It's likely to be null pointer exception.
In fact, I think you should not use getResources().getIdentifier(buttonID, "id", "com.thing") in the first place. It seems to me that all these resources are continuously numbered in R file, thus you should simply get the first id (as an integer), and then increment on that.
That is, you should do things like:
// The following code is not tested; I just wrote it here on SO.
for (int resID = R.id.button1; resID <= 32; resID++) {
ToggleButton tb = (ToggleButton) findViewById(resID);
tb.setBackgroundColor(Color.BLUE);
}
this should make all 32 buttons blue.