0

I'm running into issues opening a fragment from another fragment. My Main Activity implements the newest Nav Drawer and each of the options in the Nav Bar list opens a new fragment. That much is implemented and working well. The problem I have is with the next layer of fragments. I have an Event Fragment with an imageButton. When this is clicked I need to navigate to a new fragment for this sub event. I tried creating an onclicklistener in the Event Fragment the opened the sub event page but i get the following error.

No view found for id 0x7f08000a (com.ikimuhendis.ldrawer.sample:id/imagefrag) for fragment imageFragment1 {348db088 #0 id=0x7f08000a}

public class EventFragment extends Fragment

{
    ImageButton test;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_event, container, false);

        SliderLayout sliderShow = (SliderLayout) rootView.findViewById(R.id.slider);
        sliderShow.setDuration(8000);
        sliderShow.setPresetTransformer(SliderLayout.Transformer.ZoomOut);

        //get the button view
        test = (ImageButton) rootView.findViewById(R.id.imageButton);

        test.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Fragment videoFragment = new imageFragment1();
                FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
                transaction.replace(R.id.imagefrag, videoFragment)
                        .commit();
            }

        });

        HashMap<String, Integer> file_maps = new HashMap<String, Integer>();
        file_maps.put("Munster Vs Leinster", R.drawable.rugby);
        file_maps.put("Ennio Morricone", R.drawable.ennio);
        file_maps.put("Leinster Vs Harlequins", R.drawable.heino);
        file_maps.put("WWE Live", R.drawable.wwe);

        for (
                String name
                : file_maps.keySet())

        {
            TextSliderView textSliderView = new TextSliderView(getActivity());
            textSliderView
                    .description(name)
                    .image(file_maps.get(name));
            sliderShow.addSlider(textSliderView);
        }

        getActivity().setTitle("Events");
        return rootView;
    }
}

The code above is meant to open this image fragment

public class imageFragment1 extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.imagefragment1, container, false);

        return rootView;
    }
}

imageFragment1 xml code

<?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:id="@id/imagefrag" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="This is a test"
        android:id="@+id/textView"
        android:layout_marginTop="41dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

How to replace the activity's fragment from the fragment itself?

I'm pretty unsure about where the fragment transaction should take place. In my main activity the fragment transaction takes place in a switch block for the navigation drawer. I've read that "Please note that fragment should NOT directly replace itself or any other fragments. Fragments should be separate entities. What fragment should do is to notify its parent activity that some event has happened. But it is, again, NOT a fragment job to decide what to do with that! It should be activity to decide to i.e. replace the fragment on phone, but to i.e. add another to existing one on tablets. So you are basically doing something wrong by design"

Another poster mentions "A better way to handle this situation is by creating a callback implementation for the main activity to handle requests such as start a new fragment" How do i set this up in my main activity so that it communicates to the sub fragments of my drawer fragments. Any thoughts on this much appreciated.

Main Activity

    public class SampleActivity extends Activity {

        private DrawerLayout mDrawerLayout;
        private ListView mDrawerList;
        private ActionBarDrawerToggle mDrawerToggle;
        private DrawerArrowDrawable drawerArrow;
        private CharSequence mDrawerTitle;
        private CharSequence mTitle;
        CustomDrawerAdapter adapter;
        List<DrawerItem> dataList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);
        ActionBar ab = getActionBar();
        ab.setDisplayHomeAsUpEnabled(true);
        ab.setHomeButtonEnabled(true);

        dataList = new ArrayList<DrawerItem>();
        dataList.add(new DrawerItem("Home", R.drawable.home));
        dataList.add(new DrawerItem("How It Works", R.drawable.howitworks));
        dataList.add(new DrawerItem("Events", R.drawable.events));
        dataList.add(new DrawerItem("Profile", R.drawable.signin));

        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.navdrawer);

        drawerArrow = new DrawerArrowDrawable(this)
        {
            @Override
            public boolean isLayoutRtl() {
                return false;
            }
        };

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
            drawerArrow, R.string.drawer_open,R.string.drawer_close)
        {

            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);
        mDrawerToggle.syncState();
        adapter = new CustomDrawerAdapter(this, R.layout.custom_drawer_item,
                dataList);
        /* ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, android.R.id.text1, mNames); */
        mDrawerList.setAdapter(adapter);
        mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                {
                    displayView(position);
                    // Running Fragment Transaction code here
                }
            }

             // Method that updates content frame with different fragments
            private void displayView(int position) {
             // update the main content by replacing fragments

                Fragment fragment = null;
                Bundle args = new Bundle();
                switch (position) {
                    case 0:
                        fragment = new TitleFragment();
                        mDrawerToggle.setAnimateEnabled(true);
                        drawerArrow.setProgress(1f);
                        mDrawerToggle.syncState();
                        break;
                    case 1:
                        fragment = new HowFragment();
                        mDrawerToggle.setAnimateEnabled(true);
                        drawerArrow.setProgress(1f);
                        mDrawerToggle.syncState();
                        break;
                    case 2:
                        fragment = new EventFragment();
                        mDrawerToggle.setAnimateEnabled(true);
                        drawerArrow.setProgress(1f);
                        mDrawerToggle.syncState();
                        break;
                    case 3:
                        fragment = new ProfileFragment();
                        mDrawerToggle.setAnimateEnabled(true);
                        drawerArrow.setProgress(1f);
                        mDrawerToggle.syncState();
                        break;
                }
                    fragment.setArguments(args);
                    FragmentManager fragmentManager = getFragmentManager();
                    fragmentManager.beginTransaction()
                            .replace(R.id.content_frame, fragment).addToBackStack(null).commit();

                    // update selected item and title, then close the drawer
                    mDrawerList.setItemChecked(position, true);
                    setTitle(dataList.get(position).getItemName());
                    mDrawerLayout.closeDrawer(mDrawerList);
            }
        });

    }

    @Override
    public void setTitle(CharSequence title)
    {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // The action bar home/up action should open or close the drawer.
        // ActionBarDrawerToggle will take care of this.
        if (mDrawerToggle.onOptionsItemSelected(item))
        {
            return true;
        }
        return false;
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

}
Community
  • 1
  • 1
  • create one `interface` that has a method for opening fragment, create one instance from that in fragment and generate setter for that and call method, in activity implement interface and set fragment instance by `this`, thin handle fragment transition from activity – Shayan Pourvatan Dec 28 '14 at 12:06
  • Is it possible to see a code example? I'm unsure of how to implement that. – TheNyquistLimit Dec 28 '14 at 12:13

1 Answers1

0

As suggested in the comment, you have to make custom Interface. Trought he Interface, Fragment can communicate with its parent Activity.

In your Fragment, where you have the button:

private OnDataPass dataPasser;

//Interface, trought the fragment can comunicate with activity
public interface OnDataPass {
    public void onDataPass();
}

//Method, which you call in your onClickListener
public void passData() {
    // Method in the Activity
    dataPasser.onDataPass();
}

//Method, which creates the interface
@Override
public void onAttach(Activity a) {
    super.onAttach(a);
    try {
        dataPasser = (OnDataPass) a;
    } catch (ClassCastException e) {
        throw new ClassCastException(a.toString() + " must implement onDataPass");
    }
}

In your activity:

// You can also pass arguments, if you need
@Override
public void onDataPass() {

    //Do your code for switching the fragments or anything else
    ...

}

Your Activity has to implement this Listener:

public class ActivityMain extends Activity implements OnDataPass{

But next time try to research more before asking, there are plenty of questions to this topic. Example.

Community
  • 1
  • 1
Vojtěch Pešek
  • 1,070
  • 8
  • 25