How to bring view in front of everything? - android

I have activity and a lot of widgets on it, some of them have animations and because of the animations some of the widgets are moving (translating) one over another. For example the text view is moving over some buttons . . .
Now the thing is I want the buttons to be always on the front. And when the textview is moving I want to move behind the buttons.
I can not achieve this I tried everything I know, and "bringToFront()" definitelly doesn't work.
note I do not want to control the z-order by the order of placing element to layout cause I simply can't :), the layout is complex and I can not place all the buttons at the begging of the layout

You can call bringToFront() on the view you want to get in the front
This is an example:
yourView.bringToFront();

With this code in xml
android:translationZ="90dp"

I've been looking through stack overflow to find a good answer and when i couldn't find one i went looking through the docs.
no one seems to have stumbled on this simple answer yet:
ViewCompat.setTranslationZ(view, translationZ);
default translation z is 0.0

An even simpler solution is to edit the XML of the activity. Use
android:translationZ=""

bringToFront() is the right way, but, NOTE that you must call bringToFront() and invalidate() method on highest-level view (under your root view), for e.g.:
Your view's hierarchy is:
-RelativeLayout
|--LinearLayout1
|------Button1
|------Button2
|------Button3
|--ImageView
|--LinearLayout2
|------Button4
|------Button5
|------Button6
So, when you animate back your buttons (1->6), your buttons will under (below) the ImageView. To bring it over (above) the ImageView you must call bringToFront() and invalidate() method on your LinearLayouts. Then it will work :)
**NOTE: Remember to set android:clipChildren="false" for your root layout or animate-view's gradparent_layout. Let's take a look at my real code:
.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:hw="http://schemas.android.com/apk/res-auto"
android:id="#+id/layout_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/common_theme_color"
android:orientation="vertical" >
<com.binh.helloworld.customviews.HWActionBar
android:id="#+id/action_bar"
android:layout_width="match_parent"
android:layout_height="#dimen/dimen_actionbar_height"
android:layout_alignParentTop="true"
hw:titleText="#string/app_name" >
</com.binh.helloworld.customviews.HWActionBar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/action_bar"
android:clipChildren="false" >
<LinearLayout
android:id="#+id/layout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:gravity="center_horizontal"
android:orientation="horizontal" >
</LinearLayout>
<ImageView
android:id="#+id/imgv_main"
android:layout_width="#dimen/common_imgv_height"
android:layout_height="#dimen/common_imgv_height"
android:layout_centerInParent="true"
android:contentDescription="#string/app_name"
android:src="#drawable/ic_launcher" />
<LinearLayout
android:id="#+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:orientation="horizontal" >
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
Some code in .java
private LinearLayout layoutTop, layoutBottom;
...
layoutTop = (LinearLayout) rootView.findViewById(R.id.layout_top);
layoutBottom = (LinearLayout) rootView.findViewById(R.id.layout_bottom);
...
//when animate back
//dragedView is my layoutTop's child view (i added programmatically) (like buttons in above example)
dragedView.setVisibility(View.GONE);
layoutTop.bringToFront();
layoutTop.invalidate();
dragedView.startAnimation(animation); // TranslateAnimation
dragedView.setVisibility(View.VISIBLE);
GLuck!

Try FrameLayout, it gives you the possibility to put views one above another. You can create two LinearLayouts: one with the background views, and one with foreground views, and combine them using the FrameLayout. Hope this helps.

If you are using ConstraintLayout, just put the element after the other elements to make it on front than the others

i have faced the same problem.
the following solution have worked for me.
FrameLayout glFrame=(FrameLayout) findViewById(R.id.animatedView);
glFrame.addView(yourView);
glFrame.bringToFront();
glFrame.invalidate();
2nd solution is by using xml adding this attribute to the view xml
android:translationZ=""

You can try to use the bringChildToFront, you can check if this documentation is helpful in the Android Developers page.

There can be another way which saves the day. Just init a new Dialog with desired layout and just show it. I need it for showing a loadingView over a DialogFragment and this was the only way I succeed.
Dialog topDialog = new Dialog(this, android.R.style.Theme_Translucent_NoTitleBar);
topDialog.setContentView(R.layout.dialog_top);
topDialog.show();
bringToFront() might not work in some cases like mine. But content of dialog_top layout must override anything on the ui layer. But anyway, this is an ugly workaround.

