40

My Android application launches into BeginActivity which is a subclass of SherlockFragmentActivity and shows it's first view using:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
            Fragment f = LoginFragment.newInstance();

            getSupportFragmentManager()
                    .beginTransaction()
                    .add(android.R.id.content, f, "loginfragment")
                    .attach(f)
                    .commit();
        }
}

LoginFragment shows a view like this:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.login, container, false);

        // Get pointers to text views
        usernameField = (EditText) v.findViewById(R.id.usernameLog);
        passwordField = (EditText) v.findViewById(R.id.passwordLog);
        progressBar = (ProgressBar) v.findViewById(R.id.progressBarLog);
        // Set button click listeners for both buttons
        Button b = (Button) v.findViewById(R.id.loginButton);
        b.setOnClickListener(this);

        return v;
    }

when clicking login I show a list view like this:

BeginActivity top = (BeginActivity) getActivity();
Fragment f = OfferListFragment.newInstance();
        top.getSupportFragmentManager()
                .beginTransaction()
                .add(android.R.id.content, f, "offerList")
                .addToBackStack(f.getClass().getSimpleName())
                .commit();

and finally, OfferListFragment displays its view like this:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.offers, container, false);

        return v;
    }

Now the problem I am having, is that the final OfferListFragment seems to be transparent and I can see the login screen below it. I am using Theme.Sherlock that has a black background. Should I be manually setting the views backgrounds to black also? Or would the black in the theme be customisable by the user on the system? (I'm not an Android user).

Thanks

Darren
  • 10,182
  • 20
  • 95
  • 162
  • Do you want to remove `LoginFragment` completely from `BeginActivity` while displaying `OfferListFragment` ? – Mehul Joisar May 16 '13 at 18:08
  • Not particularly. The user should be able to click the back button to go back to it. – Darren May 16 '13 at 18:13
  • Ok bro.I am not sure but have you tried by using `replace(int, android.app.Fragment)` method of `FragmentTransaction` class ? – Mehul Joisar May 16 '13 at 18:29
  • No, I shall give that a go. How would clicking `back` work with that though? – Darren May 16 '13 at 18:33
  • 1
    you need to use `addToBackStack` method of `FragmentTransaction` class after using `replace` method and finally at the end use `commit` method. – Mehul Joisar May 16 '13 at 18:39

5 Answers5

87

IMHO I do not agree with this answer.

You may want to replace your fragment or you may want to add it.

For example let's say that you are in a fragment that is a list retrieved by a network request, if you replace the fragment with let's say the detailFragment and you add it to backStack.

When you go back your fragment will redo the network query, of course you can cache it but why? It is a back to a previous state, so with add the last fragment will be in exactly the same status with no code whatsoever.

Fragments are transparent backgrounded by default because they can be used to paint only a small portion of the screen but if your fragment is match_parent then just set its background to a color and keep using add on the fragmentTransaction.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView1"
android:background="@android:color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content" >

That will be your root element on the fragment layout XML, could be linear, etc etc and the transaction code is:

YourFragment detail = YourFragment.newInstance(Id);
ft.add(R.id.contentHolder, detail);
ft.addToBackStack(TAG);
ft.commit();

Hope this helps someone that wants to know how to see a solid background without changing the add to replace which is usually not the best case.

Regards

flooose
  • 499
  • 8
  • 25
Goofyahead
  • 5,874
  • 6
  • 29
  • 33
  • 3
    This indeed should be the correct answer, as the previous one requires using the "replace" function explicitly instead of staying implementation independent. – HBN Jun 20 '14 at 10:14
  • 1
    I found that this is the correct answer because even if using replace the fragment that I was replacing still bled through until I made the background opaque on my other fragment. Thank you! – crowmagnumb Aug 20 '14 at 00:47
  • is using replacement better in terms of speed and/or memory usage? also, both methods will need to handle state loss (meaning need to save the data into the saveInstance), right ? – android developer Nov 24 '14 at 14:04
  • I was having an issue with this solution, my fragment was still transparent even though I was setting the background... but it turned out the problem was that I was setting tools:background, instead of android:background. just sharing incase it happens to someone else. – Siavash Apr 10 '15 at 07:21
  • 32
    What might be even more helpful is set android:background="?android:attr/windowBackground" on the top element of the fragments view. This way the default background is used and not some white which likely will not fit in your theme. – Paul Woitaschek Apr 15 '15 at 10:27
  • 11
    `Fragments are transparent backgrounded by default` That alone was enough for me. I do not think I've seen this mentioned in the documentation though. – George Daramouskas Jun 12 '15 at 10:37
  • 1
    I also having the same issue. I set a background color that defined in color.xml. My fragment is still transparent. – Divya Jul 05 '15 at 22:49
  • 3
    adding background to a root element will throw a lint warning "Possible Overdraw: Root element paints background". Can this be ignored in this scenario? – Much Overflow Oct 09 '15 at 07:25
  • 2
    What about memory usage?! – codename_47 Oct 20 '15 at 05:39
  • If we add F2 on top of F1 toolbar won't have action items from both? Assume both F1 & F2 has menu items of their own. – Mahendran Jan 01 '16 at 07:05
  • 1
    But what i find strange is if the bottom fragment has a button, I am still able to click that button even if a new fragment is added on top of the stack. – Ivan Leong Feb 01 '18 at 16:58
  • I noticed this too when using `.add()` is there any documentation about Fragment being transparent by default when added instead of using replace? It would be really helpful. – Mihae Kheel Mar 19 '21 at 16:06
41

Try using FragmentTransaction class to replace the fragments instead of just adding.

Explanation:

Each transaction is a set of changes that you want to perform at the same time. You can set up all the changes you want to perform for a given transaction using methods such as add(), remove(), and replace(). Then, to apply the transaction to the activity, you must call commit().

Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.

For example, here's how you can replace one fragment with another, and preserve the previous state in the back stack:

Example:

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

Reference: Please have a look at Managing Fragments

I hope it will be helpful !!

zyamys
  • 1,609
  • 1
  • 21
  • 23
Mehul Joisar
  • 15,348
  • 6
  • 48
  • 57
  • 1
    Your awesome. That solved a multitude of problems for me including this one http://stackoverflow.com/questions/16594352/listener-for-when-a-fragment-becomes-visible Thank you – Darren May 16 '13 at 19:08
  • 1
    Its not always the best solution to just replace a fragment, most people will need to add to have the backstack implementation, we can discuss it :) see my answer – Goofyahead Feb 17 '14 at 18:00
  • 1
    @Goofyahead: If you look at the code provided in question by `Darren`, he was already using the mechanism to `add` fragments instead of `replace`.but the issue, he was able to see `login fragment` which was aimless after logged in once.so I have suggested to get rid of it by using `replace` with `OfferListFragment` fragment. – Mehul Joisar Feb 25 '14 at 14:23
