findViewById in specific layout? - android

Instead of prefixing id's in xml, is it possible to specify the particular layout in code? For example, if I have 3 layouts, each with a button that has an id of "btn". Is it possible to specify which layout to findViewById(R.id.btn) in?

The basic context is defined via setContentView(R.lyaout.my_layout). If you inflate another layout using LayoutInflater.inflate() you get a layout object, lets call it buttonLayout. You can now differ between this.findViewById(R.id.button) and buttonLayout.findViewById(R.id.button) and both will give you different button references.

findViewById is a method of the View class. You can specify where the view should be searched for like that
final View container = new View(context);
container.findViewById(R.id.btn);

If your content view is a complex hierarchy that has several views with id btn, you will need to navigate to a subtree of the hierarchy and search from there. Suppose you have three LinearLayout views, each with a btn view somewhere in it. If you can first select the correct LinearLayout (by id, tag, position, or some other means), you can then find the correct btn view. If the relevant LinearLayout has id of branch1, for instance:
View parent = findViewById(R.id.branch1); // Activity method
View btn = parent.findViewById(R.id.btn); // View method

if you have your btns inside different Viewgroups, it is possible, but requires to give ViewGroups a different name! Easyiest will be for that purpose to define the Layout of the Button inside its own XML (i.e button_layout.xml)
inside your Activity you can do this:
public MyActivity extends Activity{
Button btn1, btn2, btn3;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
LinearLayout ll = new LinearLayout(this);
setContentView(ll);
btn1 = (Button)inflater.inflate(R.layout.button_layout, ll);
btn2 = (Button)inflater.inflate(R.layout.button_layout, ll);
btn3 = (Button)inflater.inflate(R.layout.button_layout, ll);
}
}

Related

findViewById() returns null for an inflated layout

I have an Activity and its layout. Now I need to add a LinearLayout from another layout, menu_layout.xml.
LayoutInflater inflater;
inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.menu_layout, null);
After this, findViewById() returns null. Is there is any solution for that?
Note: I can't put both XML in one place, and using <include> also is not working.
Explanation
When you inflate a layout, the layout is not in the UI yet, meaning the user will not be able to see it until it's been added. To do this, you must get a hold of a ViewGroup (LinearLayout,RelativeLayout,etc) and add the inflated View to it. Once they're added, you can work on them as you would with any other views including the findViewById method, adding listeners, changing properties, etc
Code
//Inside onCreate for example
setContentView(R.layout.main); //Sets the content of your activity
View otherLayout = LayoutInflater.from(this).inflate(R.layout.other,null);
//You can access them here, before adding `otherLayout` to your activity
TextView example = (TextView) otherLayout.findViewById(R.id.exampleTextView);
//This container needs to be inside main.xml
LinearLayout container = (LinearLayout)findViewById(R.id.container);
//Add the inflated view to the container
container.addView(otherLayout);
//Or access them once they're added
TextView example2 = (TextView) findViewById(R.id.exampleTextView);
//For example, adding a listener to the new layout
otherLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Your thing
}
});
Assuming
main.xml contains a LinearLayout with the id container
other.xml is a layout file in your project
other.xml contains a TextView with the id exampleTextView
Try using
layoutObject.findViewById();

Dynamically add a button to a view from a listview Adapter GetView method

As a little eperiment, I'm trying to do the following.
I have an AXML describing a vertical linear layout which contains a listview (only filling 200dp of the vertical linear layout ). The AXML is inflated when the activity starts with SetContentView. Then the listview is correctly populated with values using its Adapter.
In the GetView method of the listview Adapter, I am trying to also dynamically create a button and add it to the linear layout, but for some reason the button is not added.
If I try to add the button in the constructor method of the Adapter instead, it is correctly added.
Can you tell me what could be possibly going wrong?
Let me add some code:
class TracksAdapter : BaseAdapter<string> {
Activity context;
List<Dictionary<string,string>> trackList;
// constructor
public TracksAdapter (Activity context, List<Dictionary<string,string>> trackList) {
this.context = context;
this.trackList = trackList;
// Just as a little test, if I create the button from here it will be correctly added to linear layout:
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
}
public override View GetView(int position, View oldView, ViewGroup parent) {
// if I create the button from here it will not be added to the layout
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
// this other code is working
View view = context.LayoutInflater.Inflate(Resource.Layout.ResultItem, null);
var artistLabel = view.FindViewById<TextView>(Resource.Id.resultArtistNameTextView);
artistLabel.Text = trackList[position]["trackArtistName"];
return view;
}
}
Update: adding some more context information because I know this can be a bit weird to understand without it:
In GetView, I don't need to return the new button I am trying to create there. GetView only need to return a listview view item, but, along its execution, GetView also has to create and add a button to the linear layout containing the listview.
The real code is much more complex than that. I have simplified it in the question. In the real code, the listview items are made of text and a button. The GetView also attaches event handlers to the buttons. Then what I need is, when a user clicks a button in any of the listview items, another button is added below the listview. So I need the code for adding another button to be in GetView, and the button needs to be added outside of the listview, ie. to the linear layout containing the listview.
Use the LayoutInflator to create a view based on your layout template, and then inject it into the view where you need it.
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
I looked in you code, you are returning view, while you add the button to ll, you should return ll
what you return in getView() is what you see in the list item layout, since you're adding the button to ll and returning view, the button won't appear.
you can add the button to view as you implementation
Also check this:
Try using boolean addViewInLayout (View child, int index, ViewGroup.LayoutParams params)
http://developer.android.com/reference/android/view/ViewGroup.html#addViewInLayout(android.view.View, int, android.view.ViewGroup.LayoutParams)
It's working... Without making any changes now it's working as it should... ! Ugh!
I really don't know what I was doing wrong here... probably it was because of some sort of caching of older version of the installed APK.. ? I know this sort of stuff can happen, and that's why I've always been uninstalling the app before deplyoing the new version to the device... but still...!

