简体   繁体   中英

Switching between fragments in a layout with BottomNavigationView

This is my first attempt to develop an android application.

I have a MainActivity with ConstraintLayout that has BottomNavigationView. Whenever the first navigation item is selected, I want to display a list of category (displayed in a fragment), then whenever this category is selected, another list will be displayed for items related to that particular category (in another fragment).

I have read in ( Android - fragment .replace() doesn't replace content - puts it on top ) it states that "static fragments written in XML are unable to be replaced, it has to be in a fragment container", how does it look like?

I tried to create my fragment container, but there is something wrong when I try to get the ListView (grand child of the container)

categoriesListView = getView().findViewById(R.id.categoriesList);

returns null.

MainActivity

package com.alsowaygh.getitdone.view.main;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;


import com.alsowaygh.getitdone.R;
import com.alsowaygh.getitdone.view.services.CategoriesListFragment;
import com.alsowaygh.getitdone.view.services.OnCategorySelectedListener;
import com.alsowaygh.getitdone.view.services.ServicesListFragment;

public class MainActivity extends AppCompatActivity implements OnCategorySelectedListener {

    private static final String TAG = "MainActivity";
    FragmentManager fragmentManager;
    FragmentTransaction fragmentTransaction;


    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_services:
//                    mTextMessage.setText(R.string.title_services);
                    CategoriesListFragment categoriesListFragment = new CategoriesListFragment();
                    fragmentTransaction.add(R.id.container, categoriesListFragment);
                    fragmentTransaction.commit();
                    return true;
                case R.id.navigation_bookings:
//                    mTextMessage.setText(R.string.title_bookings);
                    return true;
                case R.id.navigation_chats:
//                    mTextMessage.setText(R.string.title_chats);
                    return true;
                case R.id.navigation_settings:
                    return true;

            }
            return false;
        }
    };

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


        BottomNavigationView navigation = findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

        fragmentManager = getSupportFragmentManager();
        fragmentTransaction = fragmentManager.beginTransaction();
    }


    @Override
    public void onCategorySelected(String category) {
        Log.w(TAG, "Successfully created CategoryListFragment!");
    }
}

activity_main layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.main.MainActivity">


    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/navigation" />




</android.support.constraint.ConstraintLayout>

Fragment

package com.alsowaygh.getitdone.view.services;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.alsowaygh.getitdone.R;
import com.alsowaygh.getitdone.view.main.MainActivity;

public class CategoriesListFragment extends Fragment {
    private ListView categoriesListView;
    OnCategorySelectedListener categoryListener;



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             final Bundle savedInstanceState) {

        //initializing root view first to refer to it
        View rootView = inflater.inflate(R.layout.activity_main, container, false);

        //initializing ListView
        categoriesListView = getView().findViewById(R.id.categoriesList);

        //categories list
        final String[] categories = {"first category", "second category", "third category", "Fourth category"};

        //initializing and adding categories strings to the addapter
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this.getContext(),
                R.layout.category_textview);
        for (String c : categories) {
            arrayAdapter.add(c);
        }
        categoriesListView.setAdapter(arrayAdapter);

        //implement onListItemClick
        categoriesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //retrieve string from categories list at clicked position
            categoryListener.onCategorySelected(categories[position]);
            }
        });

        return rootView;
    }

    @Override //to fource container activity to implement the OnCategorySelectedListener
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            categoryListener  = (OnCategorySelectedListener) context;
        }catch(ClassCastException e){
            throw new ClassCastException(context.toString() + "must implement OnCategorySelectedListener");
        }
    }


}

fragments container

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/categories_list_fragment"
        android:name="com.alsowaygh.getitdone.view.services.CategoriesListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp">

        <ListView
            android:id="@+id/categoriesList"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp" />

    </fragment>
</FrameLayout>

Your help will be much appreciated.

You need to add the FrameLayout container within the layout file of the MainActivity(activity_main), onclick of the buttons in BottomNavigationView replace with the fragment. In this way you have a Activity and the fragments are shown within the activity, on click of each menu item you can invoke to replace it with the fragments. This should resolve your problem.

You need to change the layout as below in activity_main.xml.

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.main.MainActivity">

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

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/navigation" />
</android.support.constraint.ConstraintLayout>

In the MainActivity code, you need to change as below:

case R.id.navigation_services:
//                    mTextMessage.setText(R.string.title_services);
                    CategoriesListFragment categoriesListFragment = new CategoriesListFragment();
                    fragmentTransaction.replace(R.id.frame, categoriesListFragment);
                    fragmentTransaction.commit();
                    return true;

In the fragment layout file change to LinearLayout:

<LinearLayout
    android:id="@+id/categories_list_fragment"
 android:name="com.alsowaygh.getitdone.view.services.CategoriesListFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="8dp"
    android:layout_marginTop="8dp">

    <ListView
        android:id="@+id/categoriesList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp" />

</LinearLayout>

EDIT

In the fragment code, change the layout to the name of the fragment layout file(R.layout.fragment_layout_name).

View rootView = inflater.inflate(R.layout.fragment_layout_name, container, false);
    //initializing ListView
categoriesListView = rootView.findViewById(R.id.categoriesList);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM