Android 具有多个 Activity 的导航抽屉

Android Navigation Drawer with multiple Activity

我正在尝试创建一个带有导航抽屉的 BaseActivity 并将其扩展到其他活动中,以便我可以重用导航抽屉代码。

到目前为止我发现了什么:

但是,当我的 activity(示例 activityA)中有一个按钮并且我想加载另一个 activity(activityB)时,通过单击该按钮显示敬酒等,除非我在 BaseActivity 的 onCreate 方法中为侦听器编写代码,否则单击侦听器不起作用。

对我来说这没有意义,因为它迫使我在 BaseActivity 中编写所有代码,这不是编写代码的最有效方式(活动就像片段一样,所以我只能使用片段代替)。

我想知道的是,如何在扩展 BaseActivity 的所有活动上加载导航抽屉,并且仍然允许活动保留其行为。

代码示例

我的activity_home.xml (BaseActivity)

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity"
tools:openDrawer="start"
android:fitsSystemWindows="true">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <include
        android:id="@+id/custom_tool"
        layout="@layout/custom_bar"/>


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

<android.support.design.widget.NavigationView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/nav_display"
    app:menu="@menu/nav_drawer_menu"
    android:layout_gravity="start"
    app:headerLayout="@layout/nav_header"/>

</android.support.v4.widget.DrawerLayout>

activity_main.xml (activityA)

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

<ImageView
    android:id="@+id/imageView"
    android:layout_width="0dp"
    android:layout_height="147dp"
    android:layout_marginStart="105dp"
    android:layout_marginLeft="105dp"
    android:layout_marginTop="150dp"
    android:layout_marginEnd="105dp"
    android:layout_marginRight="105dp"
    android:layout_marginBottom="48dp"
    android:contentDescription="@string/app_logo"
    app:layout_constraintBottom_toTopOf="@+id/search_bar"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="1.0"
    app:srcCompat="@mipmap/ic_launcher" />


<SearchView
    android:id="@+id/search_bar"
    android:layout_width="0dp"
    android:layout_height="48dp"
    android:layout_marginStart="50dp"
    android:layout_marginLeft="50dp"
    android:layout_marginTop="48dp"
    android:layout_marginEnd="50dp"
    android:layout_marginRight="50dp"
    android:layout_marginBottom="50dp"
    android:background="@drawable/input_default"
    android:gravity="center"
    app:layout_constraintBottom_toTopOf="@+id/search_button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/imageView" />

<Button
    android:id="@+id/search_button"
    android:layout_width="0dp"
    android:layout_height="48dp"
    android:layout_marginStart="150dp"
    android:layout_marginLeft="150dp"
    android:layout_marginTop="50dp"
    android:layout_marginEnd="150dp"
    android:layout_marginRight="150dp"
    android:layout_marginBottom="228dp"
    android:background="@drawable/button_default"
    android:text="@string/search"
    android:textColor="@color/colorAccent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/search_bar" />

</android.support.constraint.ConstraintLayout>

当应用程序最初加载时,BaseActivity 的“main_content”会被 activity_main 布局膨胀。

当我单击 activity_main.xml 中的 search_button 时,我想加载另一个 activity,这只有在我在基础 activity 中编写代码时才会发生.

HomeActivity

package com.example.naisse;


import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

public class HomeActivity extends AppCompatActivity {

protected static int position;
private DrawerLayout drawer;
protected FrameLayout frames;

Button searchButton;
/**
 *  This flag is used just to check that launcher activity is called first time
 *  so that we can open appropriate Activity on launch and make list item position selected accordingly.
 * */
private static boolean isLaunch = true;

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

    Toolbar toolbar = findViewById(R.id.custom_tool);
    setSupportActionBar(toolbar);

    drawer = findViewById(R.id.drawer_layout);

    frames = findViewById(R.id.main_container);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();


    /*inflating the layout with activity_main*/
    getLayoutInflater().inflate(R.layout.activity_main, frames);



    searchButton = findViewById(R.id.search_button);

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

            /*removing the activity_main and inflating they layout with activity_result*/
            frames.removeAllViews();
            getLayoutInflater().inflate(R.layout.activity_result, frames);
        }
    });
}

@Override
public void onBackPressed() {
    if(drawer.isDrawerOpen(GravityCompat.START)){
        drawer.closeDrawer(GravityCompat.START);
    }else{
        super.onBackPressed();
    }
}
}

用 HomeActivity 扩展 MainActivity

MainActivity

package com.example.naisse;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends HomeActivity {



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


}

}

如何解决这个问题?

答案和理解请看我和Mike M的讨论

我最初做的是用布局膨胀 "main_container",因此 Activity class 没有被触发。为此,我必须重写 BaseActivity 中的 setContentView() 方法(在我的例子中是 HomeActivity )并放置所有可共享的代码,例如工具栏和里面的导航抽屉。

我的新HomeActivity.class

public class HomeActivity extends AppCompatActivity {

private DrawerLayout drawer;
protected FrameLayout frames;

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

@Override
public void onBackPressed() {
    if(drawer.isDrawerOpen(GravityCompat.START)){
        drawer.closeDrawer(GravityCompat.START);
    }else{
        super.onBackPressed();
    }
}


@Override
public void setContentView(int layoutResID) {
    // Set the base layout
    super.setContentView(R.layout.activity_home);

    // Find the content container
    frames = findViewById(R.id.main_container);

    // Inflate the extending Activity's layout into it
    getLayoutInflater().inflate(layoutResID, frames);

    // The rest of the base setup
    Toolbar toolbar = findViewById(R.id.custom_tool);
    setSupportActionBar(toolbar);

    drawer = findViewById(R.id.drawer_layout);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
}

}

现在所有活动共享工具栏和导航抽屉。

我很惊讶这么多年来很少有人对此感兴趣。在所有活动的 xml 文件中维护 DrawerLayout 内容的重复代码非常愚蠢。

我尝试了@Mill3r 的自我回答,不幸的是覆盖 setContentView 与数据绑定冲突并导致崩溃。

我在基础 activity 中创建了一个方法,而不是 setContentView,例如:

public void setContent(View contentView) {
    // Find the content container
    frames = findViewById(R.id.main_container);

    frames.removeAllViews();
    frames.addView(contentView);

    // The rest of the base setup
    Toolbar toolbar = findViewById(R.id.custom_tool);
    setSupportActionBar(toolbar);

    drawer = findViewById(R.id.drawer_layout);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
}

然后在所有从base deried的activity中,设置databinding后调用这个函数,如:

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
setContent(binding.getRoot());