Collapsing and scrolling Views in a LinearLayout View - android-layout

I'm trying to create a very specific behavior in an Android layout containing two Fragments when the soft keyboard opens, as depicted below from left to right.
Fragment A is a form which requires soft keyboard input, and Fragment B is a photographic slideshow, and just serves as visual filler.
The blue outline represents the root View. Fragment A is a fixed height, and Fragment B fills the remaining vertical space. As the keyboard opens, Fragment B collapses until its height is 0, at which point fragment A becomes scrollable.
I've tried the following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/FragmentB"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/FragmentA"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
</LinearLayout>
In this view Fragment B remains at the same height when the soft keyboard opens and instead Fragment A collapses.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/FragmentB"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/FragmentA"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
And in this view Fragment B is constantly collapsed, and a gap remains at the bottom of the view below Fragment A.
How can I achieve the layout behavior I laid out in the diagram above?
Thanks!

I found a solution here:
Min height fill_parent and height wrap_content in ScrollView?
My resulting code is:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"> <!-- FillViewport ensures the scrollview doesn't wrap the content -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"> <!-- Layout weight 1 means the LinearLayout will at least fill the scrollview, or wrap content if too big -->
<FrameLayout
android:id="#+id/FragmentB"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/FragmentA"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>

Related

GridLayout with variable row height in Xamarin

I have a fairly simple Xamarin app with a primary interface that consists of two ImageViews, one overlayed on the other. The images are the same size, and I want them to expand to fill the screen. Except that I want the bottom 100 pixels (about) reserved for a banner ad.
Without the ad, I found this simple. I used a RelativeLayout, set the layout_height and layout_width to match_parent, put both images in it, and set layout_CenterInParent to true for both of them. It works great.
And then I went to put the banner in. I tried using a GridLayout with one column and two rows, putting the prior RelativeLayout inside the top cell and the banner inside the bottom cell. But unless I restrict the height of the RelativeLayout to a fixed height, it expands until the banner is invisible. And I don't want to restrict it to a fixed height, because I want to expand it to the full height minus the banner height.
I realize that there's a basic contradiction between filling a space and restricting the height, but I'm hoping that there's some solution for this.
In css, I can use heights like wh-100 to be the full window height minus 100 pixels. Is there anything similar in Xamarin? Failing that, is there any trick I can use to achieve what I'm trying to do?
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rowCount="2"
android:columnCount="1"
android:id="#+id/gridLayout1">
<RelativeLayout
android:minWidth="25px"
android:minHeight="25px"
android:id="#+id/relativeLayout1"
android:layout_width="wrap_content"
android:layout_height="400px"
android:layout_rowWeight="1"
android:background="#ffff44">
<ImageView
android:id="#+id/img1"
android:src="#drawable/img1"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ImageView
android:id="#+id/img2"
android:src="#drawable/img2"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
<RelativeLayout
android:minWidth="100px"
android:minHeight="100px"
android:layout_height="100px"
android:id="#+id/relativeLayout2"
android:layout_width="wrap_content"
android:background="#ccff44">
<ImageView
android:id="#+id/banner_placeholder"
android:src="#drawable/banner_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
Thanks for any help.
At first, if you use the GridLayout , you can set the control's height as the parent's - 100 in the xml. But you can use the row height to set the control's height such as:
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rowCount="2"
android:columnCount="1"
android:id="#+id/gridLayout1">
<RelativeLayout
android:minWidth="25px"
android:minHeight="25px"
android:id="#+id/relativeLayout1"
android:layout_width="wrap_content"
android:layout_height="400px"
android:layout_row="0"
android:layout_rowWeight="3"
android:background="#ffff44">
<ImageView
android:id="#+id/img1"
android:src="#drawable/img1"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ImageView
android:id="#+id/img2"
android:src="#drawable/img2"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
<RelativeLayout
android:minWidth="100px"
android:minHeight="100px"
android:layout_height="100px"
android:layout_row = "1"
android:layout_rowWeight="3"
android:id="#+id/relativeLayout2"
android:layout_width="wrap_content"
android:background="#ccff44">
<ImageView
android:id="#+id/banner_placeholder"
android:src="#drawable/banner_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
This will set the first RelativeLayout's height as 3/4 of the parent and the second as the 1/4.
If you still want to set the first RelativeLayout's height as parent's - 100, you can use the ConstraintLayout instead of the GridLayout. And you need to install the package named Xamarin.AndroidX.ConstraintLayout at first.
And then:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:id="#+id/layout1"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="100dp"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp" // in the ConstraintLayout the odp means use the rest area in the parent
app:layout_constraintBottom_toTopOf="#+id/layout1"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
In addition, the ConstraintLayout is the most using layout in the native android, it can design many effects which is hard for the other layouts to implement.

LinearLayout - Positioning Views

