I'm trying to assemble a layout that would be fairly easy to do with weights in that everything is either 1/2, 1/4 or 1/8 of its parent, but I've heard that doing nested weights is bad for loading/performance and that relative layouts are better.
To be honest, I don't like relative layouts. I understand how to arrange things right next to or on top of something I've already put down, but struggle to understand how to arrange things in a manner similar to how I would with weighting.
This is a rough drawing of how I would like my layout to look like with the measurements on the sides. I could easily do that left grouping (Header, Name, Image, Type, Rank/Tier) but I'm not sure how to arrange the other side especially in how to maintain the height of the description box so that the rest underneath doesn't move if the content of that box changes.
[Edit]* I will set it up to always be in landscape mode
You could have two RelativeLayouts. One for the left side, and one for the right side. That of course, would only work for landscape mode, in which case scrolling would be the only other option for portrait. So you can do
Landscape
<LinearLayout
android:layout_width=""
android:layout_height=""
android:orientation="horizontal" >
<RelativeLayout..> RelativeLayout/>
<RelativeLayout..> <RelativeLayout/>
<LinearLayout/>
Portrait
<LinearLayout
android:layout_width=""
android:layout_height=""
android:orientation="vertical" >
<RelativeLayout..> <RelativeLayout/>
<RelativeLayout..> <RelativeLayout/>
<LinearLayout/>
So you still have control where the views lie in each section, but they still stay in each side respectively.
Related
Related question. Answer: RelativeLayout can't do it. I'm asking how to do it anyway, with not just RL, or with something else.
General story: you have a complex layout that would be difficult to adjust, and along comes a request for something to be added, aligning with a nested view.
What is the best approach? A popup with a custom style? (not familiar with those yet)? Spending days changing the whole hierarchy to a single RelativeLayout? A custom Layout class as wrapper?
AbsoluteLayout (deprecated) or FrameLayout with programmatically changed LayoutParams or margins? (this I'd rather avoid, I prefer not to touch onMeasure, etc)
Simplified example (no relation to pic above):
LinearLayout defines relative heights of the elements. I don't know to do it with RelativeLayout.
anExpandableView is something to be animated as sliding from under someBar (here; full-width, but perhaps it may need to align its width, as well as vertical position).
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/topStuff"
layout="#layout/incl_topstuff"
android:layout_width="match_parent"
android:layout_weight="7"
android:layout_height="0dip" />
<include
android:id="#+id/someBar"
layout="#layout/incl_filters_and_stuff"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
android:id="#+id/bottomStuff"
layout="#layout/incl_bottomstuff"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="10" />
</LinearLayout>
<include
android:id="#+id/anExpandableView"
layout="#layout/incl_filters"
android:visibility="gone"
android:layout_below="#id/someBar"/>
</RelativeLayout>
I know SO has an aversion to general questions, but I don't want an ad-hoc solution. I am asking what to do in cases which would be solved if only a wrapping RelativeLayout would allow alignment to a view that is not a direct sibling.
Putting it simply, RelativeLayout can only measure and layout it's direct children based on each other, but I guess you already knew that.
The only general solution would be to implement your own custom Layout class, which I wouldn't recommend. If I had to guess why RelativeLayout does not traverse the entire layout hierarchy at it's level and below, it's probably for performance reasons.
Unfortunately if you're using RelativeLayouts and LinearLayouts and you want views to be dependent on each other you have to pick one approach and stick to it, either the flat hierarchy of RelativeLayout, or the nested one of LinearLayout.
Based on your example, as far as I know, there is no way to implement weighted views with a RelativeLayout, so you're stuck with using a LinearLayout.
The easiest way to do what you want is to inflate your expandableView in code, align it with the bottom of the RelativeLayout, set it's height and position based on bottomStuff, and animate from there.
If you really want to do it in xml, I can think of one somewhat hacky, ad-hoc approach, but which can can be generalized to mirroring the measurement and layout of any hierarchy with a bit of work.
Create a parallel but invisible LinearLayout that is a sibling of the first one. Give it an empty view with weight 7 on top, an invisible copy of someBar in the middle, then your expandable view under that with weight 10. To have it slide up, either animate the height of the invisible someBar and the weight of the empty view on top towards 0, or remove them/set them to gone and set animateLayoutChanges on your LinearLayout.
In my app I am calling API to get list of people with some informations (address, phone numbers etc.). Under every phone number, I am creating programatically 3 buttons (add to contacts, edit and call). Problem is, that last button is cut off (small screen). I am using Linear Layout horizontal.
Is there any way to control size of screen and if needed, put last button to second line? When I rotate screen to landscape, I have enough space, so buttons should stay in one line.
Now, I am using horizontalScrollView with visible scrollbar. It's working, but I am not very satisfied with it.
Thanks for help.
I'm not really sure if you can do that with LinearLayout. But you could do that using FlowLayout. Check this link: https://github.com/ultimate-deej/FlowLayout-for-Android.
This layout moves the buttons to the next line if there is no space for them on the screen.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weight="1" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weight="1" />
</LinearLayout>
the weight attribute will automatically adjust your button size
make sure you set width to match parent for all buttons.
Best to create a new variant of the listitem layout for smaller screenshots:
layout-w200dp/listitem.xml : layout with 3 buttons on one line
layout/listitem.xml : layout with buttons on separate lines
Android will then choose the multiline layout when the current available width is smaller than 200dp. (Note that you can still tweak the 200 to a different value)
Alternatively you can also use an alternatieve linearlayout which does the wrapping for you: Flowlayout
This is probably more complicated to achieve that you wan't it to be but the best shot is to use some adapter based solution:
GridView - this is the old solution, better go for the 2nd
RecyclerView with StaggeredLayoutManager setup to your needs
Simple solution is using android:layout_weight="1" and android:layout_width="0dp" as params for each button in your LinearLayout but then they will fit the whole screen and take the same percent of the width, and if the screen is too small buttons might get cut off.
I am using the Code from JawsWare - Overlay View to create a View that lays above everything.
This works fine, but I failed to adapt the given layout to my needs.
What I want: Two Phases.
First Phase: A button in the upper left corner that is always there above all other apps.
When this button is pressed, we enter the Second Phase:
The button is replaced by two images which are to be horizontally aligned at a certain distance from the top, again floating above everything else.
I have to admit that I dont really understand Android Layouting, but I've tried fiddling with a RelativeLayout and an ImageView but it seems buggy.
Additionally, I encountered a very strange behaviour: Even if the Image is only about 200x200 px in the upper left corner, nearly the whole screen is "blocked" by the View (it receives all TouchEvents, even though there shouldt be anything). It seems that if I position the Layout using Margins to float in the middle of the screen, everything to the left and top of the visible button is also receiving touch events and not letting them pass through to the underlying app (even though there is no visible content).
Any ideas to why this happens and how to circumvent that?
Secondly: How can I achieve the two layouts from earlier?
Edit 1: My Layout. (please keep in mind that I just copied this and then did what I thought was right)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:onClick="overlayTextClicked"
android:padding="0dp"
android:id="#+id/overlay_layout_id"
>
<ImageView
android:id="#+id/imageview_info"
android:layout_width="200px"
android:layout_height="200px"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"
android:src="#drawable/picture_010512233437384578"
android:contentDescription=""/>
<TextView
android:id="#+id/textview_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:text="info"
android:textColor="#FFF"
android:orientation="vertical"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
Afterwards I am trying to set the RelativeLayouts Gravity to TOP | CENTER_VERTICAL with a Top-Margin of 200px.
I believe what's going on here is your TextView is filling out the entire screen.
wrap_content bounds the size of a View with its content. match_parent fills a view to as big as it can get (i.e., whatever size the container is bound to).
So in this case, your RelativeLayout is does not have a max size it's bound to. Your TextView is going to try to get as big as it can get, so it's going to fill the screen. Likewise, the RelativeLayout is going to blow up to that size to wrap around the TextView.
Also, RelativeLayout doesn't really respond to Gravity well. That is used in LinearLayout and FrameLayout containers a lot, but RelativeLayout relational rules like "CENTER_IN_PARENT" are going to override whatever Gravity you set (if you set Gravity.RIGHT and "CENTER_IN_PARENT", then one has to win out I guess).
When I use a linear layout I am unable to graphically move any elements around in the WYSIWYG editor. If I set them to relative I can, but I the reasoning doesn't make sense to me. After reading up I am under the impression linear is somewhat like absolute positioning. Shouldn't dragging objects be possible?
<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:background="#400080"
tools:context="com.x.EntranceActivity" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/mobile_full_logo" />
</LinearLayout>
Yes you can't visually move elements inside LinearLayout.
LinearLayout can hold all elements in vertical orientation or horizontal orientation, so there is no need for dragging elements somewhere else.
But you can set android:layout_gravity and android:gravity attribures for elements to position them in right way as you want.
From the docs:
A Layout that arranges its children in a single column or a single row. The direction of the row can be set by calling setOrientation().
You can tweak things like gravity, padding, and weight, but there is no way to set absolute positions. As such, dragging them around in the WYSIWYG editor is disabled.
Sorry for the extremely bad title, I have no other idea what to call this question. What I'm trying to do is this: have a RelativeLayout which has two children:
one with layout_centerInParent="true"
one with layout_alignParentBottom="true"
However, when the device is in landscape mode, element (1) appears slightly over or under element (2). But, element (1) has enough space above it to appear above element (2). How could I make the layout so that if the screen is too small to center element (1) and make both elements not overlap, then align element (1) above (as in layout_above) element (2)?
This should work to give you a layout where the text1 item fills the available space above text2, and is centered vertically and horizontally in that space; and text2 is on the bottom, centered horizontally.
<LinearLayout
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<TextView
android:id="#android:id/text1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Centered"
android:gravity="center_vertical|center_horizontal"
/>
<TextView
android:id="#android:id/text2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Bottom"
android:gravity="center_horizontal"
/>
</LinearLayout>
The important parts are android:layout_weight, combined with android:gravity.
Alright here's a leftfield suggestion that might work if your element (1) isn't too resource intensive.
Have two versions of element (1), the first with layout_centerInParent="true" and the second with layout_above="#id\element2". Default them both to android:visibility="invisible". In your onCreate Post a Runnable that inspects the Y dimension of both elements, and sets View.VISIBLE on the element with the smallest value.
New idea:
This is another idea that's sort of a workaround in that it's not very elegant, but it's very simple. Put element (1) in its own < LinearLayout > configured like so:
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" // More on this line below
android:layout_alignParentTop="true"
android:layout_above="#id/element2"
android:gravity="center">
That linear layout will always span from the top of screen to just above element (2), and since its gravity is "center", element (1) will always be in the middle of whatever space is available for it. Note: The line android:layout_height="..." is required, but doesn't seem to actually do anything. Whether it's fill_parent or wrap_content, its height is overridden by the lines anchoring its top to the ParentTop and its bottom to element(2). However, not having the line makes it crash with a Runtime exception.
Original, not very good idea:
Another less-than-ideal solution is to use two layout files. Put the portrait layout xml in your layout folder and the landscape layout in a new folder called layout-land. Android then automatically selects the right one based on the orientation of the phone. I think you could use layout-port, but putting the portrait one in just layout makes sure it knows which one to use by default.