web-dev-qa-db-ja.com

Androidxナビゲーションビュー-「setNavigationItemSelectedListener」が機能しない

私は何をしていますか?

Androidx Navigation Drawer(<com.google.Android.material.navigation.NavigationView>)を使用しようとしています。ドキュメンテーション Here を読みました。これは、アイテムの選択を処理するためにsetNavigationItemSelectedListenerを使用できることを示しています。

注:JetPackのナビゲーションコンポーネントも使用しています。

以下は:main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context=".MainActivity">

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

        <androidx.appcompat.widget.Toolbar
            Android:id="@+id/toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="?attr/actionBarSize"
            Android:background="@color/colorPrimary"
            Android:theme="@style/ThemeOverlay.AppCompat.Dark" />

        <fragment
            Android:id="@+id/nav_Host_fragment"
            Android:name="androidx.navigation.fragment.NavHostFragment"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

    </LinearLayout>

    <com.google.Android.material.navigation.NavigationView
        Android:id="@+id/navigationView"
        Android:layout_width="wrap_content"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        Android:fitsSystemWindows="true"
        app:menu="@menu/drawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>

ここに:MainActivity.Java

import Android.os.Bundle;
import Android.view.MenuItem;
import Android.widget.Toast;

import com.google.Android.material.navigation.NavigationView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.NavigationUI;

public class MainActivity extends AppCompatActivity {

    public Toolbar toolbar;

    public DrawerLayout drawerLayout;

    public NavController navController;

    public NavigationView navigationView;

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

        setupNavigation();

    }

    // Setting Up One Time Navigation
    private void setupNavigation() {

        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        drawerLayout = findViewById(R.id.drawer_layout);

        navigationView = findViewById(R.id.navigationView);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
                return false;
            }
        });

        navController = Navigation.findNavController(this, R.id.nav_Host_fragment);

        NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);

        NavigationUI.setupWithNavController(navigationView, navController);

    }

    @Override
    public boolean onSupportNavigateUp() {
        return NavigationUI.navigateUp(drawerLayout, Navigation.findNavController(this, R.id.nav_Host_fragment));
    }

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

}

状況:

すべてが正常に表示され、実行時にDrawerを取得し、Hamburgerも取得します。メニュー項目でNavigationViewを表示すると正常に動作します。

以下は:drawer_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">

    <group Android:checkableBehavior="single">

        <item
            Android:id="@+id/first"
            Android:icon="@mipmap/ic_launcher"
            Android:title="First" />

        <item
            Android:id="@+id/second"
            Android:icon="@mipmap/ic_launcher"
            Android:title="Second" />

        <item
            Android:id="@+id/third"
            Android:icon="@mipmap/ic_launcher"
            Android:title="Third" />

    </group>

</menu>

問題:

メニュー項目をタップすると、クリックイベントa.k.a onNavigationItemSelectedに応答しません。 MainActivity.Javaを見るとわかるように、Toastは表示されず、スイッチ内で機能するメニューIDもありません。

これを実現するために、多くの例と異なる方法を試してきました。

選択したイベントにメニュー項目を応答させる方法はありますか?

これに関する詳細が必要な場合は、以下のコメントを入力してください。

ヘルプありがとうございます。

9
Unt

私はそれを考え出しました。

誰かがそれを必要とする場合に備えて、ここに投稿しています。

これの代わりに:

navigationView = findViewById(R.id.navigationView);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
        return false;
    }
});

navController = Navigation.findNavController(this, R.id.nav_Host_fragment);

NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);

NavigationUI.setupWithNavController(navigationView, navController);

変更後:

navigationView = findViewById(R.id.navigationView);

navController = Navigation.findNavController(this, R.id.nav_Host_fragment);

NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);

NavigationUI.setupWithNavController(navigationView, navController);

navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
        return false;
    }
});

onNavigationSelectorをアタッチする前にすべてを構成する必要があるかもしれません。

7
Unt

順序を切り替えることの完全な副作用を理解していないかもしれません。

NavigationUI.setupWithNavController(navigationView, navController); // Line 1
navigationView.setNavigationItemSelectedListener({...}) // Line 2

NavigationUIは、NavigationView.OnNavigationItemSelectedListenerLine1NavigationViewに内部的に接続します。 Line 2のカスタムリスナーでそのリスナーをオーバーライドしています。

つまり、navControllerは機能せず、カスタムリスナーですべてのナビゲーションアクションを手動で処理する必要があります。したがって、完全なソリューションは次のようなものになります。

NavigationUI.setupWithNavController(navigationView, navController);

navigationView.setNavigationItemSelectedListener(
        new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {

        // TODO: do stuff
        Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();

        // You need this line to handle the navigation
        boolean handled = NavigationUI.onNavDestinationSelected(menuItem, navController);
        if (handled) {
            ViewParent parent = navigationView.getParent();
            if (parent instanceof DrawerLayout) {
                ((DrawerLayout) parent).closeDrawer(navigationView);
            }
        }

        return handled;
    }
});

注:ナビゲーションアイテムのクリックリスナーをアタッチする以外のことを行うため、カスタムリスナーをアタッチする前にsetupWithNavControllerを呼び出すこともできます。

5
Sanlok Lee

まだ誰かが答えを探している場合、NavigationViewアイテムを処理するためにNavigationControllerだけでなく、NavigationView内で特定のアクションを行うための両方の方法があります。

通常のmenu.xmlファイルのセットアップメニュー項目:

   <menu>
        <item
                Android:id="@+id/fragment_settings"
                Android:icon="@drawable/ic_settings"
                Android:orderInCategory="3"
                Android:title="@string/settings" />

        <item
                Android:id="@+id/share_app"
                Android:icon="@drawable/ic_share"
                Android:orderInCategory="4"
                Android:onClick="shareApp"
                Android:title="@string/share_to_friends" />

        <item
                Android:id="@+id/fragment_about"
                Android:icon="@drawable/ic_info"
                Android:orderInCategory="5"
                Android:title="@string/about" />
    </menu>

最初にonClickメソッド"shareApp""share_app"メニュー項目に定義します。次に、アクティビティで次のようなメソッドを作成します。

fun shareApp(item:MenuItem) {
    logD("share app clicked!")
    val intent = Intent(Intent.ACTION_SEND).apply {
        putExtra(Intent.EXTRA_TEXT, "some text to send...")
        type = "text/*"
    }
    startActivity(Intent.createChooser(intent, "Share app..."))
}

アクティビティのオーバーライドfun onCreate(savedInstanceState:Bundle?)メソッドで、ツールバー、NavigationView、およびDrawerLayoutをNavControllerにアタッチすることを忘れないでください(または必要に応じて)

override fun onCreate(savedInstanceState: Bundle?) {
    setTheme(R.style.AppTheme)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    setupActionBarWithNavController(navController, drawer_layout)
    setupWithNavController(nav_view, navController)
    setupWithNavController(toolbar, navController, drawer_layout)

}