70

I have a problem to send the view to back. In Android we have a method like bringToFront(), to place the view on top of the another view. Like that, I want to put the view on below the previous image.

Is there any method like sendToBack() or bringToBack() in Android. If so, can any one help me in this.

Note: that I do not want to control the z-order by the order of placing items in layout I want to control the z-order programmatically.

I do not want to hide the views on the front I just want them to be behind the view that is moving.

0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
Lukap
  • 31,523
  • 64
  • 157
  • 244

13 Answers13

67

I realize that this has been implied in other answers, but no one posted the code. I keep the following in a utility class where I have "helper" functions for dealing with views:

public static void sendViewToBack(final View child) {
    final ViewGroup parent = (ViewGroup)child.getParent();
    if (null != parent) {
        parent.removeView(child);
        parent.addView(child, 0);
    }
}
Turix
  • 4,470
  • 2
  • 19
  • 27
  • Wont this overwrite whatever was in slot 0 before? I would think you would have to shuffle every child down a slot so after removing the child, get the children count, for each of them retrieve the child, replace it with the previous child (starting with the one removed) and then move on to the next child. When done add the final child back in and you are done... or so I would think I've not seen anything in the documentation of addView that suggests it will displace an existing child at that location. – James Feb 21 '14 at 20:00
  • 3
    @James No, it does shift them for you (similar to `add()` in an `ArrayList`). You can try it out if you want. Or confirm it by looking at the source code... it uses addInArray() internally. But you're right about this not being clear in the documentation. And for that reason, if you use this, you should probably keep an eye on this in future API updates, just in case they decide to change this (undocumented) behaviour. Good point. – Turix Feb 21 '14 at 22:15
  • 1
    Thanks for this piece of code. Only thing I would is "null != parent" to "parent != null" since it reads better. – clocksmith Feb 16 '15 at 04:24
  • 6
    @clocksmith Thanks for the suggestion. Since I'm old, I tend to prefer always putting the null on the left hand side in comparisons to prevent accidental assignment to null (if you forget the second '=' character in "parent = null" for example). I know this isn't really necessary anymore thanks to nice compiler warnings, but it's ingrained as a habit from long ago and, well, as they say... old habits die hard. – Turix Feb 20 '15 at 21:30
  • Note that if `parent` is a `LinearLayout`, `child` becomes the first one regardless of the previous order; tried on Marshmallow 6.0.1. – Attacktive May 10 '16 at 10:12
  • it just disappeared – user924 Aug 16 '17 at 08:31
46

There is no sendToBack() method. But if you call bringToFront() on the lower positioned view you get almost the same effect.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Pepijn
  • 1,439
  • 17
  • 16
  • It is a somewhat vague answer, provides no example, and does not document that you have to invalidate the view after the call. Rather than petition for points, why not improve the answer so they are earned? At least that would have been how to handle it before @noob posted it properly. – Abandoned Cart Apr 26 '17 at 18:17
  • 1
    you mean get ALL views before needed one and call sendToBack? this is crazy – user924 Aug 16 '17 at 08:32
  • It makes sense. No more to explain ;-) – PYK Nov 27 '19 at 04:28
37

Afaik there's no built-in solution for this. I guess you're trying to modify the z-order in a FrameLayout, or something similar.

However, I think you can modify the order of the contained child elements in the layout. RemoveChild...() and addView() methods can take position values, so you could most likely swap child elements around, and that would modify the z-order. It seems a bit hacky solution however.

Or consider modifying the visibility property of the child views, you may get similar behaviour, and that'd be much cleaner I think.

Edit:

With the new Android version, the L Developer Preview it seems that at last we have the ability to easily change the Z ordering of Views. 'Elevation' and 'TranslationZ' properties to the rescue: https://developer.android.com/preview/material/views-shadows.html

Zsombor Erdődy-Nagy
  • 16,864
  • 16
  • 76
  • 101
  • 1
    I approve. I have seen that, indeed, you can not call `bringToFront()` for a `view` that has children. First you have to `removeAllViews()` or `setVisibility(View.GONE)` or somethingelse like that. Then you can use `addView()` or `setVisibility(View.Visible)` to bring children back. – AlexAndro Jan 25 '13 at 12:17
  • can you help me how to implement this one? – MMakati Oct 31 '13 at 03:57
  • This was not the issue what I was facing, but gave me an idea to fix my issue (remove and add view sorted my problem). Thanks. – avijendr May 25 '17 at 16:37
