An answer at the end of this question has been filled out, combining remarks and solutions.
Question
I searched around but haven't found anything that really explains why Android Lint as well as some Eclipse hints suggest replacing some layout_height and layout_width values with 0dp.
For example, I have a ListView that was suggested to be changed
Before
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
</ListView>
After
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
Similarly, it suggested changes to a ListView item. These all look the same before and after the changes, but I'm interested in understanding why these are performance boosters.
Anyone have an explanation of why? If it helps, here is general layout with the ListView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/logo_splash"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ImageView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#color/background"
android:layout_below="#id/logo_splash">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
<TextView
android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/no_upcoming" />
</LinearLayout>
</RelativeLayout>
Answer
I'm putting in an answer here because it's really a combination of answers and referenced links below. If I'm wrong on something, do let me know.
From What is the trick with 0dip layout_height or layouth_width?
There are 3 general layout attributes that work with width and height
android:layout_height
android:layout_width
android:layout_weight
When a LinearLayout is vertical, then the layout_weight will effect the height of the child Views (ListView). Setting the layout_height to 0dp will cause this attribute to be ignored.
Example
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
</LinearLayout>
When a LinearLayout is horizontal, then the layout_weight will effect the width of the child Views (ListView). Setting the layout_width to 0dp will cause this attribute to be ignored.
Example
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<ListView
android:id="#android:id/list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</ListView>
</LinearLayout>
The reason to want to ignore the attribute is that if you didn't ignore it, it would be used to calculate the layout which uses more CPU time.
Additionally this prevents any confusion over what the layout should look like when using a combination of the three attributes. This is highlighted by #android developer in an answer below.
Also, Android Lint and Eclipse both say to use 0dip. From that answer below, you can use 0dip, 0dp, 0px, etc since a zero size is the same in any of the units.
Avoid wrap_content on ListView
From Layout_width of a ListView
If you've ever wondered why getView(...) is called so many times like I have, it turns out to be related to wrap_content.
Using wrap_content like I was using above will cause all child Views to be measured which will cause further CPU time. This measurement will cause your getView(...) to be called. I've now tested this and the number of times getView(...) is called is reduced dramatically.
When I was using wrap_content on two ListViews, getView(...) was called 3 times for each row on one ListView and 4 times for each row on the other.
Changing this to the recommended 0dp, getView(...) was called only once for each row. This is quite an improvement, but has more to do with avoiding wrap_content on a ListView than it does the 0dp.
However the suggestion of 0dp does substantially improve performance because of this.
First of all you have this,
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
</ListView>
Never take the ListView's height as wrap_content, that will lead into troubles. Here is the reason for that and this answer.
Further more,
I searched around but haven't found anything that really explains why
Android Lint as well as some Eclipse hints suggests replacing some
layout_height and layout_width values with 0dp.
Its because you are using layout_weight = "1" that means your ListView with take the height as much as is available to it. So, in that case there is no need of using layout_height = "wrap_content" just change it to android:layout_height="0dp" and ListView's height will be managed by layout_weight = "1".
So when android:layout_weight is used on View X and LinearLayout is horizontal, then X's android:layout_width is simply ignored.
Similar, when android:layout_weight is used on View X and LinearLayout is vertical, then X's android:layout_height is ignored.
This actually means, that you can put anything in those ignored fields: 0dp or fill_parent or wrap_content. It doesn't matter. But it's recommended to use 0dp so View's do not do extra calculation of their height or width (which is then ignored). This small trick simply saves CPU cycles.
from :
What is the trick with 0dip layout_height or layouth_width?
as far as i know , there is a difference between using 0dp (or 0px btw, it's the same since 0 is 0 no matter what is the unit here ) and the wrap_content or fill_parent (or match_parent, it's the same).
it depends on the weight you use . if you only use weight of 1 , they all look the same , but the meaning is always different , and it is important for performance.
in order to show this , try the following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical">
<TextView android:id="#+id/textView1" android:layout_width="match_parent"
android:layout_height="0px" android:text="1" android:background="#ffff0000"
android:layout_weight="1" android:gravity="center"
android:textColor="#ffffffff" android:textSize="20sp" />
<TextView android:id="#+id/textView2" android:layout_width="match_parent"
android:layout_height="0px" android:text="2" android:background="#ff00ff00"
android:layout_weight="2" android:gravity="center"
android:textColor="#ffffffff" android:textSize="20sp" />
<TextView android:id="#+id/textView3" android:layout_width="match_parent"
android:layout_height="0px" android:text="3" android:background="#ff0000ff"
android:layout_weight="3" android:gravity="center"
android:textColor="#ffffffff" android:textSize="20sp" />
</LinearLayout>
and then try to replace the 0px with match_parent . you will see that the result is very different.
usually , for both better understanding and for better performance , you would want to use 0px.
LinearLayout measures all the children according to the layout_width/layout_height values, then divides up the leftover space (which may be negative) according to the layout_weight values.
0dp is more efficient than wrap_content in this case because it's more efficient to just use zero for the original height and then split the parent's full height based on the weight than to measure the child first and then split the remainder based on the weight.
So the efficiency comes from not measuring the child. 0dp should be exactly as efficient (and produce exactly the same result) as match_parent, or 42px, or any other fixed number.
Caution re using android:layout_height="0dp"
I have found that in a ListView
(with the recommended View recycling using convertView, see e.g. http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/),
setting android:layout_height="0dp" for the row TextView can lead to text truncation for multi-line text content.
Whenever a TextView object that was previously used to display a text that fitted in a single line is recycled to display a longer text that needs more than one line, that text is truncated to a single line.
The problem is cured by using android:layout_height="wrap_content"
Related
I am doing the following course at udacity. It's about Android User Interface.
As a part of my course I used an XML visualizer.
http://labs.udacity.com/android-visualizer/#/android/linear-layout-weight
Now upon experimenting I entered the following code
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:src="#drawable/ocean"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:scaleType="centerCrop"
android:layout_weight = "1"/>
<TextView
android:text="You're invited!"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:textColor="#android:color/white"
android:textSize="54sp"
android:layout_weight = "1"
android:background="#009688" />
<TextView
android:text="Bonfire at the beach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#android:color/white"
android:textSize="34sp"
android:background="#009688" />
</LinearLayout>
as per my understanding, by using android:layout_weight the whole parent layout is divided as per priority and distributed accordingly, if so, the space after distributing among image and "You're invited!" there should only be remaining space enough, to fill out "Bonfire at the beach".
Then why there is a empty space below "Bonfire at the beach" ?
(Also if possible can anyone please explain how the control flows among XML code).
UPDATE
when I added android:layout_weight = "0" in "Bonfire at the beach" then there is no empty space below. Can any one explain why this happens and why there is space in previous case. and this is the code is used.
before
after
even tried setting height to 0dp
Understand it using the below example
Weight defines how much space a view will consume compared to other views within a LinearLayout.
Weight is used when you want to give specific screen space to one component compared to other.
Key Properties:
weightSum is the overall sum of weights of all child views. If you don't specify the weightSum, the system will calculate the sum of all the weights on its own.
layout_weight specifies the amount of space out of the total weight sum
the widget will occupy.
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="4">
<EditText
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Type Your Text Here" />
<Button
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Text1" />
<Button
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Text1" />
</LinearLayout>
The output is:
Now even if the size of the device is larger, the EditText will take 2/4 of the screen's space. Hence the look of your app is seen consistent across all screens.
[This if before you edit your question might be irrelevant now
Now in your Bonfire at the beach there is no weight and its wrap_content so there is no grantee that it will take the remaining space! and that space can remain after adding it will differ with the screen size of device ]
Note:
Here the layout_width is kept 0dp as the widget space is divided horizontally. If the widgets are to be aligned vertically layout_height will be set to 0dp.
This is done to increase the efficiency of the code because at runtime the system won't attempt to calculate the width or height respectively as this is managed by the weight. If you instead used wrap_content the system would attempt to calculate the width/height first before applying the weight attribute which causes another calculation cycle.
Lets Move to your XML
see how i used them
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:weightSum="3" //<-------------------
android:layout_height="match_parent">
<ImageView
android:src="#drawable/mc"
android:layout_width="match_parent"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:layout_weight = "1"/> //<-------------------
<TextView
android:text="You're invited!"
android:layout_width="match_parent"
android:layout_height="0dp"
android:textColor="#android:color/white"
android:textSize="54sp"
android:layout_weight = "1" //<-------------------
android:background="#009688" />
<TextView
android:layout_weight = "1" //<------------------- if you remove this , this text view will be gone cuz its 0 by default
android:text="Bonfire at the beach"
android:layout_width="match_parent"
android:layout_height="0dp"
android:textColor="#android:color/white"
android:textSize="34sp"
android:background="#009688" />
</LinearLayout>
Now you ask what if you have not given android:layout_weight ,Default weight is zero. Zero means view will not be shown, that empty space will remain there
Since you don't believe you can read the documentation
EDIT: 2
Since you said that, i went through android-visualizer that you use
and Have you ever noticed this...
"Line 6: The attribute android:weight_sum is not supported here."
thing on its bottom.
Meaning they are not providing that functionality to adjust your layout boundaries. Its just a simple online tool.I am
not saying it is not recommended to use, but my personal idea is, you
can't touch the depth of android if you use that.
Now if you want a confirmation what actually happens have a look on android studio/ eclipse as well which are read IDE s
This is android studio
Can you see any view contain your text "Bonfire at the beach"? no
Instead a.studio display a red line in XML.
Suspicious size: this will make the view invisible
Because there is no layout_weight is given and we have added 0 height
Now you can accept the answer :)
This question already has answers here:
What does android:layout_weight mean?
(13 answers)
Closed 2 years ago.
The xml layout is like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="bottom"/>
</LinearLayout>
And it turns out that the textview will be placed to the bottom of its parent.I think layout_weight is used to allocate unusesd space and it's very common to use layout_weight with code like :
android:layout_width="0dp"
But in this case,the first layout asks to occupy all spaces with:
android:layout_width="match_parent"
android:layout_height="match_parent
So how does layout weight work here?
PS:I have read this question: What does android:layout_weight mean? but I don't think it accounts for this question.
layout_weight specifies how much of the extra space in the layout to be allocated to the View.
The first linearlayout has already taken the whole space with attribute match_parent,why setting layout_weight enables the second view to showup at the bottom ?
I believe this is not the common usage of layout_weight.Hope somebody point out my mistake.
When you use layout_weight attribute it is used to calculate the weightage of child views of the single parent.
As you have not mentioned weight of all other views it's behaving wrong.
layout_weight is useful when you want your child views to be certain percentage of the parent view.
for example,
in parent view you need to mention:
android:weightSum="1"
So your parent view will have total weight as 1, and in both of the views you need to mention the:
android:layout_weight=".9" and android:layout_weight=".1"
so the first view will take 90%, and second view will take 10% of the space.
To be more clear Ideally the sum of weights of all the childs should be equal to the weightsum mentioned in parent, to it work as expected.
**And as you have provided android:layout_width,android:layout_height` of the textview, this is the mistake as it will make issue in the weight.
So to use weight attribute correctly you need to give other specs as 0dp in order to weight to apply successfully.**
Note: When you use weight other specs like android:layout_width,
android:layout_height should be set to 0dp.
To understand it practically, why don't you play around with below
layout:
Just Try to change the weight of linear_layout, text_view and you will see, how it's supposed to works ideally:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="100" >
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:background="#android:color/holo_blue_bright" >
</LinearLayout>
<TextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="90"
android:background="#android:color/white"
android:text="bottom"
android:textColor="#android:color/black" />
</LinearLayout>
If you want to place your components in separate boxes in layout ,you should use LinearLayout.
You can define the manner of boxes place with orientation vertical or horizental.
You can define their size easily with layout_weight.
look here:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id=#+id/parent_linear>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4">
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="bottom"/>
</LinearLayout>
parent_linear divides your layout in 2 parts(because you use 2 components) vertically. Now you can set weights to child's components width. So,(for TextView) you set android:layout_width="0dp" for its width and android:layout_weight="2" ..follow it for LinearLayout- .
The result of this is parent_layout divide itself into 6 parts (2+4=6),and allocates 4 parts to LinearLayout and 2 for TextView.
I have searched google and stackoverflow thoroughly, but the only answer I get is: set each Tablerow with layout weight = "1". This doesnt work.
Now I have eight rows in a TableLayout, and each contains 5 LinearLayouts. Each of the LinearLayouts contains 2 TextViews, and the FontSizes vary from TextView to TextView.
It turns out that the TableRows vary in height, depending on the Fontsizes of the contained TextViews.
Strangely enough, it doesnt have any impact on the layout whether I set the layout_height of the TableRows to "0dp" or to "match_parent" or "fill_parent".
How can I force the TableRows to have the same height? I dont want to use a specific pts value as height, because the tableRows must divide the whole screen equally between themselves.
Here is part of the xml, the actual file is huge:
<TableLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6"
android:weightSum="8"
tools:context=".MainActivity" >
<TableRow
android:layout_width="match_parent"
android:layout_weight="1"
tools:context=".MainActivity">
<LinearLayout
android:clickable="true"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/btnmargintop"
android:layout_marginBottom="#dimen/btnmarginbot"
android:layout_marginLeft="#dimen/btnmarginleft"
android:layout_marginRight="#dimen/btnmarginright"
android:layout_weight="1"
android:background="#drawable/bg" >
<myapp.TypefacedTextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="#integer/layoutweight1"
android:layout_gravity="center"
stevens:typeface="myfont.otf"
android:clickable="false"
android:textSize="#dimen/fontsize1" />
<myapp.TypefacedTextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="#integer/layoutweight2"
android:layout_gravity="center"
stevens:typeface="myfont.otf"
android:clickable="false"
android:textSize="#dimen/fontsize2" />
</LinearLayout>
According to the Android developer Documentation of TableLayout, you cannot do that.
The children of a TableLayout cannot specify the layout_width
attribute. Width is always MATCH_PARENT. However, the layout_height
attribute can be defined by a child; default value is
ViewGroup.LayoutParams.WRAP_CONTENT. If the child is a TableRow, then
the height is always ViewGroup.LayoutParams.WRAP_CONTENT.
However, you can use a vertical LinearLayout to achieve a similar effect.
You are probably letting the layout of your tab to automatically adjust to the size of the content inside. There are two ways, to settle things down:
Make sure all the elements share the same size - that being said, don't worry about the table as a whole, just make sure, that the dimensions of the elements inside are the same
Or simply set the height of the parent layout and don't let the elements make a difference. Problem with this solution is, that if you get bigger inside, you'll be out of space, so you may want to stick with the first option
I'm confused and frustrated that I can't get my EditText field to take up a rational amount of space in the layout without explicitly telling it how many pixels to be.
I'm *sure I'm missing something obvious, but my experience is that EditText totally ignores layout_weight and either grows/shrinks dynamically with the text that is entered into it if I give it a layout_weight of "wrap_content" or takes up most of the space in its parent layout if I give it a weight of fill_parent.
So... what is the correct path to having an EditText field that occupies some portion of its parent layout (in my case Linear, but I'm flexible) so that it can have a label next to it and look like:
Name: [ EDIT TEXT HERE ]
Phone:[ EDIT TEXT HERE ]
etc.
TIA
You can do a couple different things. As mentioned, you should be using dp instead of pixels for layout. Using dp allows your views to scale by the screen's physical size rather than resolution.
Here's an example of specifying the edit boxes to appear to the right of each label and take up the remainder of a the screen:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/name_label"
android:layout_width="100dp"
android:layout_height="50dp"
android:text="Name:" />
<TextView
android:id="#+id/phone_label"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_below="#id/name_label"
android:text="Phone:" />
<EditText
android:id="#+id/name_text"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_toRightOf="#id/name_label" />
<EditText
android:id="#+id/phone_text"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_toRightOf="#id/phone_label"
android:layout_below="#id/name_text" />
</RelativeLayout>
Here's an example of a LinearLayout where weight is used:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Name:"
android:layout_weight="1"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Phone:"
android:layout_weight="1"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"/>
</LinearLayout>
</LinearLayout>
Note that the LinearLayout has 7 views while the RelativeLayout accomplishes something similar with 5 views. LinearLayouts hare handy, but they're more complex. As your layouts get more complicated, they will perform worse than RelativeLayouts, especially when you nest them.
For each line use a horizontal LinearLayout.
Inside that, add a horizontal LinearLayout to 'wrap' the TextView. Give that LinearLayout a layout_weight of 20 (for example).
Use another horizontal LinearLayout to 'wrap' the EditText and set the EditText to fill_parent but give its outer LinearLayout a layout_weight of 80 (or whatever value based on 20+80 = 100% if you see what I mean).
EDIT: Also if you need to have multiple lines then to simplify the overall layout file, you can define a 'single line' layout file and use it as a custom layout entry.
//for your edittext set min width and max length
android:minWidth="40"
android:maxLength="30"
android:layout_width="wrap_content"
so that it will be always shows minimum width and your characters wont exceed more than 30.
You need to work with the Layout. LinearLayout is not the right Layout for your purposes. Have a look at TableLayout, which I think might fulfill your requirements. Have a look at the TableLayout tutorial.
I have this as part of my layout:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:orientation="horizontal"
android:layout_weight="0.15">
<TextView
android:id="#+id/question_text"
android:layout_width="0dip"
android:layout_height="fill_parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="#string/score_label" />
<TextView
android:id="#+id/score_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" />
</LinearLayout>
The first TextView is empty at the beginning of the application. Its content is changed dynamically. This makes it occupy zero space so that the second TextView is aligned to the left, even though its layout_gravity is set to right.
How can I make it occupy a fixed width, without taking the contents into account?
I thought about using layout_weight, but I know the recommendation is against using nested weights (the parent ViewGroup has a layout_weight attribute). Maybe I should use a RelativeLayout?
Thanks for any suggestions.
I solved a similar problem using the attribute android:ems="<some number>" on the TextView. An "ems" is the width of the character "M". This attribute makes the TextView exactly the given no. of ems wide.
http://developer.android.com/reference/android/widget/TextView.html
You have all of your TextViews width set to android:layout_width="wrap_content" which means that if there's nothing in there it will have no width. You need to set that to either "match_parent" which will make it the same width as it's parent container or set it to a fixed value, something like android:layout_width="100dp".