Access android custom ActionBar from Activity

I created a class that extends ActionBarActivity and displays a custom XML. That class is extended by almost all my activities.
I want to access an element of that custom XML from one of my activities. Let's say I want to change the background of item2 when I'm in Activity2.
In my activity's onCreate method, after setContentView, I tried:
View cView = getLayoutInflater().inflate(R.layout.custom_menu, null);
ImageButton rewards_link = (ImageButton) cView.findViewById(R.id.rewards_link);
rewards_link.setVisibility(View.GONE); // For test purpose
Even if the button id seems correct, the changes doesn't apply. Any ideas ?
If you are setting the custom view via getActionBar().setCustomView(R.layout.custom_menu); (or getSupportActionBar() for v21 of AppCompat), then you can access those views by using findViewById() directly as the view is part of your view hierarchy just like views added via setContentView():
ImageButton rewards_link = (ImageButton) findViewById(R.id.rewards_link);
rewards_link.setVisibility(View.GONE); // For test purpose
Use #getCustomView
View view =getSupportActionBar().getCustomView(); ImageButton imageButton =
(ImageButton)view.findViewById(R.id.action_bar_back); imageButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v){
// Your code here ...
}
});

Android - Reference object in separate view

I am doing an Android App. I want to use a button in one view to set the text of a text view in a different view. How do I reference the button in the other view?
If the views containing button and textView are in the same layout that you inflated in onCreate() method using setContentView(R.layout.layout), then you can simply use:
Button button = (Button)findViewById(R.id.button);
Else, if the textView/Button view is not in the layout that is inflated in onCreate() method, you need to inflate the other view first and then reference the textView/Button as follows:
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
View view = (View)inflater.inflate(R.layout.layout2, null);
Button button = (Button)view.findViewById(R.id.button1);
//add code for button
// or TextView tv = (TextView)view.findViewById(R.id.textView);

how to remove dynamically inflated views?

In a simple card game that i want to develop, I have three buttons: button1,button2 and button3. button1 creates two imageviews in a tablerow and displays the image. When button2 and/or button3 is clicked, it dynamically adds imageview on the tablerow through layout inflater. When game is over, I want user to click button1 and start things all over again. I am able to do that but the problem is, the imageviews that were previously displayed by clicking button2 and button3 also displays. I want them to be removed when button1 is clicked. How can I remove them on click of button1?
Please help me!
Just like you added views, you can remove them. Just call removeViewAt(int index) or removeView(View view) on the parent container to remove the view(s) you want.
Alternatively, if you foresee reusing them, you can just set their visibility to GONE. Then you could bring them back without the expense of inflating them again.
If you're letting the inflater automatically attach the inflated imageviews to the parent, then you'll have to keep track of the position of the added views. You can use getChildCount on the parent just before inflating to find the index of the next view that will be added.
you can use ViewGroup.removeView(View v);
something like this:
tblRow.removeView(button2);
here is how I add then remove a View 5 seconds later (in another context)
final LinearLayout linearLayout = context.getResources().getLayout(R.layout.activity_main)
LayoutInflater inflater = LayoutInflater.from(linearLayout.getContext());
final View details = inflater.inflate(R.layout.extra_details, linearLayout, false);
linearLayout.addView(details);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (linearLayout.findViewById(R.id.extra_details) != null){
linearLayout.removeView(details);
}
}
}, 5000);
the same use scenario is in the context of onClickListener.
Check more here https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
//add view
LayoutInflater inflater = (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
final View buttons = inflater.inflate(R.layout.activity, null );
addContentView(buttons, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//remove view
((ViewManager)buttons.getParent()).removeView(buttons);

Categories

Resources