I'm trying to understand Android's View structure and I'm a little confused on how to position child views
Let's say I have a FrameLayout that will contain my custom view. My custom view only draws a rectangle 50x50 px.
So I set my View.setMeasureDimension(50, 50);
Now how should I move this view? I found a couple of ways of doing it.
1: I could do something like canvas.drawRect(new Rect(offsetX, offsetY, right, bottom)); but this will make my View larger and thereby my measureWidth / height are not valid any longer?
2: Set padding on the parent element, and thereby affect the left / top View.getLeft() / View.getTop(). But this will affect all child elements.
3: Use View.offsetLeftAndRight( number of pixels to move ). I do not quite understand what this actually does. Does it cause some kind of canvas.translate() ? But this way I need to keep the state on how many times I called offsetLeftANdRight() because calling offsetLeftANdRight(10) and then offsetLeftANdRight(10) will move it 20px.
I'm a bit confused on what way is the "correct" way of doing it. Is there a better way?
Android apps run on devices of different sizes, with often completely different screens. Because of that you shouldn't be using any absolute positioning or sizing. Wherever possible create views and position them relative to each other.
You need to become familiar with the various views Android provides to create layouts:
http://developer.android.com/guide/topics/ui/layout-objects.html
It sometimes takes a lot of thought as items will be positioned differently on different devices (and orientations) so the view relationships are more important than absolute positions.
LinearLayout is a good all-purpose container for placing controls, though RelativeLayout is often more efficient (if a bit harder to use sometimes)
Once items are positioned relative to each other you can use padding and margins to tweak their positions.
Related
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.
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.
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.
I'm a bit amazed that absolute layout is deprecated. I understand using this is not very flexible and can cause problems with dynamic screen layout. Also I've found alternatives where one uses RelativeLayout and emulate the x & y using margin offsets, but that seems like total bollocks, because it still has fixed x & y values.
Anyhow, what I'm doing ATM is writing a Gallery replacement (because that is deprecated as well), which adds the missing view reuse. Unfortunately I wasn't able to get EcoGallery to behave nicely - scrolling was totally off on a tablet.
The replacement Gallery uses HorizontalScrollView with an AbsoluteLayout inside. Using the scroll position and the width of the HSV it is easy to calculate which child views are visible in the AL (given the fixed child width I'm using).
So the AbsoluteLayout only has those child views that are actually visible and they are positions to match the scroll. It seems to me this is a very valid use case for AbsoluteLayout. Or am I missing something and is this going to break?
I am trying to write a calendar app and I plan to have a grid (week view) which will probably be a TableLayout and directly on top of that I will have to absolutely position events on the grid.
But AbsoluteLayout is deprecated. What should I use instead?
Events may overlap and I think it would be really silly to try and use a non absolute layout to achieve what I want.
Maybe I should use RelativeLayout with a margin left and margin top on each of the child nodes. Seems odd to do it that way and might not be as efficient. Is this the best way or is there an alternative?
But AbsoluteLayout is deprecated. What should I use instead?
Write your own layout manager that implements the rules you want.
CommonsWare suggested writing my own layout manager and Christian pointed out it sounds easier than it is.
Yahel suggested SurfaceView/OpenGl and draw whatever I want.
I found out you can recreate absolute positioning by adding your child views to a RelativeLayout and set the RelativeLayout.LayoutParams to have only default values except width, height, marginTop and marginLeft. The top and left margin will be similar to top and left in AbsoluteLayout. Also, negative margins are supported.
Make sure you account for screen density and width and orientation changes and all the other caveats of absolute positioning that used to apply to AbsoluteLayout
If you have problems with getting your content to overflow past the right edge of the screen, try supplementing your positive left margin with an equally negative right margin. (original question)
I would suggest either going the easy way :
Setting your calendar for 15(or 30) minutes intervals, this way you don't need absolute positionning. A table view filled with linear view each representing 15 minutes interval and fill these with events.
Or going the hard but a lot more stable/speedy/customisable way :
SurfaceView/OpenGl draw your own however you want.
The problem with number 1 is the fact that the more you add elements in your view hierachy the more your app will take a performance hit. Say a conventional month you have 3 appointments a day, your hierarchy will be filled with a hundred views wich will be very long to render and heavy memory-wise too.
The problem with number 2 : Well it's a lot harder to code at first. If you have to write your own layoutmanager, don't, go surfaceview or openGL.