6

i used many techniques but no gain Finally i fixed it by adding background of the container or the fragment layout like this

android:background="@android:color/white"    

you just need to add in your Layout or the container view of you Fragment Hope it will help

Sultan Ali
  • 2,497
  • 28
  • 25
1

Well, giving background to fragment is not always enough. For example if your background activity or fragment contains buttons, then we should set elevation for our FragmeLayout so that our fragment comes on top of other elements. Something like this:

    <FrameLayout
    android:elevation="5dp"
    ... />

and then inside our fragment layout, we should set a background and make clickable attribute true to prevent working of buttons in background activity or fragment. Something like this :

<androidx.constraintlayout.widget.ConstraintLayout
...
android:background="@android:color/darker_gray"
android:clickable="true">
OmiD_D
  • 71
  • 2
0

Nobody mentioned that if you added a background to your Fragment but you are still getting a transparent background, you need to check that your FrameLayout is the last view in your XML.

Because z-index in Android is calculated by XML position and lowest view in the hierarchy have the highest z-index.

For example I fixed this problem recently simply moving the FrameLayout from here:

<androidx.coordinatorlayout.widget.CoordinatorLayout
  ...>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <RelativeLayout
      ...>
    </RelativeLayout>

    <RelativeLayout
      ...>
    </RelativeLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

to here:

<androidx.coordinatorlayout.widget.CoordinatorLayout
  ...>

    <RelativeLayout
      ...>
    </RelativeLayout>

    <RelativeLayout
      ...>
    </RelativeLayout>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
MatPag
  • 41,742
  • 14
  • 105
  • 114