You can use BindingAdapter like this:
#BindingAdapter("bringToFront")
public static void bringToFront(View view, Boolean flag) {
if (flag) {
view.bringToFront();
}
}
<ImageView
...
app:bringToFront="#{true}"/>

The order of the overlapping views really depends of 4 things:
The attribute android:elevation which is measured in dp/sp
The attribute android:translationZ which is also measured in dp/sp.
In Constraint Layout, the order in which you put the views in your Component Tree is also the order to be shown.
The programmatically order that you set through methods like view.bringToFront() in your kotlin/java code.
The numerals 1 and 2 compite with each other and take preference over the points 3 and 4: if you set elevation="4dp" for View 1 and translationZ="2dp" for View 2, View 1 will always be on top regardless of the numerals 3 and 4.

Thanks to Stack user over this explanation, I've got this working even on Android 4.1.1
((View)myView.getParent()).requestLayout();
myView.bringToFront();
On my dynamic use, for example, I did
public void onMyClick(View v)
{
((View)v.getParent()).requestLayout();
v.bringToFront();
}
And Bamm !

You can use elevation attribute if your minimum api level is 21. And you can reorder view to the bottom of other views to bring it to front. But if elevation of other views is higher, they will be on top of your view.

If you are using a LinearLayout you should call myView.bringToFront() and after you should call parentView.requestLayout() and parentView.invalidate() to force the parent to redraw with the new child order.

Arrange them in the order you wants to show. Suppose, you wanna show view 1 on top of view 2. Then write view 2 code then write view 1 code. If you cant does this ordering, then call bringToFront() to the root view of the layout you wants to bring in front.

Try to use app:srcCompat instead of android:src

You need to use framelayout. And the better way to do this is to make the view invisible when thay are not require. Also you need to set the position for each and every view,So that they will move according to there corresponding position

You can set visibility to false of other views.
view1.setVisibility(View.GONE);
view2.setVisibility(View.GONE);
...
or
view1.setVisibility(View.INVISIBLE);
view2.setVisibility(View.INVISIBLE);
...
and set
viewN.setVisibility(View.VISIBLE);

Related

Custom view hast strange layout behavior

Basically I have a custom View-Class (MessageViewAudio) which extends ConstraintLayout. This custom view contains another ConstraintLayout which contains another custom view (AudioVisualizationView) I made myself. The problem ist that the Top-Layer-Custom View (MessageViewAudio) always has some space to the right. I attached the information the layout inspector gave me. If you need any more code, just let me know.
As already said, I inspected the layout and tried different types of containers and manually tried to remove margins and paddings from every view mentioned above. But the layout inspector already says that there is no margin oder padding that could cause that strange behavior. There are two ways I got this to work One: is to remove all containers and just add the AudioVisualizationView custom view. Two: is to remove the property constrainedWidth = true from the LayoutParams of MessageViewAudio. Now I need constrainedWidth = true but I have that feeling that this property is kind of the problem, I can't just figure out why constrainedWidth results in this behavior.
With containers
Not Working
Hierarchy
ChatMessage
MessageViewAudio
audioContent
visualizationView
Without containers
Working
The only code I can provide for now is the xml of the views:
audioContent + visualizationView:
<com.jooyapp.jooy.custom_views.RoundedConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/audioContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundColor="#color/colorAccent"
app:radius="20">
<!--android:paddingStart="10dp"-->
<!--android:paddingTop="10dp"-->
<!--android:paddingEnd="10dp"-->
<!--android:paddingBottom="10dp"-->
<com.jooyapp.jooy.custom_views.AudioVisualizationView
android:id="#+id/visualizationView"
android:layout_width="wrap_content"
android:background="#color/light_grey"
android:layout_height="wrap_content" />
</com.jooyapp.jooy.custom_views.RoundedConstraintLayout>
All others are created programmatically
All in all my problem is that I don't understand where this space to the right of the custom view comes.

Does 'android:animateLayoutChanges="true" ' Still work