19

Call bringToFront() on the view you want to get in the front, and then call the invalidate() method on all the view including the view which you want in the front. Repeat same for all the listeners.

So when another view's listener will get called, the previous view will get invalidated and will be in background.

Andrey Rudenko
  • 1,271
  • 20
  • 34
0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
9

Here is the method I am using to send a View to the back (so opposite of bringToFront, kind of sendToBack):

    private void moveToBack(View myCurrentView) 
    {
        ViewGroup myViewGroup = ((ViewGroup) myCurrentView.getParent());
        int index = myViewGroup.indexOfChild(myCurrentView);
        for(int i = 0; i<index; i++)
        {
            myViewGroup.bringChildToFront(myViewGroup.getChildAt(i));
        }
    }

Hope this helps!

Al-Noor Ladhani
  • 2,413
  • 1
  • 22
  • 14
  • There is a bug on this, let say I have 3 images. If I move to back the 2nd image it works fine. But if I move the 3rd image (after the 2nd image), the 3rd image move to back but the second image goes to front. – MMakati Nov 03 '13 at 15:30
  • this is crazy, it will crash all your layout/view design – user924 Aug 16 '17 at 08:41
2

Please note that you can use view.setZ(float) starting from API level 21. Here you can find more info.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
2

it work's fine like bringToBack()

public void moveToBack(ViewGroup viewGroup, View v) {
    int s = 1;
    for (int i = 1; i < viewGroup.getChildCount(); i++) {
        if (viewGroup.getChildAt(1) == v) {
            s = 2;
        } else {
            viewGroup.getChildAt(s).bringToFront();
        }
    }
}
2

If you're using appCompat library, there's another way to change Z order for devices lower than 21 API level:

ViewCompat.setTranslationZ(view, zValue);
Fragment
  • 1,555
  • 1
  • 26
  • 33
2

In your XML File you must to write in order:

<FrameLayout
android:id="@+id/frameLayoutXML"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
<ImageView
 android:id="@+id/imageViewXML"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatB_XML"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>

In this case, the imageView will be back of the FloatingActionButton.

If you want change something, and you will do it programmatically then:

public class SomeActivity extends AppCompatActivity {

    //declare variables
    ImageView imageView;
    FrameLayout frameLayout;
    FloatingActionButton floatingActionButtonNew;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Here is to call what already exists at XML file
        frameLayout=findViewById(R.id.frameLayoutXML);   
        imageView = findViewById(R.id.imageViewXML);
        //Here is to declare a new Element to add to the view, but is not at XML File
        floatingActionButtonNew=New FloatingActionButton(this);
        frameLayout.removeAllViews();  //here you remove all views.
        frameLayout.addView(imageView);//And you add again the imageView first
        floatingActionButtonNew.setLayoutParams(new 
         RelativeLayout.LayoutParams(
          RelativeLayout.LayoutParams.WRAP_CONTENT,
          RelativeLayout.LayoutParams.WRAP_CONTENT
        )); //Then you can give some format to your floatingButtonNew

        //And finally  add to the frameLayout the new View in this case the floatingButtonNew
        frameLayout.addView(floatingActionButtonNew);
    }
}

In this order of view declarations, you will have again the image back from the floating button. So the view that is declared first will be back from the view that is declared secondly, and the key to achieve the order, is to removeAllViews of a FrameLayout or LinearLayout and add again this views when you are adding programmatically.

1

If the views in question are buttons, programmatic adjustments require a single line of xml for full z-order control. Otherwise, setElevation(), setZ(), setTranslationZ(), and bringToFront() will all inexplicably fail you. See description on separate thread below.

https://stackoverflow.com/a/68674834/14116101

1

You can also try to use functionality of ViewGroup.addViewInLayout() method which take an index, determining should the view be at the end or at the beginning of the list

teoREtik
  • 7,886
  • 15
  • 46
  • 65
0

I would either set it's visibility to 0 or just bring the view under it in front of it.

-5

You could try doing view.setVisibility(View.INVISIBLE) or view.setVisibility(View.GONE).

UPDATE:

This shows you how to accomplish what you want to do.

A. Abiri
  • 10,750
  • 4
  • 30
  • 31