How does setting baselineAligned to false improve performance in LinearLayout? - android

I was just building some UI in xml, and Lint gave me a warning and said to set android:baselineAligned to false to improve performance in ListView.
The docs for the Lint changes that added this warning say
Layout performance: Finds LinearLayouts with weights where you should
set android:baselineAligned="false" for better performance, and also
finds cases where you have nested weights which can cause performance
problems.
Can somebody explain why this improves performance, specifically when weight is involved?

By setting android:baselineAligned="false" , you're preventing the extra work your app's layout has to do in order to Align its children's baselines; which can obviously increase the performance. (Fewer unnecessary operations on UI => Better performance)

how android:baselineAligned="false" help . It may not be the answer but help to get concept.
I've just managed to get 3 items (icon, text, button) centered
vertically in horizontal LinearLayout.
This may seem simple, but in reality specifying
android:gravity="center_vertical" as LinearLayout attribute is not
enough - icon is centered, but text and button are not. This is
because (presumably) text have a baseline, and centering algorithm
uses it instead of 'real' vertical center. But what is worse - button
(which comes next to text) is centered using text's baseline!
Specifying android:baselineAligned="false" in LinearLayout turns this
off, and everything centers correctly.

// Baseline alignment requires to measure widgets to obtain the
// baseline offset (in particular for TextViews). The following
// defeats the optimization mentioned above. Allow the child to
// use as much space as it wants because we can shrink things
// later (and re-measure).
if (baselineAligned) {
final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(freeSpec, freeSpec);
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/LinearLayout.java#L1093

Related

ConstraintLayout performance - Guidelines vs Margins

I'm using ConstraintLayout in most of my layouts, and I want to know what's the best practice in the performance aspect:
Using a guideline as a view's limit, including as a margin limit.
Example: 4 guidelines in total, no margins.
guideline picture
Using a view margin, which will result in less accurate spacing, because I will need to insert an arbitrary number of dps.
example: 2 guidelines in total, 2 margins (top + bottom)
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
margins picture
If you have another option, I will be happy to read it.
Also, I would like to know how to track performance of layout configuration such as this (where have you looked / what have you used to give me the answer).
Thanks.
In this case, you can get the same result without guidelines. Percent dimensions can be used in ConstraintLayout.
Just set the "layout_constraintHeight_default" attribute to "percent" (to use percentage units), and set the percentage using "layout_constraintHeight_percent". (width related attributes are available too)
As for the layout performance between 4 widgets, and, 2 widgets and 2 constraints(margins). I am sure that the latter will do better as it takes a smaller layout to render.
However, in this case, the difference is insignificant.

Is there any determining factor for selecting a specific layout in Android?

I'm familiar with almost all the basic layouts in Android & understand when they are to be used. I know that a RelativeLayout is to be used when elements in the UI are to positioned relative to each other, that a LinearLayout is to be used when UI elements are to be displayed vertically or horizontally. So I was wondering if the ease of development was the only factor that determined what layout should be selected or if there was any performance factor involved. I mean I can lay out two ImageViews vertically in Android using both LinearLayout and RelativeLayout, so why use a particular layout then?
There are some performance gains for avoiding certain things, such as nesting RelativeLayout (see this question). Also, the docs recommend making layouts shallow and wide, which can facilitated with RelativeLayout, again for performance reasons.
However, often thinking about such things will be premature optimization for simple layouts, and you should use whatever makes the most sense for the situation.

Weight setting performance [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I heard that the Weight setting inside Layout Parameters can dramatically incrase app's performance. So I am going to use it cautiously, or better - completely avoid using it...
What is the best performance way to build Button that fills 2/3 of avalible width and second Button using the rest (1/3 of width)?
and
What is the best performance way to build Button that fills 100dp of avalible width and second Button using the rest?
Yes, I searched it, but didn't find nothing about the performance, really! :)
Thanks in advance!
So I am going to use it cautiously, or better - completely avoid using it...
Get this thought out of your head quickly. layout_weight can be very handy in the right situations. I would definitely not rule out using it completely. As far as cautiously, I'm not sure what your concerns are but if you use it properly then you will be fine.
What is the best performance way to build Button that fills 2/3 of avalible width and second Button using the rest (1/3 of width)?
The main thing to remember when using layout_weight is that your width of child Views should be 0dp with a horizontal LinearLayout and your height 0dp when using a vertical LinearLayout. See below for a short example. Using layout_weight can help keep your layouts looking the same on different screen sizes/resolutions. If you do something like the below code and don't declare a weightSum in your parent LinearLayout then the CPU will calculate it for you. You only need to declare weightSum if you are doing something where you want empty space or maybe other cases but in general it is best to let it be calculated for you.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
...
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<Button
...
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</LinearLayout>
What is the best performance way to build Button that fills 100dp of avalible width and second Button using the rest?
Using a LinearLayout you can set the width of your first Button to 100dp and the width of your second Button to match_parent. This will result in your first Button being drawn first and your second Button will use the available width.
You can and should use layout_weight when it makes your XML easier. It won't be a problem unless you are having very deep, nested layouts (which is not the case when simply aligning two buttons).
If you worry about performance, take a look at the hierarchy viewer every now and then and check if your layout trees are not too large. Click on one of the top right buttons that estimates the measure/layout/draw times, and see if there are any red dots. Those layouts are possibly too slow, and might need to be optimised.
In general; layout_weights are not that bad.
About implementing, use layout weights for the first question, and 100dp & fill_parent width for the second ( inside linear).

Is it a bad practice to use negative margins in Android?

Demo of negative margin:
                         
The scenario
Overlapping views by setting a negative margin to one of them so that it invades the bounding box of another view.
Thoughts
It seems to work the way you'd expect with overlapping of the layouts if they should. But I don't want to run into a bigger problem for unknowingly not doing things right. Emulators, physical devices, you name it, when you use negative margins everything seems to work correctly, one view invades another's views bounding box and depending on how it's declared in the layout it will be above or below the other view.
I'm also aware that since API 21 we can set the translationZ and elevation attributes to make view appear above or below other views but my concern basically comes from the fact that in the documentation for the layout_margin attributes it's clearly specified that margin values should be positive, let me quote:
Excerpt:
Specifies extra space on the left, top, right and bottom sides of this view. This space is outside this view's bounds. Margin values should be positive.
Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), mm (millimeters)...
In the years since originally asking this question I haven't had any issues with negative margins, did try to avoid using them as much as possible, but did not encounter any issues, so even though the documentation states that, I'm not too worried about it.
In 2010, #RomainGuy (core Android engineer) stated that negative margins had unspecified behavior.
In 2011, #RomainGuy stated that you can use negative margins on LinearLayout and RelativeLayout.
In 2016, #RomainGuy stated that they have never been officially supported and won't be supported by ConstraintLayout.
In December 2020(v2.1.0, official release June 2021), negative margin support for constraints has been added to ConstraintLayout.
It is easy to work around this limitation though.
Add a helper view (height 0dp, width constrained to parent) at the bottom of your base view, at the bottom add the margin you want.
Then position your view below this one, effectively allowing it to have a "negative" margin but without having to use any unsupported negative value.
Hope this will help someone. Here is working sample code using ConstraintLayout based on #CommonsWare's answer:
Add an helper view (height 0dp, width constrained to parent) at the
bottom of your base view, at the bottom add the margin you want. Then
position your view below this one, effectively allowing it to have a
"negative" margin but without having to use any unsupported negative
value.
Sample code:
<TextView
android:id="#+id/below"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F1B36D"
android:padding="30dp"
android:text="I'm below"
android:textColor="#ffffff"
android:textSize="48sp"
android:textAlignment="center"
tools:layout_editor_absoluteX="129dp"
tools:layout_editor_absoluteY="0dp" />
<android.support.v4.widget.Space
android:id="#+id/space"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="#+id/below"
app:layout_constraintLeft_toLeftOf="#id/below"
app:layout_constraintRight_toRightOf="#id/below" />
<TextView
android:id="#+id/top"
android:layout_width="100dp"
android:layout_height="60dp"
android:textAlignment="center"
android:textColor="#ffffff"
android:text="I'M ON TOP!"
android:background="#676563"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/space" />
Output:
Instead of negative margins you can use:
translationX and translationY.
Example:
android:layout_marginBottom = -2dp
android:translationY = -2dp
UPDATE:
Have in mind that the whole view is translated.
In case you want use negative margin,set enough padding for container and its clipToPadding to false and set negative margin for it's children so it won't clip the child view!
It might have been bad practice in the past but with Material Design and its floating action buttons, it seems to be inevitable and required in many cases now. Basically, when you have two separate layouts that you can't put into a single RelativeLayout because they need distinctly separate handling (think header and contents, for instance), the only way to overlap the FAB is to make it stick out of one those layouts using negative margins. And this creates additional problems with clickable areas.
For me, and regarding setting a negative margin on a TextView (I realize the OP is referring to a ViewGroup, but I was looking for issues with setting negative margins and I landed here)... I found a problem with 4.0.3 (API 15) ONLY and the setting of android:layout_marginTop or android:layout_marginBottom to a negative value such as -2dp.
For some reason the TextView does not display at all. It appears to be "gone" from the view (not just invisible).
When I tried this with the other 3 versions of layout_margin, I didn't see the issue.
Note that I haven't tried this on a real device, this is using a 4.0.3 emulator. This is the 2nd odd thing I've found that only affected 4.0.3, so my new rule is to always test with a 4.0.3 emulator :)
I have success with reducing the bottom margin of a TextView by using android:lineSpacingExtra="-2dp" which works even though I happen to have android:singleLine="true" (and so I wouldn't have thought that line spacing would be a factor).
No, you should not use negative margin. instead you should use translate. Even if negative margin work sometime, when you change layout programmably, translate would help. And view can't overflow the screen wen you use margin.
I've only known that it was possible for a rather short period of time. But I see no problem with it. Just be aware of screen sizes and such so you are sure not to accidentally make to items that shouldn't appear overlapped on the screen. (i.e. text on top of text is likely a bad idea.)

Android: trying to understand android:layout_weight

I'm trying to divide a page in three parts. I'd like to do it in percentage values, however that is not supported by Android. Instead I have to use android:layout_weight. But I have a hard time understanding it and getting it right. Especially how the actual size gets calculated. Is there a way to get a percentage value (0..100%) out of android:layout_weight?
I went through a few cases (see attached screenshot) to describe the problems. The colored fields are all <LinearLayout> with android:layout_height="fill_parent", because I want the full screen to be divided between those.
Case 1
Okay, simple. Every <LinearLayout> gets 33%.
Case 2
Ups?! The first (yellow) <LinearLayout> disappears completely? Why?
Case 3
Confused again. The yellow <LinearLayout> is back. However, the two first <LinearLayout> with the heavier weight get smaller? What is going on?
Case 4
I have absolutely no idea what the maths behind all this is.
Is there a way to get a percentage value (0..100%) out of android:layout_weight?
Sure. Make them add up to 100.
For your "percentage value", you want the android:layout_height of the individual items within the LinearLayout to be 0px.
When you use android:layout_height="fill_parent" for the bars, you are not leaving any available space. (Since they are filling the parent.) Because all 3 are set to fill, the requested height is actually 3x the parent height, so the weights are being applied to a negative remaining space. This explains the weird behavior you are seeing, and why setting layout_height to 0px solves it.

Categories

Resources