【问题标题】:Drawer Layout not closing on back pressed (depending on support-v4 lib)抽屉布局未在后按时关闭(取决于 support-v4 lib)
【发布时间】:2020-10-24 19:33:03
【问题描述】:

我正在关注Creating a Navigation Drawer tutorial (Android Training)

我已经下载了示例应用程序,它可以按预期工作。我打开抽屉,向后按,它就关上了。

当我在Android-SDK/extras/android/support/v4/android-support-v4.jar(大小为 741 KB)中将lib/android-support-v4.jar(最初大小为 523 KB)替换为更新版本(修订版 20)时,问题就出现了。更换后,如果我打开抽屉然后按下设备的后退按钮,应用程序将关闭而不是关闭抽屉。

我该如何解决?我应该保留旧的 android-support-v4.jar 版本还是应该在需要时以编程方式拦截关闭抽屉的后退按钮?

更新:我一直在测试问题,为此我在 AndroidStudio 中构建了项目。复制示例应用程序(src、res 和更新清单)后运行它:即使 DrawerLayout 打开,后退按钮也会关闭应用程序。 然后我修改了build.gradle文件改行:

compile 'com.android.support:appcompat-v7:20.0.0'

compile 'com.android.support:appcompat-v7:19.0.0'

问题消失了:后退按钮先关闭抽屉,然后关闭应用程序

活动的完整代码(Link to the Android Training Source Code)

public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private String[] mPlanetTitles;

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

        mTitle = mDrawerTitle = getTitle();
        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        // set up the drawer's list view with items and click listener
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        // enable ActionBar app icon to behave as action to toggle nav drawer
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description for accessibility */
                R.string.drawer_close  /* "close drawer" description for accessibility */
                ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                //supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                //supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
            selectItem(0);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    /* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
         // The action bar home/up action should open or close the drawer.
         // ActionBarDrawerToggle will take care of this.
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle action buttons
        switch(item.getItemId()) {
        case R.id.action_websearch:
            // create intent to perform web search for this planet
            Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
            intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());
            // catch event that there's no activity to handle intent
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(intent);
            } else {
                Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /* The click listner for ListView in the navigation drawer */
    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    private void selectItem(int position) {
        // update the main content by replacing fragments
        Fragment fragment = new PlanetFragment();
        Bundle args = new Bundle();
        args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
        fragment.setArguments(args);

        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

        // update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        setTitle(mPlanetTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    /**
     * Fragment that appears in the "content_frame", shows a planet
     */
    public static class PlanetFragment extends Fragment {
        public static final String ARG_PLANET_NUMBER = "planet_number";

        public PlanetFragment() {
            // Empty constructor required for fragment subclasses
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_planet, container, false);
            int i = getArguments().getInt(ARG_PLANET_NUMBER);
            String planet = getResources().getStringArray(R.array.planets_array)[i];

            int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
                            "drawable", getActivity().getPackageName());
            ((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId);
            getActivity().setTitle(planet);
            return rootView;
        }
    }
}

【问题讨论】:

  • 请把你的一些代码放在这里?
  • 已更新代码,但与您在第一个链接中按“下载示例应用程序”时得到的完全相同
  • 你确定库导入正确吗???
  • 是的,用eclipse复制粘贴到lib文件夹中:P
  • 这个答案和赞成的评论有帮助吗? - stackoverflow.com/a/18997280/1256219

标签: java android android-support-library


【解决方案1】:

将支持库升级到 20.0.0 后,我遇到了完全相同的问题。

在下面添加一行代码可以解决我的问题。 (在我的活动中创建)

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

    mDrawerLayout = (DrawerLayout) this.findViewById(R.id.drawer_layout);
    mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); /* add this line */

    ....
}

【讨论】:

  • 今天在支持库 v21 上测试,同样的问题仍然存在,同样的修复在我的项目中仍然有效。
  • mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 在 DrawerLayout 层次结构中的某处有 EditView 时阻止键盘打开,因为 EditView 不会获得焦点。
【解决方案2】:

这里有一个快速解决您的问题的方法。只需覆盖 Activity / Fragment 中的 onBackPressed() 方法即可:

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

左侧抽屉使用Gravity.START,右侧抽屉使用Gravity.END

【讨论】:

  • 我确定支持库是问题所在,事实上我可以看到问题是如何消失并在库之间交换时回来的