I have this layout.
<RelativeLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/numbers_root"
android:orientation="vertical"
android:gravity="top"
>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/numbersList"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="116dp"
android:clipToPadding="false"
tools:layout_height="100dp"
></ListView>
<ExpandableListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/subcategory_expandable"
>
</ExpandableListView>
</LinearLayout>
</RelativeLayout>
But the problem is that the ExpandableListView is always centered on screen despite gravity="top" in the parent Layout. What I want is to have it start exactly where the ListView ends. Any idea what might be causing this?
Should I use a scrollview instead of linearlayout?
Here is a screenshot to clarify:
I want the expandable listview to appear below the listview.
I think the issue is that you're paddingBottom="116dp" on the ListView is pushing the ExpandableListView down.

Android Material Design Toolbar and FAB Button crossing over

In the Google's Material Design specs they often shown the Floating Action Button lying over half the toolbar and have over the content.
http://www.google.com/design/spec/components/buttons-floating-action-button.html
But I have tried a few variations and there is still a gap between the toolbar and content, caused by the button.
<LinearLayout>
<include layout="#layout/toolbar" />
<include layout="#layout/fab_button" />
<ScrollView>
Content
</ScrollView>
</LinearLayout>
I have also tried placing both toolbar and FAB button in a FrameLayout and it also had the gap.
The FAB button code was taken from Google's samples, and I haven't had issues with having it overlap at the bottom of over a RecyclerView.
Is there a way to achieve this look shown in the Material Design Specs.
Add layout_anchor property in FAB and set it to Top View.
Make CoordinatorLayout as your root view, this would be best layout practice.
You can set FAB gravity using layout_anchorGravity attribute in FAB.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/viewA"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:background="#android:color/holo_blue_bright"
android:orientation="horizontal"/>
<LinearLayout
android:id="#+id/viewB"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.4"
android:background="#android:color/holo_green_light"
android:orientation="horizontal"/>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:src="#drawable/ic_done"
app:layout_anchor="#id/viewA"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
Check this out.
Hope this could help you.
Using Relative layout is the easiest to position a FAB in between 2 views. You can use elevation parameter for the fab to get it over the toolbar. Set the elevation of the FAB more that that of the toolbar.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp"
android:background="?attr/colorPrimary"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<ListView
android:id="#+id/listview"
android:layout_below="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.getbase.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/favorite"
android:layout_alignBottom="#+id/toolbar"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:elevation="8dp"
android:layout_marginBottom="-32dp"
fab:fab_icon="#drawable/ic_favorite_outline_white_24dp"
fab:fab_colorNormal="#color/accent"
fab:fab_size="mini"
/>
</RelativeLayout>

How do I load two fragments vertically in the same layout?

I am making an app for my university's SafeWalk program and I am trying to make an activity that will display a map fragment with a button bar below it with emergency call buttons. The problem I am running in to is that when I load the following layout file, only the map fragment is displayed, and not the buttons along the bottom.
Note: I am also using a navigation drawer in this layout so I have included that code in case it is conflicting.
I have tried changing the layout_width and layout_height values of the two parent FrameLayouts
and I only can obtain one of two results, a full page of map, or a full page of my buttons (stretched to the top). I can attach the layout for the CallButtonFragment if necessary, but it is a horizontal linear layout with the button bar style containing two buttons.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:orientation="vertical" >
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" >
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="#+id/content_frame" >
<fragment
android:id="#+id/titles"
android:name="edu.purdue.SafeWalk.CallButtonFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>
<!-- The navigation drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
Following the suggestion of Android-er-naut below, I have this result:
(It is an improvement, but the buttons need to be a bit larger and fit the width of the screen.)
How about this -
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" >
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" >
<fragment
android:id="#+id/titles"
android:name="edu.purdue.SafeWalk.CallButtonFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>

Scrollview doesn't scroll to the margin at the bottom

I have a simple layout as follows :
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#D23456" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#FFFFFF" >
<ImageView
android:layout_width="match_parent"
android:layout_height="800dp"
android:src="#drawable/ic_launcher" />
</LinearLayout>
</ScrollView>
The background of the scrollview is pink and linear layout inside has the android icon image with a height of 800dp (that doesnt fit to the screen) . What I'm expecting to see is that imageview floats in a background of pink with a margin of 10dp in every sides (top,bottom,left,right).But when I scroll to the bottom, the scrollview doesn't scroll to the margin, so the bottom of the scroll is the imageview not the pink margin.
How can I prevent this? This makes the user think the page hasn't ended yet and makes him want to scroll more.
I later found out that ,a similar situation has already been answered in the following thread https://stackoverflow.com/a/16885601/1474471 by #olefevre.
Adding an extra LinearLayout that surrounds the current LinearLayout with a padding and removing the inner LinearLayout's layout-margin solved the problem:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#D23456"
android:padding="10dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF" >
<ImageView
android:layout_width="match_parent"
android:layout_height="800dp"
android:src="#drawable/ic_launcher" />
</LinearLayout>
</LinearLayout>
</ScrollView>
The solution posted by #Mehmet Katircioglu works well, but you can solve the problem simply changing the android:layout_margin to android:padding, without none extra view. Like this:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#D23456"
android:padding="10dp" >
<!-- Your content (ImageView, buttons...) -->
<LinearLayout/>
use android:fillViewport="true" on the ScrollView may do it.
example in this thread.

Resources