Android: an easy way to alternate UI elements in one place - android

There is a dialogue, in one place of which I need to show either one element or another, depending on the situation. Example:
I would like to do this so that the elements below do not move. I want to keep the area occupied by alternating elements of a constant size.
What is the easiest way to do this?
I can, of course, manually change the visibility. Вut when switching, if there is a different height, then the underlying elements will jump. I can manually set their height equal, but this is inconvenient. It will be necessary to correct the heights of all alternating elements every time after I change one of them.
For example, Qt has Stack Layout that allows you to alternate elements and takes the size of the largest of them. Does Android have something like this?

You might be able to use the ViewSwitcher to hold the two layouts.
It holds 2 different child views and measures its height to the biggest child by default.
Here's the documentation for it: https://developer.android.com/reference/android/widget/ViewSwitcher

Just an idea if you can't find something like Stack Layout. I haven't tried it.
You can put all the elements in an horizontal LinearLayout with MATCH_PARENT width for the visible one and 0 for the invisible ones, but keeping all of them VISIBLE. It should always have the largest height and only the MATCH_PARENT width element should actually be visible.

Related

How does fill_parent in Android actually work under the hood?

I see great value in fill_parent, and I'd like to make my own implementation of it so I can do more than just fill the remaining space (ex: fill 80% of the remaining space, etc.)
How does fill_parent actually work under the hood? As in how does it compute the space remaining, how does it work at runtime, etc.
I've done similar things to fill_parent in the past where I calculate the space an element should take up based on the current screen size, how much of the screen the element should take up, etc. but I want to know specifically how Android does it with fill_parent.
Try creating a custom View or ViewGroup and you will find out.
There's 3 stages on bringing a View to your screen:
measure
layout
draw
In measure the parent tells the child how much space is available. It may do that in respect to the childs layout parameters. So if the child says match_parent (fill_parent is deprecated) the parent will pass in either its own size, or the remaining space (most of the time...)
The child then takes the available size, calls setMeasuredDimenstion(allTheSpaceIGot) and that's measuring for you.
Next up during layout, the parent checks the childrens measured sizes. It then sets the childrens bounds (top, left, bottom, right) accordingly.
Finally in onDraw every child draws itself within its bounds.
To sum this up:
Child gives parent information about its wishes.
Parent offers child some available space.
Child says "I'll take it".
Parent gives child its final restraints
Child draws itself within the constraints
If you want to assign say 60% to a view you should have a look at creating a custom ViewGroup (since that is who actually decides on the childs dimensions)
I also wrote a blog post about custom views that goes into more detail, followed by how to create a custom layout.
The entire source code for Android is open source, freely available within a few clicks on Google, so you can read it and study it all you want.
But just a fair warning, it's definitely no small task you're trying to accomplish, as there are an enormous amount of cases you have to account for.
If you want a layout to take X percent of available height/width, take a look at PercentageRelativeLayout
Just FYI: 'fill_parent' is deprecated, use 'match_parent' instead. They literally do the exact same thing, it's simply a different word.

Does programmatically setting layout sizes actually save on performance?

So whenever I try to use layout_weights within each other to achieve the layouts I want, Android Studio helpfully tells me that nested weights are bad for performance. Various answers here on SO say that it's okay to nest them for a couple layers of deep, but don't overdo it. I'm not sure how deep is too deep, o what I'm trying instead is doing something like this:
//get pix size of device screen
int[] dimens = ImageUtils.getScreenDimensions(getWindowManager());
//programmatically set height of my two sections to the percentages that I want
upper.getLayoutParams().height = (int) (dimens[1]*0.8);
lower.getLayoutParams().height = (int) (dimens[1]*0.2);
// do the same thing for the left and right sections of our upper block
upperLeft.getLayoutParams().width = (int) (dimens[0] * 0.5);
upperRight.getLayoutParams().width = (int) (dimens[0] * 0.3);
...so on and so forth
And I mean, it works. I get some nice percentage-based layouts. My question is though, does that actually help with performance at all? Or am I just doing the same thing in a more complicated and fancy fashion?
Edit: adding desired layout. I guess I could use a grid layout if necessary? Or would just plain old percentages work?
"Nested Layouts" implies that Android does not know how big each layout should be without iterating over each layout setting to determine if the size should be changed based on other layouts.
This means that "nesting" could result in many iterations of trying to size each layout, then trying to figure out if child layouts change based on changes to parent layouts and sibling layouts.
If you can determine the size of a layout programmatically (which it seems you can do), then the LayoutManager will use the sizes that you dictate and not try to layout the screen and then check to see whether the layouts have been sized properly.
That said, it might not really matter if you only have a dozen or so layouts. The performance hit happens when several dozens of layouts (or more) need to be measured. That is why a lot of comments on SO say that it doesn't really matter - most times, a few dozen layouts are all that are present on the screen. (HINT: if you have a ListView or GridView or something that requires an indeterminate number of layouts be used; then nesting matters and recycling views matter)
If these layout weights aren't going to change dynamically, you are better off defining them in the XML layouts. Not only will your intention be clearer, but Android does perform optimizations when inflating your layouts.