I saw that this statement used inside an xml layout will automate animations for you. I want to add this to my app, but when I put it in the layout I want
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/arrow_background"
android:layout_marginTop="7dp"
android:layout_marginBottom="7dp"
android:padding="10dp"
android:animateLayoutChanges="true"
android:visibility="visible"
android:id="#+id/format_help">
And then I change the visibility to gone
view.findViewById(R.id.format_help).setVisibility(View.GONE);
It only just instantly goes away. The information I saw about this was from a few years ago so does anyone know if this is still supposed to work or how to get it to work?
EDIT: Also I added this statement everywhere and it still does not working. If it matters this is inside a fragment/dialog
It works for views inside container which has the property android:animateLayoutChanges="true". If a Linear layout having the above property, whenever a new view added or removed from that container the effect is visible. The animation effect will not be visible to the container itself when container is added or removed. For more information check the below link.usage of animateLayoutChanges

Exclude certain elements from being animated in android layout transitions

I have a question regarding the android layout transition framework. In particular i want to achieve an effect that a certain part of an layout slides down or up depending on the visibility of another view(s).
Imagine the following layout. (And please overlook the nested LinearLayouts here ;) )
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="#+id/changingView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
<View
android:id="#+id/changingView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout
android:id="#+id/movingView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="false"/>
</LinearLayout>
Now what i want to achieve is that when changingView1 and changingView2 change their visibility that movingView slides up or down.
By enabling the LayoutTransition.CHANGING for the parent layout the sliding part works fine so. But this has the side effect that the movingView will also be animated when there are being items added or removed because this layout changes its bounds. And here lies my problem because this results in a very strange looking animation.
So back to my question. Is there a way to keep the sliding animation without animating layout bound changes on the movingView?
Disabling layoutTransitions on the movingView obviously does not help because this only effects the animations of the child views. I also tried playing around with enabling and disabling different LayoutTransitions on the parent layout but so far without the desired effect.
If i can add more details please let me know otherwise i hope someone can help me out.
Thanks in advance!
I know it's late but hope it can help someone. Since android:animateLayoutChanges is the property of the direct parent, you can wrap your View/Layout in a FrameLayout (or some other ViewGroup) and set android:animateLayoutChanges="false" on the new parent.
To avoid unwanted animations you can remove the animate layout changes by code when needed, something like this:
//removing the animate layout changes to prevent the default animation for the newly added items
parentLayout.setLayoutTransition(null);
/* do some logic to add the new views */
//add the animate layout changes back so the over changes will be still animated
new Handler().post(() -> {parentLayout.setLayoutTransition(new LayoutTransition());});

How to set an imageView to not be fixed at a position

