【问题标题】:Switching between fragments in a layout with BottomNavigationView使用 BottomNavigationView 在布局中的片段之间切换
【发布时间】:2018-06-04 17:38:14
【问题描述】:

这是我第一次尝试开发安卓应用程序。

我有一个带有底部导航视图的 ConstraintLayout 的 MainActivity。 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).

我在 (Android - fragment .replace() doesn't replace content - puts it on top) 中读到它说“用 XML 编写的静态片段无法替换,它必须在片段容器中”,它看起来如何?

我尝试创建我的片段容器,但是当我尝试获取 ListView(容器的孙子)时出现问题

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

返回空值。

主活动

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 布局

<?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>

片段

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");
        }
    }


}

片段容器

<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>

您的帮助将不胜感激。

【问题讨论】:

    标签: java android firebase android-fragments


    【解决方案1】:

    您需要在MainActivity(activity_main)的布局文件中添加FrameLayout容器,将BottomNavigationView中的按钮的onclick替换为fragment。这样,您就有了一个活动,并且片段显示在活动中,单击每个菜单项,您可以调用以将其替换为片段。 这应该可以解决您的问题。

    您需要在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>
    

    在 MainActivity 代码中,您需要进行如下更改:

    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;
    

    在片段布局文件中改为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>
    

    编辑

    在片段代码中,将布局改为片段布局文件的名称(R.layout.fragment_layout_name)。

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

    【讨论】:

    • 感谢您的回答,但我仍然收到以下错误:尝试在空对象引用上调用虚拟方法 'android.view.View android.view.View.findViewById(int)'。这发生在` View rootView = inflater.inflate(R.layout.activity_main, container, false); //初始化ListView categoriesListView = getView().findViewById(R.id.categoriesList);`被调用
    • 更改为categoriesListView = rootView.findViewById(R.id.categoriesList);
    • 仍然得到与 categoriesListView = rootView.findViewById(R.id.categoriesList); 相同的错误;
    • 我认为它与在完全初始化之前调用根视图有关?我在 View rootView = inflater.inflate(R.layout.activity_main, container, false); 之后的 onCreateView 中调用它;
    • 是的,这是个问题。您必须将其设置为片段布局文件。我已经更新了答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2012-03-12
    • 1970-01-01
    • 2018-07-19
    相关资源
    最近更新 更多