【问题标题】:Android Jetpack Navigation - Custom Action with Drawer ItemAndroid Jetpack 导航 - 带有抽屉项的自定义操作
【发布时间】:2018-10-08 10:07:39
【问题描述】:

我将新的Jetpack Android Navigation 与抽屉布局结合使用。将 Drawer XML 中的相同 ID 与 Navigation Graph 中的 Fragments 结合使用时,一切都按预期工作。我设置了一切:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val navController = findNavController(R.id.navigation_host_fragment)
        setupActionBarWithNavController(navController, find(R.id.drawer_layout))
        val navigationView = findViewById<NavigationView>(R.id.nav_view)
        navigationView.setupWithNavController(findNavController(R.id.navigation_host_fragment))
}

我现在还想在单击抽屉菜单中的项目时触发自定义操作/代码并且不执行片段事务。 我有以下菜单,想在点击“退出”时退出用户

【问题讨论】:

标签: android navigation-drawer android-jetpack android-architecture-navigation


【解决方案1】:

我找到了解决办法:

val navigationView = findViewById<NavigationView>(R.id.nav_view)
val logoutItem = navigationView.menu.findItem(R.id.nav_logout)
logoutItem.setOnMenuItemClickListener {
     toast("Log me out")
     true
}

【讨论】:

  • 最佳解决方案,尤其是当您想将其与图形结合起来并且不想手动处理片段时。
【解决方案2】:

我也找到了解决办法。

首先,您需要创建自定义 NavigationUI。

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.navigation.NavigationView;

import java.lang.ref.WeakReference;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import androidx.navigation.ui.NavigationUI;

public class CustomNavigationUI {

    public static void setupWithNavController(@NonNull final NavigationView navigationView,
                                              @NonNull final NavController navController,
                                              @Nullable final NavigationView.OnNavigationItemSelectedListener customListener) {
        navigationView.setNavigationItemSelectedListener(
                item -> {
                    boolean handled = NavigationUI.onNavDestinationSelected(item, navController);
                    if (handled) {
                        ViewParent parent = navigationView.getParent();
                        if (parent instanceof DrawerLayout) {
                            ((DrawerLayout) parent).closeDrawer(navigationView);
                        } else {
                            BottomSheetBehavior bottomSheetBehavior =
                                    findBottomSheetBehavior(navigationView);
                            if (bottomSheetBehavior != null) {
                                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
                            }
                        }
                    } else {
                        if (customListener != null) {
                            customListener.onNavigationItemSelected(item);
                        }
                    }
                    return handled;
                });
        final WeakReference<NavigationView> weakReference = new WeakReference<>(navigationView);
        navController.addOnDestinationChangedListener(
                new NavController.OnDestinationChangedListener() {
                    @Override
                    public void onDestinationChanged(@NonNull NavController controller,
                                                     @NonNull NavDestination destination, @Nullable Bundle arguments) {
                        NavigationView view = weakReference.get();
                        if (view == null) {
                            navController.removeOnDestinationChangedListener(this);
                            return;
                        }
                        Menu menu = view.getMenu();
                        for (int h = 0, size = menu.size(); h < size; h++) {
                            MenuItem item = menu.getItem(h);
                            item.setChecked(matchDestination(destination, item.getItemId()));
                        }
                    }
                });
    }

    static BottomSheetBehavior findBottomSheetBehavior(@NonNull View view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
            ViewParent parent = view.getParent();
            if (parent instanceof View) {
                return findBottomSheetBehavior((View) parent);
            }
            return null;
        }
        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
                .getBehavior();
        if (!(behavior instanceof BottomSheetBehavior)) {
            // We hit a CoordinatorLayout, but the View doesn't have the BottomSheetBehavior
            return null;
        }
        return (BottomSheetBehavior) behavior;
    }

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    static boolean matchDestination(@NonNull NavDestination destination,
                                    @IdRes int destId) {
        NavDestination currentDestination = destination;
        while (currentDestination.getId() != destId && currentDestination.getParent() != null) {
            currentDestination = currentDestination.getParent();
        }
        return currentDestination.getId() == destId;
    }

}

其次,在Activity中调用这个CustomNavigationUI而不是NavigationUI

/* NavigationUI.setupWithNavController(binding.navigationView, navController); */
CustomNavigationUI.setupWithNavController(binding.navigationView, navController, item -> {
            switch (item.getItemId()){
                case R.id.sign_out:
                    //todo sign out
                    break;
            }
            return true;
        });

就是这样!

【讨论】:

    【解决方案3】:

    我在 Kotlin 中编写了那个扩展函数来解决这个问题:

    fun NavigationView.setSafeNavigationItemSelectedListener(vararg listener: Pair<Int, () -> Unit>) =
    listener.forEach { (itemId, act) ->
        menu.findItem(itemId)?.setOnMenuItemClickListener { act(); true }
    }
    

    可以如下使用:

        val navigationView = findViewById<NavigationView>(R.id.nav_view)
        navigationView.setSafeNavigationItemSelectedListener(
            R.id.shareIntent to {
                shareIntent()
                drawerLayout.closeDrawer(GravityCompat.START)
            },
            R.id.mySchedulesIntent to {
                val i = Intent(this, MySchedulesActivity::class.java)
                startActivity(i)
                drawerLayout.closeDrawer(GravityCompat.START)
            },
            R.id.importantDetailsIntent to {
                displayImportantDetailsDialog()
                drawerLayout.closeDrawer(GravityCompat.START)
            },
            R.id.infoIntent to {
                val i = Intent(this, InfoActivity::class.java)
                startActivity(i)
                drawerLayout.closeDrawer(GravityCompat.START)
            },
            R.id.settingsIntent to {
                val i = Intent(this, SettingsActivity::class.java)
                startActivity(i)
                drawerLayout.closeDrawer(GravityCompat.START)
            },
        )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 2020-01-18
      • 2020-07-20
      • 1970-01-01
      相关资源
      最近更新 更多