the xml file:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/singleProp"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:visibility="gone">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/propertyImg"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/propertyData"
android:layout_below="#id/propertyImg">
</ListView>
</RelativeLayout>
With the above codes, the image will be fixed at top-center position. With CSS terms in html, the style of that image view is style="position:fixed" but what I want is style="position:relative".
For example,
I hope the picture can illustrate the idea.
May I know how I should modify my codes?
Let me elaborate a bit more on mark.zhai`s answer, since it's the only one that I find to be the proper approach.
First of all I wanna point out that you should think about implementing your list with a RecyclerView instead of ListView (right now it's generally favoured to use a RecyclerView; ListView is getting kinda deprecated)...
If you want to be sure that your ImageView works nicely (scroll-wise) with your list (without too much "side-work" on scroll integration), you should implement it as a first item of your list. If you stick with your ListView you can use the header function of it and add your ImageView with ListView's method addHeaderView. If you decide to move to a RecyclerView (which I think you should), you can accomplish that in a bit more difficult manner (more on that for example here).
why don't u make the imageview an item of the listview
For this you need to create a custom listview which having the first item as a image view and later having all your list items. Probably you can control this in your adapter getview method by the use of position(int)
For example if Position is equal to '0' show only image view and if position is not equal to '0' show your rest elements by using Visibility
Note: here their might be a chance of performance issues as it is loading the unnecessary views every time
To achieve this, you need to scrolling the complete layout. In general case, when you fling on a list view, only the item within the list view moves.
Check this link.
I'm not entirely sure what you're asking, as I don't know a lot about CSS, but you can check out this link which describes aligning elements within a Relative Layout.
You might want to try adding alignParentLeft or alignParentRight.
Remember margins are external to the object and padding is internal. For example to move the image 20dp from the left you would:
<ImageView
android:layout_alignParentLeft="true"
android:layout_marginLeft="20dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/propertyImg"/>
Here are some useful links about mastering Relative Layouts:
Relative Layout Params
Moving Elements Around in a Relative Layout Tutorial
Another RelativeLayout Example
Margins and Padding
Why don't you use layout_below to take your layout below whatever you want, and use layout_gravity to set it's gravity. You can check these Link to get you better understand, it will help you in these problem.

Using layout_gravity="bottom" to place at bottom of LinearLayout

I would like to place a layout on the bottom of a LinearLayout, but I can't seem to get it to work. I know that I can use RelativeLayout to do this, but I should be able to use LinearLayout, shouldn't I?
EDIT: Actually this is more confusing than I thought. The layout below is simplified. In reality, I'm using fragments on a pre-3.0 device, with the compatibility layer.
I used Hierarchy Viewer to examine what's going on, and found that an android.support.v4.app.NoSaveStateFrameLayout was added to my layout, and that layout has layout_height set to wrap_content. That seems to be what's causing my problem, but I haven't yet figured out how to fix it.
Specifically, why doesn't this work? Shouldn't the layout_gravity place it at the bottom?
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
... stuff here ...
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal">
... more stuff here ...
</LinearLayout>
</LinearLayout>
BTW, changing layout_height to fill_parent or setting layout_weight don't seem to work either. I just want to better understand what is going on, because clearly I'm missing something important. Thanks.
First of all nice question.
Android behaves we can say weird in the situation like this.
if you have selected your parent linear layout's orientation horizontal then you can set its child component at bottom by setting its layoug_gravity=bottom. suppose you have added 2 text views in that horizontal linear layout and second textview's layout_gravity is bottom then it will set to bottom but it work like it is set at bottom in other column then the first text view. NOTE : you can set textview's layout_gravity = "left" or "right" when its parent linearlayout is horizontal but you cant see its result.
Oppositely, if you have selected parent linearlayout's orientation vertical then you can set its child component at left or right by using layout_gravity. but the second textview will shown in you can say next row with left or right gravity as you have set. NOTE you can set textview's layout_gravity = "top" or "bottom" when its linear layout is vertical but you can not see its result.
Try to make sample xml design as i have stated above so you get better idea.
Strange but True!!! Try to understand this behavior. :)
Just add space between what you want at the bottom and all the rest:
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
So I resolved the problem. It's a two-part solution:
First, the way to do this without using LinearLayout is to provide weight to the element above so that it takes up all of the empty space. BTW, you can see this example in the API demos: http://developer.android.com/resources/samples/ApiDemos/res/layout/linear_layout_3.html
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
... stuff here ...
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weight="1"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
... more stuff here ...
</LinearLayout>
</LinearLayout>
This by itself didn't solve my problem, as I had a NoSaveStateFrameLayout with layout_width="wrap_content" as a parent view, and so I needed to get that fixed first. I'm using code based on the wonderful Google I/O App, and when I searched the code for NoSaveStateFrameLayout, I found this:
// For some reason, if we omit this, NoSaveStateFrameLayout thinks we are
// FILL_PARENT / WRAP_CONTENT, making the progress bar stick to the top of the activity.
mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
Thanks for an awesome comment Google!!! I added this into my source and everything worked great!
The moral of the story: Hierarchy Viewer and comments are your friends.
LinearLayout will just stack things as they are placed in there. Since it is vertical, it will keep placing items one after the next in a vertical manner. Can you change the android:gravity of the linearLayout and not the layout_gravity of the nested one and see if that works.
RelativeLayout of course should be the first way but you stated you didnt want to do that. Is there reason for that?
It could be that, as per https://stackoverflow.com/a/13366783/513038, you need to set the parent LinearLayout to have android:baselineAligned="false". Worked in my case.

Categories

Resources