【解决方案3】:

在 setUpNavDrawer 中

mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

还有

@Override
public void onBackPressed()
{
  if (mDrawerLayout.isOpen())
    mDrawerLayout.close();
  else
    super.onBackPressed();
}

【讨论】:

  • 值得注意的是,阻止对抽屉后代的关注也会阻止所有其他 UI 元素,即使在抽屉关闭时也是如此。这意味着一旦您设置了这种后代可聚焦性,所有文本输入都会被阻止。
  • 正如@SDJMcHattie 所说,如果您有编辑文本或任何其他视图,它不会对焦点做出反应。
【解决方案4】:

不推荐使用mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 的解决方案,因为如果您对活动进行了TextEdit,您将无法获得焦点。最好使用前面提到的onBackPressed() 解决方案。

@Override
public void onBackPressed()
{
  if (mDrawerLayout.isOpen())
    mDrawerLayout.close();
  else
    super.onBackPressed();
}

【讨论】:

    【解决方案5】:

    右键单击您的项目单击属性并转到 java 构建路径并检查您想要的库是否存在并且没有不需要的库..如果您更改 supportlibrary v4,我建议您在 appcompat v7 库中更改它。 . 其次

    onDrawerOpened
    

    是当drawerlayout完全出现在你的用户界面上时,如果它没有完全出现,则活动将被关闭。..

    请在文档站点的代码中重新检查这些内容

    The main content view (the FrameLayout above) must be the first child in the 
    DrawerLayout because the XML order implies z-ordering and the drawer must be 
    on top of the content.
    The main content view is set to match the parent view's width and height,
    because it represents the entire UI when the navigation drawer is hidden.
    The drawer view (the ListView) must specify its horizontal gravity with the 
    android:layout_gravity attribute. To support right-to-left (RTL) languages,
    specify the value with "start" instead of "left" (so the drawer appears on
    the right when the layout is RTL).
    The drawer view specifies its width in dp units and the height matches 
    the parent view. The drawer width should be no more than 320dp so the
    user can always see a portion of the main content.
    

    最后我看到你正在使用支持库,如果你使用支持库,你不应该使用活动,你应该使用 ActiobBarActivity 或 FragmentActivity

    【讨论】:

      【解决方案6】:

      这里的焦点是一个问题,但实际上并不是孩子窃取了抽屉布局(ActionBar/Toolbar)上方的父母的焦点。

      我在MainActivity.class 中使用了与此非常相似的方法:

      @Override
      public void onBackPressed() {
          if (mDrawerLayout.isDrawerVisible(Gravity.START)) {
              mDrawerLayout.closeDrawer(Gravity.START);
              return;
          }
          super.onBackPressed();
      }
      

      【讨论】:

        【解决方案7】:

        试试这个修复:

        mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
        

        ...

        mDrawerLayout.setDrawerListener(new DrawerListener() {
        
            @Override
            public void onDrawerStateChanged(int arg0) {
        
            }
        
            @Override
            public void onDrawerSlide(View arg0, float arg1) {
        
            }
        
            @Override
            public void onDrawerOpened(View view) {
                mDrawerLayout.post(new Runnable() {
        
                    @Override
                    public void run() {
                        // request the focus to correctly process pressed
                        // back key
                        mDrawerLayout.requestFocus();
                    }
                });
            }
        
            @Override
            public void onDrawerClosed(View arg0) {
            }
        });
        

        【讨论】:

          【解决方案8】:

          工作没有任何警告

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

          【讨论】:

            【解决方案9】:

            初始化这个

              navigationView.setNavigationItemSelectedListener(this)
                    actionBarToggle = ActionBarDrawerToggle(this, drawerLayout, 0, 0)
                    drawerLayout.addDrawerListener(actionBarToggle)
                    supportActionBar?.setDisplayHomeAsUpEnabled(true)
                    actionBarToggle.syncState()
            

            那就用这个方法处理

            override fun onSupportNavigateUp(): Boolean {
                    if (this.drawerLayout.isDrawerOpen(GravityCompat.START)) {
                        this.drawerLayout.closeDrawer(GravityCompat.START)
                    } else {
                        this.drawerLayout.openDrawer(GravityCompat.START)
                    }
                    return true
                }
            

            【讨论】:

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