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.
Related
So suppose I have a textview called tvPlaceholder with the following property android:layout_alignParentEnd="true". How would I go about setting this to be false in the code (Kotlin)? I know you can change things like visibility, text size, e.t.c. in the code but could not find a definitive answer for layout_alignParentEnd. I am also calling tvPlaceholder from a viewholder if that matters at all: viewholder.tvPlaceholder.
When a view is added to a parent, it adds a LayoutParams object that defines any rules for laying it out. You can get this object by calling getLayoutParams(). Each layout parent has their own layout params subclass, I'm assuming this is a relative layout. So for a RelativeLayout, the LayourParams has a function removeRule that can do this.
val params = view.getLayoutParams() as RelativeLayout.LayoutParams
params.removeRule(RelativeLayout.ALIGN_PARENT_END)
I read often something like this:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
What exactly LayoutParams do?
I've read the Documentary but I wasn't smarter after reading!
Hope someone can explain me what LayoutParams do or pass!
Kind Regards!
LayoutParams are the Java Object representation of all the params you give to your View in the .xml layout file, like layout_width, layout_height and so on. Getting this object from a View allows you to look up those params on runtime, but also to change them in your Java code, when you need to move the View, change it's size etc.
LayoutParams are used by views to tell their parents how they want to be laid out.
The base LayoutParams class just describes how big the view wants to be for both width and height. For each dimension, it can specify one of:
FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which means that the view wants to be as big as its parent (minus padding)
WRAP_CONTENT, which means that the view wants to be just big enough to enclose its content.
That's all folks.
LayoutParams is use for the dynamically change the layout width and height. and also use the create custom view without the xml by using the directly by use of the LayoutParams for Relative or Linear type layout.
Basically when you set an xml with 'match_parent' or anything like layout_something
the android inflator will set the layout param for the child with the appropriate Layout params with the type matching the parent control, you could also do this in code and if you forget or set the wrong type you will get an exception in runtime.
the parent control needs this information to layout the child control correctly and to his liking.
Please see the following: Android Developer site - Layout Params
I think this picture says it all
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.
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.
I have a custom component where I know the width and height is always as follows:
android:layout_width="fill_parent"
android:layout_height="wrap_content"
I would like to avoid having to specify the width and height in XML since any other settings are wrong.
I've tried a lot of things, but nothing works. For example, this code doesn't work:
public class MyLayout extends ViewGroup {...
LayoutParams layoutParams =
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
setLayoutParams(layoutParams);
but no matter what I do, I get the exception message "You must supply a layout_width attribute." which goes away if I put back the XML layout_width, layout_height.
I've also tried to Override onFinishInflate(), but that never gets called. I tried inheriting from View, ViewGroup and TableLayout. I've tried calling getLayoutParams(), but it returns null.
How do I get my custom component to not need these specified in XML?
Please no snark.
Thanks.
You have the answer,
LayoutParams layoutParams = new LayoutParams(width, height);
setLayoutParams(layoutParams);
height and width are specified in px, dip, sp
Alternatively, some of them provide with setHeight and setWidth methods, you can use them.