Can we place a small view over another large view? For example, I have a VideoView which is playing a file in the background. Over this, somewhere in the middle/corner, I want to place another ImageView.
But in Linear/Relative Layout, views can be placed only one after another or relative to each other, and AbsoluteLayout is advised against. So what do I do?
The FrameLayout is the simplest ViewGroup and stacks the Views in the order they're defined in layout XML (or added programmatically); the first will be lower, and the last will be on top.
Here is an example where two Views are stacked and offset to better illustrate the point:
Here is the actual layout XML with the two overlapping TextView boxes. The offset of the two boxes is done using android:layout_gravity while android:gravity is used for centering the text itself within each box.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp">
<TextView
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="top|left"
android:background="#android:color/holo_blue_light"
android:gravity="center"
android:text="First is below"/>
<TextView
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="bottom|right"
android:background="#android:color/holo_green_light"
android:gravity="center"
android:text=" Last is on top"/>
</FrameLayout>
Just in case if you want to place a view on top of a ButtonView then use this;
android:elevation="7dp" for the view which needs to be placed on top of the button.
FrameLayouts let you pile each view on top of the one below. This can also be achieved with a RelativeLayout.
You can also do it by using ConstraintLayout a new layout introduced by google.
ConstraintLayout allows you to create large and complex layouts with a flat view hierarchy (no nested view groups).
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="4"
tools:context="com.edalat.example.MainActivity">
<VideoView
android:id="#+id/videoView"
android:layout_width="283dp"
android:layout_height="349dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="24dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="24dp"
android:layout_marginRight="24dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="24dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.509"/>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#mipmap/ic_launcher"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="24dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="24dp"
android:layout_marginLeft="24dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="24dp"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/dp_20"
android:background="#color/yellow"
>
<VideoView
android:id="#+id/videoview"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:layout_height="300dp"
android:contentDescription="#string/app_name"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/camera"
android:layout_margin="30dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:id="#+id/imageView" />
</RelativeLayout>
Create Relative Layout and place views inside it and add
android:elevation="2dp"
for the view whcich is to be over another one
It can be done easily by putting the back layouts before forwarded layouts in XML file.
for example if I want to cardView1 comes over cardView2 I write this code:
<androidx.cardview.widget.CardView
android:id="#+id/cardView2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/cardView1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
Since cardView2 comes before cardView1 , cardView1 is the one that comes over the other one.
Related
I have following xml code from youtube:
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".MainActivity">
<androidx.cardview.widget.CardView
android:layout_width="300dp"
android:layout_height="300dp"
app:cardElevation="10dp"
app:cardCornerRadius="20dp"
app:cardBackgroundColor="#color/white"
tools:ignore="MissingConstraints">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_height="150dp"
android:layout_width="match_parent"
android:src="#drawable/sandwich"
android:id="#+id/sandwich"
android:scaleType="centerCrop"
tools:ignore="MissingConstraints" />
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Welcome"
android:textAlignment="center" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
Why we need the LinearLayout that inside the Card component? Can we just inside the Card use ImageView and Text component alone.
CardView is basically a styled FrameLayout source code, thus it doesn't support placing multiple views inside it, unless you want to stack them on each other. So to get around that, you can place a layout that supports multiple views and use it to manage the placement. It doesn't have to be LinearLayout, you can use any available Layout out there.
you have to use another layout in cardview to define background color or image. because cardview doesn't have background feature
I have a small view, which at the beginning only contains a loading indicator, which is why it is relatively small. However, when the actual content is loaded, I would like to display that instead of the loading indicator, for which I add 2 text fields and an ImageView. Currently I just do this by hiding the ProgressBar and showing the elements I just mentioned, but this way there is a hard cut between the two states. I would like to change this so that first the height of the view is adjusted over a short period of time, and then the content is shown (maby faded in, but I'm more concerned about changing the height).
In general I already have some ideas how to do this, but I don't know how to calculate the new height? Is there a way to calculate it, or even a function directly from Android that solves my Problem?
Thanks already :)^
Heres the Layout for the Fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="#+id/home_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".viewables.fragments.home.HomeFragment">
<ListView
android:id="#+id/home_vertretungsplan_preview"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/vertretungsplan_list_item"/>
<include
android:animateLayoutChanges="true"
android:layout_weight="0"
android:id="#+id/home_article_preview"
layout="#layout/thomsline_main_recyclerview_article"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
</LinearLayout>
and here ist the Included Layout
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:animateLayoutChanges="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:clickable="true"
android:focusable="true"
app:cardElevation="10dp"
app:cardCornerRadius="20dp"
app:cardPreventCornerOverlap="false">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/thomsline_post_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="0dp"
android:adjustViewBounds="true"
android:padding="0dp"
android:scaleType="centerCrop"
android:src="#drawable/img_thomsline_article_image_default"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:id="#+id/container1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/thomsline_post_image"
app:layout_constraintLeft_toLeftOf="parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="19sp"
android:id="#+id/thomsline_post_title"
tools:text="Article Title"/>
<TextView
android:id="#+id/thomsline_post_excerpt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textAllCaps="false"
android:textSize="12.5sp"
tools:text="Post Excerpt" />
</LinearLayout>
<ProgressBar
android:id="#+id/thomsline_post_loading_indicator"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
You can try using animateLayoutChanges attribute in your parent layout.
Add this line to your root element of your activity layout :
android:animateLayoutChanges="true"
Or you can use TransitionManager for smooth transitions. (API 19+)
Add this code to your file just before the line where you set your content :
TransitionManager.beginDelayedTransition(cardView); //Default transition
You can pass your preferred transition to this function like this :
Transition transition = new ChangeBounds();
TransitionManager.beginDelayedTransition(cardView,transition);
You can choose any transition :
ChangeBounds
Explode
Slide
Fade
AutoTransition
TransitionSet
If you want to know more about animations in android, i would suggest u read this : Simple Animations in Android
For the sake of simplicity, let's say I've got two text views A and B. A is a set size with a set margin between it and the parent. B is a variable size.
The goal is to position B centered below A if it fits but not have B go off the screen.
Here's the xml I've currently got for the two elements:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/element_A"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="elem_A"/>
<TextView
android:id="#+id/element_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="#id/element_A"
app:layout_constraintEnd_toEndOf="#id/element_A"
app:layout_constraintTop_toBottomOf="#id/element_A"
android:text="sml"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The image below shows three figures: left is what I'm seeing when element B is small enough (great), middle is what I'm seeing when element B is too big (not good), and right is what I want to see when element B is too big.
As it turns out, switching from ConstraintLayout to LinearLayout actually fixes this problem. I'm still curious if this is possible using ConstraintLayout but for now I'll just use LinearLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_gravity="end"
tools:context=".MainActivity">
<TextView
android:id="#+id/element_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="end"
android:layout_weight="1"
android:text="elem_A"/>
<TextView
android:id="#+id/element_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="1"
android:text="much much longer element B"/>
</LinearLayout>
First create LinearLayout and set orientation to horizontal And again you need to create child LinearLayout and wrap both text feilds into it and set it's layout_gravity to right also set orientation to vertical. After that you need to distribute weight of LinearLayout into both of text feilds equally and also set gravity and layout_gravity to center for both text feilds . Tip :- don't use hard-coded values,instead use match_parent / wrap_content for all elements.
I have made changes to your code, cop-paste all code to your xml file...
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/element_A"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="32dp"
android:text="elem_A"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="#+id/element_B"
app:layout_constraintStart_toStartOf="#+id/element_B"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/element_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:text="sml"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
tools:layout_editor_absoluteY="88dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
A bit of context: I am trying to implement a SearchView, when onQueryTextChange is called, it displays a ProgressBar, and when the query is done it hides the progress bar and displays another view depending on the outcome of the query. If the query returns nothing, it makes a textview visible saying "No Results" and if there is data, it populates the recyclerView.
My question is, what is the correct way of implementing this?
Do I stack them all on top of each other and make each one visible/invisible depending on the outcome of the query? Or do I use a viewflipper to display a fragment for no result and a fragment containing a recyclerview? Or lastly there is another way I do not know of?
This is what my search fragment looks like:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
android:fitsSystemWindows="true"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="#color/colorWhite">
<android.support.v7.widget.SearchView
android:id="#+id/fragsearch_searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:queryBackground="#android:color/transparent"
app:queryHint="Search"
app:iconifiedByDefault="false"
android:background="#color/backgroundColor"/>
<View
android:id="#+id/fragsearch_divider1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/dividerColor"
android:layout_below="#+id/fragsearch_searchView"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/fragsearch_recycler"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorWhite"
android:layout_below="#+id/fragsearch_divider1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragsearch_progress_layout"
android:background="#color/colorWhite"
android:visibility="invisible"
android:layout_below="#+id/fragsearch_divider1"
android:gravity="center">
<ProgressBar
android:id="#+id/fragsearch_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="#+id/fragsearch_textview_noresults"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/fragsearch_divider1"
android:padding="12dp"
android:text="No Results Found"
android:visibility="invisible"/>
</RelativeLayout>
Right now I'm just stacking all of them on top of each other and changing the visibility on each one. Is there a better way of doing this?
I like to use a ViewFlipper for this. This way you can encapsulate the various view states in separate layouts and verify at design time that the correct layout is displayed. Much nicer than setting visibility on different Views.
<ViewFlipper>
<ViewGroup1>
</ViewGroup1>
<ViewGroup2>
</ViewGroup2>
</ViewFlipper>
To switch between the different children of a ViewFlipper call setDisplayedChild(index),
FrameLayout is used for this purpose.It is very useful for arranging views on top of each other.In your case replace RelativeLayout with FrameLayout.
I have done it using Constraintlayout considering searchview inside toolbar:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/padding_8dp">
<ProgressBar
android:id="#+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="#+id/recycler_company_details"/>
<TextView
android:id="#+id/txt_empty_data"
android:text="No data available!!"
android:layout_width="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#android:color/holo_red_dark"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
Consider using framelayout for this purpose, also we can easily set children layout gravity, it gets rendered perfectly. Relativelayout could also help, but we should avoid views termed as 'Legacy'.
What I want to achieve is that I want to place a View "above" the center of its parent layout. consider the image below:
The blue rectangle it where I want my View to be. as you can see it is exactly above the (vertical)center of the screen.
The challenge is that we don't know the height of the view (so I can't use a bottom margin for it) and I want to do it in layout xml file (so I can't use code to determine the height of the view and set it a margin programmatically)
with these restrictions, is there any way to do this?
You can follow the following layout to place your view at the desired location-
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<View android:id="#+id/dummy_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerInParent="true"
/>
<View
android:id="#+id/your_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_above="#+id/dummy_view"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
I recommend you to use ConstraintLayout, it can be done using guidelines easily (instead of using a View as the anchor point):
XML example:
<android.support.constraint.ConstraintLayout
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"
>
<android.support.constraint.Guideline
android:id="#+id/mid_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"
/>
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#F00"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/mid_guideline"
/>
</android.support.constraint.ConstraintLayout>