I've read this answer : https://stackoverflow.com/a/5027921/1364174
And wonder why depending on the root parameter inflate method changes its behavior such drastically creating confusion.
According to that answer this code:
view = LayoutInflater.from(getBaseContext()).inflate(R.layout.smallred, null);
parent.addView(view);
Will create will create view specified in smallred.xml completely ignoring the properties of tags replacing them with some mysterious defaults values.
But this code will respect the properties from smallred.xml
view = LayoutInflater.from(getBaseContext()).inflate(R.layout.smallred, parent, false);
parent.addView(view);
Why is that ? Why we need to specify root/parent to which we later insert our view to, nflate" method?
Why is that necessary ? Why if we wouldn't we won't get the properties from .xml file ?
Probably because attributes are read only when you are actually inflating the view, so once you inflate it without providing the parent you will be missing information inside the inflated view. Then it doesn't matter if you add it to a parent, the data isn't there so the layout won't be as you expected it to be.
The layoutinflater doesn't know about your parent when he's inflating your view. So it doesn't even know its class. If you notice, every layout has its own LayoutParams class inside it, and you have to tell the layoutinflater which one it has to use or they will be simply discarded.
Related
I am aware of a post that was made before this pertaining to the same topic, however it was in java.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
This was the definition the docs gave me, "Instantiates a layout XML file into its corresponding android.view.View objects." What does this mean?
Then there is the inflate method which the docs state "Inflate a new view hierarchy from the specified XML node."
Could someone explain to me in simpler terms what Layoutinflater and it's method inflater do?
TL;DR The "inflater" reads the XML layout file, which defined what View objects to create and where to put them, and actually does the View creation.
Some helpful terms:
View - Anything that inherits from the View class, e.g. TextView or Button
Layout - an arrangement of different View objects on the screen (this is what you see looking at the app)
XML Layout File - An XML text file that describes a layout - specifically what Views go in that layout and how to position them (e.g. activity_main.xml). The XML file is not the layout, it is a description of how to build the layout.
Inflater - A routine/object that takes an XML layout file, reads it, and actually creates the Layout (arrangement of View objects). Calling inflate on the inflater returns a View object that contains everything you defined in the XML file.
More Details
A screen you see in an Android app is a collection of "Views". These may be things like TextView, ConstraintLayout, EditText, Button, etc... - all different types of views (they all inherit from the View class).
When you build up a layout of those views you typically use an XML file to define what views to create and where to position those views. The XML file is not the view itself, it is just a description of how the views should be constructed and positioned.
The layout inflater takes that XML file and actually goes about building the views as you see them on the screen in the app. When you call inflate it reads all the data about the views from the XML file, creates instances of those views, and positions them in the parent view container based on what you told it to do in the XML file.
In the example code you showed (from a RecyclerView adapter) the XML file it is referring to is the one that describes how to arrange the views in a given row in the RecyclerView. Once the adapter "inflates" the view for that row, then the actual view objects (e.g. TextViews) have been created and positioned within that row.
The RecyclerView adapter will call this method multiple times, to "inflate" a new unique view instance for each displayed row. The "recycler" part of the RecyclerView means that it will try not to call this more than necessary, and will re-use the views on new rows where it can as you scroll.
Additional Reading
Official docs,
What does layout inflater in Android do?
What is layout inflater and how do I use it?
Short Story:
I have a layout "layout.xml", which gets replaced by another layout "success.xml" after a successful web request. Both layouts have an ImageView that provides the backgrounds to the layouts. These 2 backgrounds both need to be the same, and both are dependent on a user preference.
Longer Story: This all happens in a Fragmnet with an AsyncTask replacing the contentView with "success.xml" in onPostExecute after the web request. This happens as follows:
View view = getView();
view = null;
view = View.inflate(context, R.layout.success, null);
What I tried to do is give both ImageViews the following android:id="#+id/background_image" and then call
ImageView background = (ImageView)view.findViewById(R.id.background_image);
background.setImageResource(R.drawable.bg1);
This background-setting works for the initial view (layout.xml), but on trying to change to "success.xml", I get a NullPointException because background is null.
I've checked and the View's id is set to -1 while the original view's background_image id is set to something sensible and valid.
I've also tried setting the second view's background id like this: android:id="#id/background_image", i.e. without the '+', but still no luck.
The added complication is that it's not just 2 layouts, but about 5 that I need to do this for, so it would be really handy to recycle view id's.
Any help would be greatly appreciated.
Your code for replacing the fragment's view will not do what you want, the original view will remain the same as you change only a reference to that view and not the actual object.
To replace the view of the fragment with the new layout you could have another ViewGroup(for example a FrameLayout) in the basic layout (layout.xml) wrapping your current content(don't forget to give it an id) of layouts.xml(as I understand this is the basic layout). Then, when it's time to replace the layout you could simply do:
// remove the current content
((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)).removeAllViews();
// add the new content
View.inflate(context, R.layout.success, ((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)));
You could avoid adding an extra layout if, by any chance, all your five layouts have the same type for the root view(like a LinearLayout etc). In this case you would use the same code as above but you'll modify the other layouts file to use a merge tag. Also, you'll be looking for the id of the root in the layout.xml layout into which you'll add the content of the other files.
Then you could have the same ids, but you'll have to reinitialize any reference to the views(meaning that you'll have to search for the view again if you store a reference to the view(like a Button field in the fragment class)).
I have a complex empty view in a layout, with an icon, text, button, etc.
It is easy to select a view within my layout.xml to use when the listview is empty, similar to
getListView().setEmptyView(findViewById(R.id.empty));
This code sets the empty view works just fine when it resides in the layout.xml file.
Now I want to refactor this view into its own empty.xml layout file, and have coded it similar to the following:
// Setup the empty layout.xml
LayoutInflater vi = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vlEmpty = vi.inflate(R.layout.empty, null);
// Find the empty layout view
vEmpty = vlEmpty.findViewById(R.id.llEmpty);
vEmpty.setOnClickListener(ocl);
// Find the ListView
vListView = (ListView) findViewById(R.id.lvWords);
vListView.setEmptyView(vEmpty);
The problem is that the details within llEmpty never show up; The exact same layout and view works withing the main layout, just not refactored into its own xml file.
Has anyone got something like this to work?
You might need to pass the proper context to the inflater:
vListView = (ListView) findViewById(R.id.lvWords);
View vlEmpty = vi.inflate(R.layout.empty, (ViewGroup)vListView.getParent());
which (should) make them both live in the same root view. It may be sufficient to just pass the root view of the parent activity.
Let me know if that works.
I doubt that setEmptyView() automatically makes the supplied View a child of any container in your activity.
Personally, I'd just use the <include> element rather than inflating it separately. But, if you really want to inflate it separately, the answer that Femi posted while I was writing this may work, depending on what the ListView's parent is.
I am new to android development and keep coming across references to Inflating views from a layout xml file. I googled and searched the development guide but still wasn't able to pick up a sense for what it means. If someone could provide a very simple example, it'd be much appreciated.
When you write an XML layout, it will be inflated by the Android OS which basically means that it will be rendered by creating view object in memory. Let's call that implicit inflation (the OS will inflate the view for you). For instance:
class Name extends Activity{
public void onCreate(){
// the OS will inflate the your_layout.xml
// file and use it for this activity
setContentView(R.layout.your_layout);
}
}
You can also inflate views explicitly by using the LayoutInflater. In that case you have to:
Get an instance of the LayoutInflater
Specify the XML to inflate
Use the returned View
Set the content view with returned view (above)
For instance:
LayoutInflater inflater = LayoutInflater.from(YourActivity.this); // 1
View theInflatedView = inflater.inflate(R.layout.your_layout, null); // 2 and 3
setContentView(theInflatedView) // 4
"Inflating" a view means taking the layout XML and parsing it to create the view and viewgroup objects from the elements and their attributes specified within, and then adding the hierarchy of those views and viewgroups to the parent ViewGroup. When you call setContentView(), it attaches the views it creates from reading the XML to the activity. You can also use LayoutInflater to add views to another ViewGroup, which can be a useful tool in a lot of circumstances.
Inflating is the process of adding a view (.xml) to activity on runtime. When we create a listView we inflate each of its items dynamically. If we want to create a ViewGroup with multiple views like buttons and textview, we can create it like so:
Button but = new Button();
but.setText ="button text";
but.background ...
but.leftDrawable.. and so on...
TextView txt = new TextView();
txt.setText ="button text";
txt.background ... and so on...
Then we have to create a layout where we can add above views:
RelativeLayout rel = new RelativeLayout();
rel.addView(but);
And now if we want to add a button in the right-corner and a textview on the bottom, we have to do a lot of work. First by instantiating the view properties and then applying multiple constraints. This is time consuming.
Android makes it easy for us to create a simple .xml and design its style and attributes in xml and then simply inflate it wherever we need it without the pain of setting constraints programatically.
LayoutInflater inflater =
(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View menuLayout = inflater.inflate(R.layout.your_menu_layout, mainLayout, true);
//now add menuLayout to wherever you want to add like
(RelativeLayout)findViewById(R.id.relative).addView(menuLayout);
A layman definition for inflation might be to convert the XML code to Java code. Just a way to understand, e.g., if we have a tag in XML, OS has to create a corresponding Java object in memory, so inflatter reads the XMLtags, and creates the corresponding objects in Java.
I think here "inflating a view" means fetching the layout.xml file drawing a view specified in that xml file and POPULATING ( = inflating ) the parent viewGroup with the created View.
Because we make UI into XML but view objects is what we display so we somehow need to convert xml into view objects so inflating means we are converting xml into view objects so that it can be displayed, for this we need a service called layout inflator service and give it an xml and it will be convert for you.
In the iOS UIKit universe, this means getting the reference to the .Xib (which is XML, just like android) file and adding it to the current ViewController's view hierarchy.
Can anybody please tell What Inflator is and how it is being used in an Android application?
I don't know the exact use of it and Why it is being used.
My preferred way to handle inflation:
//First get our inflater ready, you'll need the application/activity context for this
LayoutInflater mInflater;
mInflater = LayoutInflater.from(mContext);
//Inflate the view from xml
View newView = mInflater.inflate(R.layout.my_new_layout, null);
//Then you'll want to add it to an existing layout object
mMainLayout.add(newView);
//Or perhaps just set it as the main view (though this method can also
// inflate the XML for you if you give it the resource id directly)
setContentView(newView);
Basically, you use it to inflate existing xml layouts at runtime. Usually you go ahead and insert those new views into previously defined ViewGroups or List objects.
Not quite sure what you mean, but if its related with inflating views, its used to load layout xml files into your application. e.g by
View myWelcome = View.inflate(this, R.layout.welcome, null);
Its easier and consider best practice to have you view definition inside layout xml files, instead of creating your views fully by code.
layout inflator is used to return a java object of your complete layout
suppose you have a layout xml file in which the root element is relative layout and it contains a imageview and textview then using layout inflator you can return a view object that refers to entire layout.
this basically is used in list view and grid view to plug into them a layout object of single row or element which is to be repeated.
you were asking for use of Inflator..
basically when you want to use two xml files in one java class ,inflator is used and its code is simple which is given below..
TextView text;
View layout;
LayoutInflater inflator=getLayoutInflater();
layout =inflator.inflate(R.layout.new_xml_that you want to use in that java class,null);
text=(TextView)layout.findViewById(R.id.text);
text.setText("progressing");
here i use textview,this is present in next xml with id=text
thats it..
if you find this worthy then please like this..
thanks