Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Starting a fragment from an activity.

Hello.

I have been trying to figure this out for a while, I'm trying to start a fragment from an activity using an ImageView button. The thing is the only examples I've seen online of starting a fragment from an activity was when RecyclerViews were being used. How do I start a fragment from an activity using an ImageView?

Thanks!

Kourosh Raeen
Kourosh Raeen
23,733 Points

Hi Diego - Is it an ImageButton or an ImageView? And when you click/touch the ImageButton/ImageView you want to start a fragment. Is that correct?

ImageView and yes, starting a fragment is my intent :)

1 Answer

Kourosh Raeen
Kourosh Raeen
23,733 Points

So let's say that you have an ImageView in your activity whose id is my_image and you get a reference to it in your activity's onCreate() method like this:

ImageView imageView = findViewById(R.id.my_image);

Let's also assume that the Fragment you want to start is called MyFragment. Also, assume that you have a FrameLayout in your activity's layout file whose id is fragment_container and that it is going to contain the fragment Then you can set a click listener on the ImageView and start your fragment like this:

imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyFragment fragment = new MyFragment();
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragment_container, fragment);
                transaction.commit();
            }
        });

If you would like to pass some information to the fragment you can use a Bundle and pass that Bundle to the Fragment by calling the setArguments() method. For example, if I have a custom object that I want to pass to the Fragment it would look like this:

imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle args = new Bundle();
                args.putParcelable("my_custom_object", myObject);
                MyFragment fragment = new MyFragment();
                fragment.setArguments(args);
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragment_container, fragment);
                transaction.commit();
            }
        });

In the above code the variable myObject is holding a reference to my custom object. There are other methods in the Bundle class that you can call to put primitive data types in it. Then on the fragment side you can retrieve the arguments like this:

MyCustomObject object = getArguments().getParcelable("my_custom_object");

The fragment you want to start could also live in another activity. In that case, in the onClick() callback you use an Intent to start that activity and then you can use a FragmentTransaction to start your fragment dynamically similar to the code above.

Let me know if you have any questions.

Thanks! But now, for some reason, the button from the activity is still active in the background. When I'm in the fragment and I press in the same area where the button was, the fragment gets added again.

Kourosh Raeen
Kourosh Raeen
23,733 Points

You could change the visibility of the button by calling setVisibility(View.GONE) on it. But I think a better solution might be to start another activity when the image is clicked and have that activity contain and start the fragment. Can you tell me a bit more about what you're trying to do in general terms?

Sure thing.

So I currently only have two activities and three fragments (the third fragment isn't needed for now), my main activity is a list activity, in that activity I have a button in the top right that sends you to the second activity, this is where the problem is. In the second activity I have two big buttons, each taking up half of the screen horizontally. Each button is suppose to open/start a fragment, button one starts fragment one, and, likewise, button two starts fragment two.

Kourosh Raeen
Kourosh Raeen
23,733 Points

So after you click one of these big buttons the buttons should disappear and the fragment should take up all the space. Is that the expected behavior?

Yes.

Kourosh Raeen
Kourosh Raeen
23,733 Points

Can you post the layout file where these buttons are defined?

Sure.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/NewItemLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".activities.NewItemActivity"
    android:background="@color/colorBackground">

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/NewNoteImage"
            android:src="@drawable/sm_note_select"
            android:layout_weight="1"
            android:padding="10dp"/>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/NewCategoryImage"
            android:src="@drawable/sm_category_select"
            android:layout_weight="1"
            android:padding="10dp"/>
    </TableLayout>
</RelativeLayout>
Kourosh Raeen
Kourosh Raeen
23,733 Points

Ok, I just created a test application and this is what I did and it seems to be working. In your activity's layout file add a FrameLayout for the Fragment and give it some id. Also, give some id to the TableLayout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kouroshraeen.testapplication.MainActivity">

    <TableLayout
        android:id="@+id/table_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/NewNoteImage"
            android:src="@drawable/flag_of_california"
            android:layout_weight="1"
            android:padding="10dp"/>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/NewCategoryImage"
            android:src="@drawable/flag_of_new_mexico"
            android:layout_weight="1"
            android:padding="10dp"/>
    </TableLayout>

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

    </FrameLayout>

</RelativeLayout>

I copied the xml of your TableLayout and used a couple of images I had handy.

My activity's code looks like this:

package com.kouroshraeen.testapplication;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView caImageView = (ImageView) findViewById(R.id.NewNoteImage);
        ImageView nmImageView = (ImageView) findViewById(R.id.NewCategoryImage);
        final TableLayout tableLayout = (TableLayout) findViewById(R.id.table_layout);

        caImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tableLayout.setVisibility(View.GONE);
                Fragment fragment = new FirstFragment();
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.contaner, fragment);
                transaction.commit();
            }
        });

        nmImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });


    }
}

When the image is clicked I set the visibility of the TableLayout to GONE and then start the fragment. My fragment is a really simple one with just a TextView:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context="com.kouroshraeen.testapplication.FirstFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment"/>

</FrameLayout>
package com.kouroshraeen.testapplication;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
 * A simple {@link Fragment} subclass.
 */
public class FirstFragment extends Fragment {


    public FirstFragment() {
        // Required empty public constructor
    }


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

}

Give this a try and see if it fits your need. Let me know how it goes.

p.s. A concern that I have for this approach is navigating back to the activity where the buttons are. That is the reason I think it might be better to start an activity containing the fragment when the image is clicked.

It works! But yeah, I think opening a new activity containing the fragment is a better approach. I'll let you know if I have any problems. Thanks for everything!

Also, I'm assuming I will need a bundle for this?

Kourosh Raeen
Kourosh Raeen
23,733 Points

Glad it worked! The two buttons and the fragment are in your second activity so I assume after you click one of those buttons and you see the fragment you can hit the back button to go back to the first activity with the list and from there you can go back to the second activity and see the two buttons again, although it feels a bit round about. If you have the two buttons start a third activity that hosts the fragment then you can get back to the second activity with one click.

I think another possibility is to modify the behavior of the back button in the second activity so that when the buttons are visible pressing the back button will take the user back to the first activity but if the buttons are gone and the fragment is visible then pressing the back button will remove the fragment from FragmentManager and makes the buttons visible again.

As for using a Bundle, it depends. If you need to pass any information to the fragment then you can use it.

Happy coding!

Thanks!

So I'm already having a bit of a problem. I have the fragment I want in the new activity I created, but how do I make it so that the fragment changes depending on which button I press?

Kourosh Raeen
Kourosh Raeen
23,733 Points

When you create the intent to start the activity you can add a string to the intent as an extra, using the putExtra() method. The string would indicate which fragment the activity should host. On the activity side you can retrieve the string extra using the getStringExtra() method and then use an if statement to decide which fragment to go with.

Worked like a charm! Thanks for everything!

Kourosh Raeen
Kourosh Raeen
23,733 Points

My pleasure! Glad I could help!