This makes no sense to me, coming from CSS. In CSS, if you specify a margin and then margin-left, the left margin will assume the more granular value.
In Android, it is the opposite. Same goes for android:radius, and I'm sure other values.
My question is: why?.. It makes no sense. Is there a single reason for doing it this way?
Edit: prompted by trying to find a solution to yet another Google ADT/Android bug http://code.google.com/p/android/issues/detail?id=7588
I have had the same frustration, but if you think about it, which value should be used? I know in your post you say that CSS uses the "more granular value" but it all boils down to pixels in the end and the result is simply two pixel values that need to be chosen between. The CSS standard chose to do it one way, Android chose the other, I don't think either approach is wrong, they are just different.
Related
I'm looking for something equivalent to MultiSlider's different colours for each bin feature but in the modern 'Materials Range Slider'.
MultiSlider's example:
MultiSlider's example
(from https://github.com/apptik/MultiSlider)
However Multislider is no longer being maintained as of 2 years ago and I don't want to depend on unmaintained code.
I've looked at the xml attributes for the Range Slider and I don't see something that would accomplish this. (https://developer.android.com/reference/com/google/android/material/slider/RangeSlider)
Context: I have three percentage based inputs that are user defined. A range slider seemed to be the most efficient way of dealing with having these three percentages defined nicely (without worrying about rounding, having it all equal to 100%, dealing with users typing in stuff, etc).
Is there a better way of dealing with three percentage based inputs then range sliders? If so, what is it?
If not, is it possible to implement this idea with range sliders?
If not, what third party libraries would you recommend?
Thanks in advance.
(It looks like this question comes closest, but if there is another solution besides 'make it yourself', that would be great, and if not, I'll make it myself then: Circular Progress bar with three different color in Android)
What I've tried:
Using Multislider: couldn't get it to build properly
Using Range Slider: can't seem to modify the colour of only one side of the track. There seems to only be 'active' track and 'inactive' track.
Is there any reason to avoid having dps defined directly in the xml files?
E.g. is there any reason to prefer:
android:layout_marginLeft="#dimen/left_margin"
over this:
android:layout_marginLeft=16dp
If I understand correctly, this would make sense only for tablets but in that case won't we have a relevant xml in land with the relevant values?
Also if is there anything to be careful in regards to adding something to dimen.xml? E.g. should left_margin be defined in all dimen.xml for all dimension?
There's a good reason for using the first. Lets say that you decide on really big devices you want a bigger margin. With the first, you only have to override the dimens file and override the 1 dimension. In the second, you have to override the entire layout, which causes larger maintenance issues.
(Also you should almost always be using marginStart and marginEnd instead of left and right, so you handle RTL languages correctly).
One good reason would be that maybe you have a whole lot of layouts where marginLeft needs to be the same. You could set them all to 16dp right in the layout files, but what if you need to change that dimension? If you have 16dp defined in every layout, you'll have to change every single instance of it, and you might forget some. If it's defined in dimens you only have to change it once.
Another reason would be themers. Someone might make a theme for your app. It's a lot easier to override extracted values than having to override and copy an entire layout just to change one value.
And as Gabe says, you really should use start and end instead of left and right, whenever possible. Otherwise, your app will look terrible on devices using RTL.
Some commonly used android layouts such as
RelativeLayout and LinearLayout (when weights are nonzero)
have onMeasure() implementations that measure their children
twice, resulting in exponential running time when nested.
This is easily verifiable by emitting Log entries
from a leaf View's onMeasure()... it gets called 2depth
times.
Can someone give a clear and specific description as to why this is?
Most importantly, is this exponential behavior due to an important part
of the overall contract, or is it just an implementation detail
that might be optimized away? If it is believed to be unavoidable,
please give an example that requires it.
Such an example would greatly help me and others
who are grumbling that the "keep your layouts shallow"
mandate is burdensome and who are wondering
whether this is being driven simply by
not-yet-optimal algorithms in the core libraries,
or whether there really is a fundamental difficulty
blocking a fix.
Perhaps a minimal example would consist
of a Button inside a LinearLayout inside another LinearLayout
(with match_parent and weight=1 everywhere, to trigger
the full exponential behavior),
with some additional parameters or circumstances
making it clear that all four of the calls
to Button.onMeasure() are indeed meaningful and necessary.
My first guess would be that only two linear-time
traversals are really needed-- the first traversal to gather everyone's
preferred sizes, the second traversal to distribute slack
and/or shrinkage.
Other layout engines in the world, such as those for Tex and Swing and HTML,
seem to be able to routinely handle very deep hierarchies
having lots of alignment constraints and stretches,
without any exponential blowup, and I imagine that's how they work.
Please note, I don't want answers explaining how
the exponential blow-up occurs-- I understand that,
and there have been several posts already where that has been
asked and answered:
Why are nested weights bad for performance? Alternatives?
Android layout measuring time doubles with each step up the hierarchy
Layout Weight warning Nested weight bad performance
Efficiency of Android Layout hierarchy
http://android-developers.blogspot.com/2009/02/android-layout-tricks-1.html
My question is whether the recursive double-measuring is
fundamentally necessary/justified,
and if so, I'd like a clear explanation/example showing why.
Edit 2013/8/22: I think maybe my question is still not getting across.
I'll try to clarify and explain my motivation, more boldly this time.
Layout is not an exponentially hard problem,
as evidenced by efficient layout engines in the world, such as those for Tex and Swing and HTML.
So, what happened with LinearLayout,
and how should the android developer community proceed in response?
I am asking not in the spirit of laying blame,
but rather to understand and decide how to best move forward.
I can think of 4 possibilities:
Fix the performance bug in the core library, without changing any contracts
Change contracts as needed, and fix the performance bug in the
core library
Write an alternative to LinearLayout, that has its essential
features (namely distributing extra space among children in specified proportions) but without the performance bug, and use it for new apps
Continue to micromanage our layouts to work around the
performance bug for the rest of our android development careers.
(4) isn't a serious option for me personally.
Furthermore it seems clear to me that
changing the behavior of LinearLayout at this point is impractical,
so I don't believe (2) is a serious option either.
That leaves (1) and (3).
I'm capable and willing to do either of those personally, but which one?
Obviously (1) is far preferable if it's possible-- so, is it possible?
That seems to be the crucial blocking question that needs to be answered
in order to determine how to move forward.
I have spent some time in the core code
and the doc and it's not becoming clear,
so that is why I'm asking the question here.
In terms of measuring children twice, it's my understanding that this is what happens with LinearLayouts particularly when weights are involved. The best explanation I've found for this comes from RomainGuy in one of his presentations.
He has a slide about this and briefly speaks to it at 17:45. Feel free to rewind to get a bit of context though. You can find the video I'm referencing here: Devoxx'10 - Dive Into Android
Basically what he says is that on the first pass they calculate the total width or height depending on orientation of the LinearLayout, add the weights of the children, and find out how much space is left over, then on the second pass with that information they are able to properly divvy out all the remaining space to all the children. Simple enough.
I'd also like to point out though that yes, while it's very true that shallow layout hierarchies have less of a performance hit, if you are adding just 1 or 2 extra layers, you probably aren't going to see a big performance impact for the user. Once it's laid out, it's done. Even in ListView's if you properly use the given "convertView", and set up ViewHolder's, you're going to get good performance.
I'd encourage you to use DDMS and do a layout dump of some of Google's apps. They are very complex, and often times surprisingly deep, but they still get good performance. Don't be stupid with your layouts, but if it saves you time, adding an extra layout isn't the end of the world.
From here: http://developer.android.com/guide/topics/ui/how-android-draws.html
A parent View may call measure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small (that is, if the children don't agree among themselves as to how much space they each get, the parent will intervene and set the rules on the second pass).
It seems they view the measurement pass as a dialog between parent and children. In other words they opted for maximum flexibility instead of optimization. It still seems like they could optimize the base layouts though.
I came here tonight to ask this. It's disappointing that nobody else even seems to understand your question. After thinking about it for a couple more hours, I think I might know the answer.
Consider this example:
The red box represents a LinearLayout with vertical orientation. The green box represents another LinearLayout with horizontal orientation. I would expect the layout to proceed like this:
1) The red LinearLayout would measure the heights of green LinearLayout and the large blue widget on the bottom, then compare their weights, divide any leftover vertical space accordingly, and measure the children again. (The important thing to know here is that "measuring" a view actually sets its size.)
2) The green LinearLayout would then measure the widths of its three children, compare their weights, divide the horizontal space, and "measure" again.
The catch is that in order for the red layout to measure the height of the green layout, the green layout needs to know the height of its children.
Now, you would think that LinearLayout would be smart enough to optimize away many of its calculations. For example, there is no logical reason for the green layout to measure the width of its children when determining its own height. And if its children all have a height of fill_parent, then it shouldn't need to perform any calculations at all.
But the API doesn't allow LinearLayout to be that smart. The fundamental problem is that there is no way to measure only one dimension of a view. You can get them separately after they've been measured, but the actual measurement is done by View#onMeasure(int, int). The arguments to that method are encoded with View.MeasureSpec, and there's no way to encode "ignore this dimension." So the green LinearLayout stupidly calculates both dimensions of all its children when the red layout measures it, then repeats the entire process again when it does its own layout. The widths will not have changed the second time around, but they must still be recalculated because, again, there's no way to tell the layout or its children to measure only one dimension.
So to answer your question... no, it doesn't necessarily need to be this way, at least for many common use cases. This is a deficiency of the Android API.
If Google were to add new methods to View to measure dimensions separately, the default implementation would have to rely on onMeasure(int, int), which could be even worse for performance. But if there are any unused bits in the View.MeasureSpec encoding, then it might be possible to add an "ignore" flag that would allow future versions of LinearLayout to be better optimized.
The problem in my opinion is the measure cache. As far as I could see the cache only works if there was a layout of the view in the middle, so when you perform two consecutives measures of a child (even with the same exact measure specs) in the same "onMeasure" all the children and their sub-children are measured again. If the measure cache worked fine, the second measure should be much faster as it would take the cached values and it wouldn't cause all the children hierarchy to be measured again.
Rather surprised that I haven't been able to found detailed information about Android's box model. I mean how padding, margins, gravities, etc. they all interact together.
Other than this note about margin and padding in the dev site and this SO question there's not much information out there.
What I'm looking for:
What are the defaults for margins, paddings, gravities, etc.
Can manufacturers alter those defaults. If so, is it a good practice ignoring those defaults so your app looks consistent across different manufacturers?
How are conflicts resolved, specially between a component and its children.
Any difference between Android versions?
Is it really that simple that is not worth a deeper explanation in the docs?
Thanks,
Juan
Rather surprised that I haven't been able to found detailed information about Android's box model.
Note that little in your question has anything to do with LinearLayout, the Android equivalent of the "box model" found in XUL or Flex. Perhaps you have a different definition of "box model" than I use.
What are the defaults for margins, paddings, gravities, etc.
0 pixels for the default margin and padding. Default gravity varies by widget/container.
Can manufacturers alter those defaults.
Technically, yes, though I am not aware of this being done in practice.
How are conflicts resolved, specially between a component and its children.
There are no possible conflicts in margin, padding, or gravity.
Any difference between Android versions?
Not that I am aware of.
Is it really that simple that is not worth a deeper explanation in the docs?
IMHO, yes.
If you compare Android's box model to CSS's box model, I find Android's indeed easier to grasp, and of much lower complexity. You don't have those shenanigans like the padding getting added up to the element's width. IMHO, positioning logic (CSS: float/absolute/relative etc.) is very well and elegantly encapsulated in Android's layout components. While some things are hard to do in Android (like having a toolbar at the view's bottom and filling the rest with a list - but this also involves evil hackery in CSS), it's much more predictable than CSS.
I would suggest that you read up on all layout components, as the box model is straightforward (margin, padding, width, height), and most of positioning and alignment is layout-component-specific (e.g., "gravity" in LinearLayout, "layout_above/below/toLeftOf/toRightOf" in RelativeLayout,...).
BUT: I agree that a complete guide (+ good examples and analogies) on that topic would help novices to come to terms with Android layouts much quicker, since some in-depth info is only available as case-based code snippets (speaking only of the web, books surely do a better job).
As a side-note on the box-model: One "peculiarity" I have stumbled upon is that 9-patch-drawables which are set as a background to an element affect the element's padding. If the box-padding of the 9-patch is not 0, the element's padding is set accordingly, if not overridden. This really bit me in the butt once.
I am trying to make a fraction:
I am using this is a text view but it is not rendering very nicely:
"5"+'\u2044'+"9";
It does not turn the text into a nice fraction instead it sort of covers part of the numbers and squishes them together.
Any solutions or alternatives?
Try:
tv.setText(Html.fromHtml("<sup>5</sup>/<sub>9</sub>"));
Don't know if that will look good, but it's worth a shot. Otherwise, other than the single-glyph fractions like 1/2, I suspect you either will need to go without or render it yourself.