I have a small project where I want to reuse a certain UI component a few time so I created a widget by expanding a ViewGroup. In that ViewGroup I inflated a view that contained a TextView inside a LinearLayout and added that inflated view to the ViewGroup trough addView.
The outer LinearLayout expands itself perfectly but the inner TextView have getHeight() = 0 and getWith() = 0 when I view it through Hierarchy Viewer. The strange thing is that layout_height and layout_width is the values I gave them in my xml.
I don't have the code here but it looked something like this:
xml:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="random text.."
android:layout_with="200px"
android:layout_height="50px" />
</LinearLayout>
Java:
class MyWidget extends ViewGroup {
...
//In constructor
myView = View.inflate(context, R.layout.xml, null);
addView(myView);
//In layout
myView.layout(l, t, r, b);
I have tried to give my text view fill_parent values for size but it didn't help.
Remember:getHeight() and getWidth()return 0 if components are not drawn yet.
To find the width And height of a View before it being drawn:
First call measure
view.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED)
Now you can get width using getMeasuredWidth and height using getMeasuredHeight
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
I have posted some more ideas here: How to get width/height of a View
1) Here is some links to use Hierarchy Viewer on your dev phone.
http://developer.android.com/guide/developing/debugging/debugging-ui.html
and the class you'll need:
http://github.com/romainguy/ViewServer
2) You can also reuse layout like a component with the include tag:
<include android:id="#+id/your_id" layout="#layout/layout_name" />
So, I put a bounty on this one, and here is what I've found.
Inflating with a null reference is A Bad Idea(TM). Essentially, that View won't get the proper layout parameters it needs (its parent sets a whole bunch of them, with a whole bunch of magic/logic involved). So inflating into null means no parents, and no inherited layout parameters. One can manually set a number of these parameters, but due to the magic involved it might not solve your problem.
The "solution(s)" that I've come up with involve; using include (when you know how many you need) and pulling them into code, or inflating to a parent (when you need true dynamic, N things). And of course, the XML you inflate will have ID collisions, so I go about it by grabbing the last child (e.g. getChildAt(getChildCount()-1) ) of whatever I'm looking for, etc.
Did you try passing yourself as the root:
View.inflate(context, R.layout.xml, this);
Since you will be the parent of this View that complies with the javadoc spec.
Related
From the developer guide it says that
though a view can define a padding, it does not provide any support for margins. However, view groups provide such a support.
but why i can set layout_margin attributes in ImageView,EditView and so on,they exist and work just like padding,
I can't understand what the guide says, Can someone help me to understand it?
Basically that means that margins are defined in xml for child views, but are used by their parent.
Technically, paddings are fields of the View class. Paddings are being used in the View.draw() method by a View itself. See:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/view/View.java#15156
Margins are fields of the MarginLayoutParams class. Margins are used by a ViewGroup to layout its children. See:
http://developer.android.com/reference/android/view/ViewGroup.MarginLayoutParams.html
EDIT:
Margins are loaded to MarginLayoutParams and then used in the layouting phase.
Method which uses these xml attributes to create MarginLayoutParams in FrameLayout:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/widget/FrameLayout.java#678
Loading margins: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/view/ViewGroup.java#6619
Layouting: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/widget/LinearLayout.java#1539
View class does not contain margins. It contains the padding because padding offset the contents of the view. Margin is meant to offset the view itself from the parent, ViewGroup. As such, the margins are contained in the ViewGroup class.
However remember the principle of inheritance. A view is a child of the ViewGroup class. As a result, it inherits the properties of the ViewGroup, including the margins. So when you apply the margin on the view, it responds because it already has the margins properties by virtue of inheritance.
I have an XML definition for a view that I am adding to a larger container view with addChild. It's based on a LinearLayout and looks basically like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="52dip"
android:background="#drawable/box_bg"
android:clickable="true"
android:onClick="onTreeBoxClick"
android:orientation="horizontal" >
<ImageView android:id="#+id/box_photo"
android:layout_width="45dip"
android:layout_height="45dip"
...
/>
<RelativeLayout
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
>
(Remainder omitted -- probably not relevant since it's basically working as designed)
When I create these views, I have found the following behaviors that seem odd to me:
Right after I inflate the view, getLayoutParameters() returns null.
After I call addChild() to add it to its parent, getLayoutParameters() returns a valid object.
Examining the LayoutParameters, I find both width and height set to -2 (WRAP_CONTENT), which is clearly not what I specified in the XML file.
When I look at the layout parameters of the enclosed ImageView, it reads out at the specified values.
Can anyone explain what is going on here? Why isn't my specified height being noticed?
This isn't really affecting me since the parent view is a custom view wherein I force the final dimensions of the children with MeasureSpec etc., but I'd like to understand this anyway!
You didn't provide some details which are important.
1) Right after I inflate the view, getLayoutParameters() returns null.
I would assume that you used this:
inflater.inflate(R.layout.content, null);
in this case the LayoutInflater can't make(at all) proper LayoutParams for the root Linearlayout because it doesn't know who is going to be its parent(so it can create the right type of LayoutParams). If you would use this:
inflater.inflate(R.layout.content, someOtherLayout, false/true);
then the root LinearLayout will have proper LayoutParams because it will see the type of someOtherLayout and create the LayoutParams from this information. You may want to provide a snippet of code to get a better answer if this is not what you currently do.
2) After I call addChild() to add it to its parent,
getLayoutParameters() returns a valid object.
I assume that you speak about the addView() method. The addView() method will check the LayoutParams of the view which is trying to add and if those LayoutParams are null then it will automatically assign that view a LayoutParams object returned by its generateDefaultLayoutParams() method.
3) Examining the LayoutParameters, I find both width and height set to
-2 (WRAP_CONTENT), which is clearly not what I specified in the XML file.
As I said at 2, the generated LayoutParams are coming from the generateDefaultLayoutParams() method which will return a LayoutParams instance as the parent was designed to do. For example, a LinearLayout with orientation HORIZONTAL(the default one) will return a LayoutParams instance with width/height set to WRAP_CONTENT.
4) When I look at the layout parameters of the enclosed ImageView, it
reads out at the specified values.
Because the LayoutInflater took care of this, as the ImageView it's in the interior of the layout and has a known parent from which the LayoutInflater can make the proper LayoutParams.
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've been trying to start programming with the Android OS. Using the tutorials on the website I see that such views as LinearLayout, GridLayout use layout_width and layout_height xml attributes but the documentation never shows the inheritance of these attributes for these layouts. I have read where they're required but don't see how they can use something they never inherit.
Hopefully a simple question that has been bugging me.
Check http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html and http://developer.android.com/guide/topics/ui/declaring-layout.html
XML layout attributes named layout_something define layout parameters for the View that are appropriate for the ViewGroup in which it resides.
Every ViewGroup class implements a nested class that extends ViewGroup.LayoutParams. This subclass contains property types that define the size and position for each child view, as appropriate for the view group. As you can see in figure 1, the parent view group defines layout parameters for each child view (including the child view group).
Note that every LayoutParams subclass has its own syntax for setting values. Each child element must define LayoutParams that are appropriate for its parent, though it may also define different LayoutParams for its own children.
All view groups include a width and height (layout_width and layout_height), and each view is required to define them.
These attributes are inherited by LayoutParams from ViewGroup.LayoutParams: LinearLayout.LayoutParams, GridLayout.LayoutParams, etc.
What is android here?
what is Orientation here?
What is Vertical ?
I would be pleased to know if they are classes or packages or methods..?
I am confused?
Can some one explain hierarchy of it?
I am sure you have seen this inside the <LinearLayout>.
It means that whatever view you take inside the LinearLayout will be shown in screen by vertical (like Stake of views).
Every attributes started with android followed by : so here orientation is an attribute and vertical is the value to be assigned this attribute.
Update:
(Answer taken from here.)
For android:orientation="vertical", your views get stacked vertically like this:
View1
View2
View3
View4
etc...
And For android:orientation="horizontal", your views gets placed horizontally like this:
View1 View2 View3 View4 etc...
This is the XML tag for the Layout properties of any Layout Widget for Android UI.
android:orientation is the XML tag and "vertical" is value for the same. so when it will be loaded in UI framework, child of the layout will be arranged in vertical form.
These are Input parameters for XML tags . Although Java is an object oriented language ,but it does not means that you will consider every element of android as Classes . XML Layout structure is view forming technique which use native kit internally .so these #android:something are just identifier to tell the native kit what to do . nothing else .
This is the code written in android.widget.LinearLayout.java
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mOrientation == VERTICAL) {
layoutVertical();
} else {
layoutHorizontal();
}
}
You can view the SOURCE CODE HERE, Based on the orientation and gravity attribute how the android sets Child Views into Parent.