How to create a regular, resizable grid without nested weights?

I've one of the simplest layouts imaginable: A num pad.
I want to create a fragment containing a 3 x 4 grid of buttons. The layout should automatically resize the num pad to fill the available space.
I've learned, that GridLayout is not up to the task, and TableLayout/TableRow or nesting LinearLayouts means nesting weights, which is also discouraged for performance reasons. A RelativeLayout won't work either, because that requires at least one button with given dimensions.
So, is there a clean way to create a regular grid that will resize to fill its parent?
Any help is appreciated, thx!
You will need a custom compound control.
Check the following link:
http://developer.android.com/guide/topics/ui/custom-components.html#compound
Make the control fill the available space. Make it to have 12 buttons. Calculate the size and position of them based on their position and the available space.
Depending on your needs you might also need to override onMeasure() and onLayout() defined earlier in the above document, in the "Fully Customized Components" section.

Full-screen tabular layout

I have 12 basically identical views which I want to arrange in a grid that covers the whole screen. Depending on the device's orientation, I want to use a 3x4 or a 4x3 grid.
As far as I understand, there are basically three approaches to this topic:
Use a GridView
Use nested LinearLayout instances
Use a TableLayout
I'd like to have a layout that
automatically adapts to orientation changes (as GridView does)
uses all available screen space (as nested LinearLayout instances do)
doesn't allow scrolling (and without that "can't scroll any further" effect of the GridView)
allows me to force the same size on all of my items
By default, GridView has scrolling and doesn't fill the screen, whereas LinearLayout and TableLayout don't automatically adapt to orientation changes.
Currently I'm using a GridView with disabled scrolling and a custom adapter which sets the item views' minimum height depending on the orientation and the container's height to force a filled screen. This works but feels like a really ugly hack.
Dynamically constructing nested LinearLayout instances depending on the orientation would probably also work, although I haven't tried that.
This seems to be a frequent goal (1, 2, 3, 4), but all the suggested solutions are either as hackish as mine or don't satisfy some of my requirements.
As I'm new to Android development I'm not sure whether I'm missing something.
What is the optimal way of implementing this?
I'm targeting API level 8 and above.
Use a GridView
A GridView is a widget that you would use when you want to show data in a grid like manner with a larger set of data(as the GridView's recycling mechanism would provide a greater performance than a normal built hierarchy). This is not your case as you want all the views visible from the start and from my point of view the overhead of a GridView isn't simply worth it.
Use nested LinearLayout instances
A good option but avoid nested weights. You could use instead two LinearLayout with weights on the longest direction(vertical for portrait and horizontal for landscape) placed in a RelativeLayout with a centered anchor view.
Use a TableLayout
Another option. Use the stretchColumns option for the width and weight on the TableRows for the height.
Depending on the device's orientation, I want to use a 3x4 or a 4x3
grid. What is the optimal way of implementing this?
There isn't an optimal way, either of the solutions above could be used, you could also make your own layout.

Two-pass UI Layout : Why?

I've noticed that Android, WPF, and Silverlight all follow a two-pass layout pattern. There's a recursive Measure() method that gets called to size the element, possibly multiple times. Then a recursive Layout/Arrange() method is called which lays out the exact positions of children in their parent control, and will also set the final size of the control.
My question: why is this split into two passes, especially when, for some types of controls, Measure() can't compute the actual size of a control without actually laying out the positions of the children? Is there some type of layout minority case that is made possible by this?
I'm trying to create my own UI toolkit, and I'm currently leaning toward a one-pass Layout() pattern, but I'd like to be convinced whether this is wise or not.
Thanks for reading this :)
Sean
The reason for the two passes is that any element in the structure can influence the remaining available space of the others.
Some element wish to take the largest possible space while others have fixed dimensions. You can also have elements with only a max width set. It creates an equation that can not be solved in one pass.
The different panels in the hierarchy ask the elements what size they need in the first pass, then distribute the space among them according to each panel's nature, and finally informs each element of its allocated space.
EDIT: Some more explanations
The main drawback of a single pass layout is that you are handling each element sequentially. A first element takes a certain amount of space and the others take the rest. Why is this element the first? Try your algorithm with different element order, and you will have different resulting layouts.
A two pass layout simulates a parallel behavior where each element influences the whole layout.

Categories

Resources