2

even though i googled extensively, i cant find a solution to my problem. I am new to programming, so please consider that in your answer.

I have a Main Activity and a Menu bar at the bottom. Since the menu bar is scrollable and i want to have it for all the different screens, i figured out that i could - instead of making an intent for a new activity - just put a fragment on top of the existing screen (and spare out the menu bar).

But i fail at programatically opening that fragment. I tried the following, but it doesnt even recognice the ID of the FrameLayout.

I was trying to replace a FrameLayout in my Main Activities' xml file with the fragment:

    FragmentManager fragmentManager = getSupportFragmentManager();
    android.support.v4.app.FragmentTransaction ft =
    fragmentManager.beginTransaction();

    ft.replace(R.id.idOfFrameLayout, new nameOfFragmentClass());
    ft.commit();

EDIT:

It works after i implemented OnFragmentInteractionListener into the Main Activity. Thanks to everyone!

Florian Walther
  • 6,237
  • 5
  • 46
  • 104

3 Answers3

1

When you use the 'replace' method, you need 3 things:

1- the container id, which is the view that is going to hold your fragment's view. 2- the fragment instance you want to use and 3- the fragment instance's tag, but this is optional.

Given that, let's say you have the following layout for your activity:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    ...
</android.support.design.widget.AppBarLayout>

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</android.support.v4.widget.NestedScrollView>

<android.support.design.widget.BottomNavigationView
    android:id="@+id/navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:background="?android:attr/windowBackground"
    app:menu="@menu/navigation" />
</android.support.design.widget.CoordinatorLayout>

The FrameLayout which id is "container" is the holding view, so that's the id you've gotta use:

ft.replace(R.id.container, new nameOfFragmentClass());

Rob
  • 2,243
  • 4
  • 29
  • 40
1

I suggest use this library to manage fragments:

FragmentManagerAndroid

1

My original answer suggested using add instead of replace for the Fragment transaction. I have since learned that either can be used in this case. For more info on the differences, see this, this and this

Since my add/replace idea was off base, I've changed my answer to a simple Fragment tutorial. One Fragment inflated from one Activity. I've included the code for Fragment to Activity communication (the reason for the OPs problem) but left comments on what could be deleted if that's not needed. The only thing done in the Activity is launching the Fragment then receiving a message back from that Fragment. The Fragment has a button that will cause a message to be sent back to the Activity. The message will then be Logged.

In both classes, if no communications is needed from the Fragment to the Activity, delete anything that is marked TODO:

// this is what controls whether you use a Fragment from the support library
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class SimpleActivity extends AppCompatActivity
//      TODO: delete "implements SimpleFragment.OnFragmentInteractionListener" from this
//      line (leave the '{')
        implements SimpleFragment.OnFragmentInteractionListener {

    private static final String TAG = SimpleActivity.class.getSimpleName();

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

        SimpleFragment fragment = new SimpleFragment();

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
            .add(R.id.fragment_container, fragment)
            .commit();
    }

    // TODO: this entire method can be deleted
    @Override
    public void onFragmentInteraction(String message) {
        // This is where you can act on the message from the Fragment.  You would do 
        //  things that are done from an Activity or you may pass the message on 
        //  to another Fragment.
        Log.d(TAG, message);
    }
}

Most import statements aren't shown, I left this one in to indicate using the support library

import android.support.v4.app.Fragment;

public class SimpleFragment extends Fragment {
    private OnFragmentInteractionListener mListener;    // TODO: delete this line

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

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

        Button button = (Button)rootView.findViewById(R.id.msg_button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // TODO: delete these 3 lines, do something else with the button click
                if (mListener != null) {
                    mListener.onFragmentInteraction("Message from Fragment");
                }
            }
        });

        return rootView;
    }

    // TODO: this entire method can be deleted
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    // TODO: this entire method can be deleted
    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    // TODO: this entire method can be deleted
    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(String message);
    }
}

Now the layout files. 1st activity_simple.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fragment_container"
        >
    </FrameLayout>
</android.support.constraint.ConstraintLayout>

Then fragment_simple.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Info to Activity"
        android:id="@+id/msg_button"
        />
</RelativeLayout>

This is a very basic sample. Here is a more extensive guide for Fragment usage.

Gary99
  • 1,750
  • 1
  • 19
  • 33
  • Thank you for your answer. Unfortunatly, changing "replace" to "add" did not work and the app is still crashing. I read the tutorial and what i noticed (before already), is, that i cant use the code that is given there. It shows an error message saying something about "Required [...].v4.[...]", hence i used "android.support.v4.app." infront of "FragmentTransaction" (it was an option in the dropdown menu that made the compiler error go away). I also cant use "getFragmentManager", because it shows the same "v4" Error Message. – Florian Walther Aug 01 '17 at 17:26
  • Yes. While Google's example code in their guides is great as a general guide, it is sometimes old & sometimes even has errors (I think they just enter the code without compiling & running sometimes). "...support.v4..."The support packages can be confusing at 1st (& sometimes later too). In general, when they're available you want to use them. It's better to handle them with an "import" at the top of the file but this works too. – Gary99 Aug 01 '17 at 17:35
  • "You may only need to change one line" I say may because there may be other issues with your code as well. Can you post your stacktrace from the crash? You'll want to do this as an edit to the question (this applies to the layout file request too) vs. in a comment. – Gary99 Aug 01 '17 at 17:37
  • After you asked for my "stacktrace", i looked into Android Monitor (since i didnt know what stacktrace is and searched for it). There i found a red message telling me, that i had to implement OnFragmentInteractionListener + its onFragmentInteraction method. I did that and now it works. – Florian Walther Aug 01 '17 at 17:52
  • So it was failing in `onAttach()` because your Activity didn't implement the listener. A common error when 1st working with fragments. For future reference, you only need that if you're planning on sending info to the activity (or another Fragment). If all of your info is Activity->Fragment, you can gut the `onAttach()` method, delete the `interface` from your Fragment and skip putting it in your Activity. Curious, now that it's working, is it working with `replace()`? – Gary99 Aug 01 '17 at 17:58
  • Well, I learned something then. I thought an `add` was needed before 'replace` could be used. – Gary99 Aug 01 '17 at 18:01