【问题标题】:Android: Handling a switch in drawer menuAndroid:处理抽屉菜单中的开关
【发布时间】:2020-08-21 01:54:27
【问题描述】:

我的应用中只有一个用户设置,我想将其放入导航抽屉中,并在给定的菜单项中添加一个开关。

这里是相关的菜单代码:

<item
    android:id="@+id/nav_dark"
    android:checkable="true"
    android:icon="@drawable/round_brightness_4_24"
    android:title="@string/menu_dark"
    app:actionViewClass="android.widget.Switch" />

开关确实出现在菜单项的右侧。

我的听众:

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

    if (item.getItemId() == R.id.nav_dark) {
        // code to apply dark or light theme
        // works as expected
    }
    else {
        // code to handle regular menu items
        // it works too
    }

    return true;
}

我的问题:

  • 当我点击R.id.nav_dark 时,项目被选中。我希望彩色叠加层保留(或跳回)上一个菜单项,其片段实际上显示在抽屉后面。
  • 即使我手动使用item.setChecked(true),开关也没有相应的反应。我希望在启用深色主题时打开开关,并在禁用时关闭。
  • 点击开关本身不会将事件传递给菜单项。我希望它们能够同步工作。

我曾在其他应用程序中看到过类似的复选框和开关,但大多数都在应用程序栏的溢出菜单中。 (我也试过用复选框,但没有区别。)

【问题讨论】:

    标签: android menuitem drawerlayout


    【解决方案1】:

    我使用这个线程解决了这个问题:Switch in Navigation drawer item with Design Support Library on Android

    在此示例中,专用菜单项在浅色和深色主题之间切换,但您当然可以使用它来切换任何设置。

    需要解决的问题

    • 实现我们自己的 onNavigationItemSelected 侦听器,因为 Android Studio 创建的默认解决方案会阻止使用专用菜单项。
    • 实现片段事务和工具栏处理逻辑。
    • 实现开关的onCheckedChange监听器。

    我们所做的是捕获对菜单项的点击。如果是普通物品,我们改变抽屉后面的片段。如果是带有开关的专用项,我们手动切换开关,调用它的监听器。

    实际代码(在这种情况下更改主题)由开关的侦听器处理。如果点击开关本身,就会直接调用监听器。

    来自activity_main_drawer.xml菜单文件的相关代码

    <item
        android:id="@+id/nav_dark"
        android:checkable="true"
        android:icon="@drawable/round_brightness_4_24"
        android:title="@string/menu_dark"
        app:actionViewClass="android.widget.Switch" /> <!-- you can also use a CheckBox -->
    

    来自MainActivity.java的相关代码

    public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, Switch.OnCheckedChangeListener {
    
        private Toolbar toolbar;
        private DrawerLayout drawerLayout;
        private ActionBarDrawerToggle toggle;
        private NavigationView navigationView;
        private Switch switchDark;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            toolbar = findViewById(R.id.toolbar);
            toolbar.setTitle(getResources().getString(R.string.toolbar_title));
            setSupportActionBar(toolbar);
    
            // We have to handle the fragment changes manually, 
            // because what we do conflicts with the default solution created by Android Studio
            drawerLayout = findViewById(R.id.drawer_layout);
            toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            drawerLayout.addDrawerListener(toggle);
            toggle.setDrawerIndicatorEnabled(true);
            toggle.syncState();
    
            navigationView = findViewById(R.id.nav_view);
            // Check the menu item connected to the default fragment manually
            navigationView.getMenu().findItem(R.id.nav_item1).setChecked(true);
            navigationView.setNavigationItemSelectedListener(this); // See below!
    
            switchDark = (Switch)navigationView.getMenu().findItem(R.id.nav_dark).getActionView();
            // Set the default state of the switch connected to the menu item
            switchDark.setChecked(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES);
            switchDark.setOnCheckedChangeListener(this); // See below!
        }
    
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            // Handle the menu item with the switch
            if (item.getItemId() == R.id.nav_dark) {
                ((Switch)item.getActionView()).toggle(); // Call the onCheckedChangeListener of the switch and let it do the work
                return false; // Prevent the menu item to get selected (No overlay indicator will appear)
            }
    
            // Handle the other menu items
            // We have to do this, because we deleted the default solution created by Android Studio
            Fragment newFragment = null;
    
            if (item.getItemId() == R.id.nav_item1) {
                newFragment = new CustomFragment();
                toolbar.setTitle(getResources().getString(R.string.custom_fragment_title));
            }
            else if (item.getItemId() == R.id.nav_item2) {
                newFragment = new OtherFragment();
                toolbar.setTitle(getResources().getString(R.string.other_fragment_title));
            }
    
            // Start the fragment transition manually
            if (newFragment != null) {
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.nav_host_fragment, newFragment);
                transaction.addToBackStack(null);
                transaction.commit();
                drawerLayout.close();
            }
    
            return true; // The selected item will have the overlay indicator
        }
    
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(buttonView.getContext());
            SharedPreferences.Editor editor = sharedPreferences.edit();
    
            int themeID;
            if (isChecked) {
                themeID = AppCompatDelegate.MODE_NIGHT_YES;
            }
            else {
                themeID = AppCompatDelegate.MODE_NIGHT_NO;
            }
    
            AppCompatDelegate.setDefaultNightMode(themeID); // Change the theme at runtime
            editor.putInt("themeID", themeID); // Save it to be remembered at next launch
            editor.apply();
        }
    }
    

    【讨论】:

      【解决方案2】:

      试试这个。

        <item
              app:actionViewClass="androidx.appcompat.widget.SwitchCompat"
              android:icon="@drawable/message"
              android:title="All inboxes"
              android:id="@+id/inbox"
              />
      

      上面这个是我们需要的菜单项

      为了获得点击事件,请遵循以下提到的步骤

              navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
              @Override
              public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                  if (item.getItemId()==R.id.inbox){
                      ((SwitchCompat) item.getActionView()).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                          @Override
                          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                              if (isChecked){
                                  Toast.makeText(buttonView.getContext(), "Checked", Toast.LENGTH_SHORT).show();
                              }
                              else {
                                  Toast.makeText(buttonView.getContext(), "unChecked", Toast.LENGTH_SHORT).show();
                              }
                          }
                      });
                  }
              Toast.makeText(MainActivity.this, ""+item.getTitle(), Toast.LENGTH_SHORT).show();
                  drawerLayout.closeDrawer(GravityCompat.START);
                  return true;
              }
          });
      

      我们已经在 xml 的菜单项中给出了我们的动作类。 我们只需要验证它是哪个项目,当它发生时,我们可以获得我们分配的 actionviewclass 和一个 onclicklistener .. 这个对我有用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多