【问题标题】:NavigationView onClick from xml causes errors来自 xml 的 NavigationView onClick 导致错误
【发布时间】:2015-08-13 17:08:33
【问题描述】:

使用新发布的 Android 支持设计库中的 NavigationView,如果导航标题布局包含 onClick(在 xml 中),onClick 事件会使应用程序崩溃。 OnClick 可以通过view.onClickListener(而不是 xml)以编程方式添加,然后单击可以正常工作。但是由于某种原因,每当使用xml onClick 时,都会出现错误。

这是我的主要布局:

<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/mainActivityLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <RelativeLayout
        android:id="@+id/mainContentFrame"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

    </RelativeLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/drawerNavView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/drawer_menu">

    </android.support.design.widget.NavigationView>

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

在我的活动中,我的菜单项点击(添加了navView.setNavigationItemSelectedListener())工作正常。问题是点击标题时:

drawer_header.xml:

...

<View
    android:id="@+id/testButton"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:onClick="testButtonClick"/>

...

产生以下错误:

java.lang.IllegalStateException: Could not find a method testButtonClick(View) 
in the activity class android.view.ContextThemeWrapper for onClick handler
on view class android.view.View with id 'testButton'

更新

NavigationView 可以使用标准的菜单资源文件,但是如果使用菜单 XML 资源中的 onClick 也会出现类似的问题。根据Menu Resource referenceandroid:onClick 属性会覆盖正常的回调。这通常可以正常工作,但对于 NavigationView 中的菜单项,它就不行了。相反,它会因以下错误而崩溃:

java.lang.RuntimeException: Unable to start activity ComponentInfo{...}:
android.view.InflateException: Binary XML file line #34: 
Error inflating class android.support.design.widget.NavigationView

当我删除 XML onClick 时错误消失。

更新

我使用 Android 设计库的“官方”demo project 测试了 xml onClick。结果相同:将 onClick(在 xml 中)添加到 NavigationView 的菜单或标题会导致应用程序崩溃。所以这似乎是 NavigationView 的一个错误。

在 v23.1 中已解决

Google 在 Support Library v23.1 中针对这些 XML onClick 错误发布了 a fix

【问题讨论】:

  • 你在用碎片吗
  • 是的,我正在使用片段和浏览器。
  • 好吧,所以 xml 中的 onclick 在 Activity 中不起作用,因为标题视图位于片段类中,先生,这有意义吗?
  • 我不明白你在说什么。我正在使用 viewpager 和 Fragments,但仅在我的主要内容区域中,而不是在我的抽屉中。我的标题视图通过 XML 添加到新的 NavigationView 小部件。该标头只是另一个 XML 布局文件。我错过了什么吗?
  • 也许this 会让@Elltz 的文字更清晰。

标签: android navigation-drawer android-resources android-design-library navigationview


【解决方案1】:

确认,这是支持库中的错误。

显然是和ContextThemeWrapper有关,根据这个bug report,问题存在于Support Library 22.1。

所以,简短的回答是:

在修复之前,不要将 XML onClick 与 NavigationView(或其他一些组件,如 EditText)一起使用。

解决方法:

在代码中设置点击监听器。对于 NavigationView,请使用 setNavigationItemSelectedListener()

更新:此错误已修复

您现在可以在 Support Library 23.1 (bug report) 中使用 XML onClick。我已经验证它在我的应用程序中有效。但在 v23.1 中,NavView 似乎还有其他(较新的)XML 问题(见下文),即使这个特定的 onClick 错误现已修复。

为了完整性:

通过 XML 扩展 NavigationView 标头时似乎存在另一个(相关?)错误。使用 XML app:headerLayout 会在 23.1 中产生错误,即使 XML onClick 现在可以正常工作。由于这个通货膨胀问题,您需要在代码中使用NavigationView.inflateHeaderView() 方法。这个新方法是在 23.1 中添加的,显然,以前的 XML 膨胀现在被破坏了(或者他们可能在没有告诉任何人的情况下弃用了 app:headerLayout?)。更多信息详解here

【讨论】:

  • 我已经在 setNavigationItemSelected..() 上实现了 switch case。打开各种碎片。它适用于 Phone 布局,但在 twopane layout 上,相同的代码不起作用。默认情况下被触发。表示 MenuItem 的 ID 已更改。
【解决方案2】:

嗨:我的解决方案是删除

app:headerLayout="@layout/drawer_header"

从您的 NavigationView 布局如下:

<android.support.design.widget.NavigationView
    android:id="@+id/drawerNavView"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/drawer_menu">
</android.support.design.widget.NavigationView>

然后在您的活动或视图控制器中使用下面

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View headerView= navigationView.inflateHeaderView(R.layout.nav_header);

TextView tvName = (TextView) headerView.findViewById(R.id.id_nav_header_uname);
tvName.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        L.d("=======tv click=====");
    }
});

这对我有用。

【讨论】:

  • 对不起。正如我在原始帖子中所说,我们显然可以在 Java 中添加 onClick。错误是 onClick 不能在 XML 中工作。无论如何,由于谷歌已经发布了一个错误修复,这一点现在没有实际意义。有关信息,请参阅我更新的帖子。
  • 我看到了谷歌修复的错误,我使用支持库 23.1,但是,它不能添加 onClick,除非你使用navigationView.inflateHeaderView(R.layout.nav_header); 加载视图。通过 xml 无法在 NavigationView 中为 headerView 设置 onClick。
  • 这似乎是另一个通过 XML 膨胀 NavigationView 标头的错误。我在使用 v23.1 时遇到了同样的问题,但是 XML onClick 现在可以正常工作(我已经在我的应用程序中验证了)。只是现在 XML app:headerLayout 坏了,所以你不得不在代码中使用 inflateHeaderView()。这个方法只是在 23.1 中添加的,所以看起来他们在实现中破坏了一些东西。前进一步,后退一步。我上周搜索了有关此 XML app:headerLayout 问题的信息,但没有找到任何信息。也许您想为此发布一个新问题?
  • 哦,自从我上次查看以来,似乎其他人已经发布了有关此膨胀问题的帖子。 stackoverflow.com/a/33163288/3449044
【解决方案3】:

NavigationView 有一个用于菜单项的 OnNavigationItemSelectedListener。

例如

navigationView.setNavigationItemSelectedListener(new SelectedNavigationItemListener());

private class SelectedNavigationItemListener implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {

        switch (menuItem.getItemId()){
            case id1:
                break;
        }

        Log.d("MENU ITEM", menuItem.getTitle().toString());
        return false;
    }

}

对于标题,您可以执行类似的操作,例如

navigationView = (NavigationView) findViewById(R.id.navigation_view);
View header = navigationView.inflateHeaderView(R.layout.drawer_header);
RelativeLayout drawerHeader = (RelativeLayout) header.findViewById(R.id.drawerHeader);
drawerHeader.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("CLICKED HEADER", "Header Clicked");
    }
});

我的 HeaderLayout 参考:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerHeader"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="12dp">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"
    android:textSize="16sp" />

【讨论】:

  • 对不起,我认为你误解了这个问题。我不是在问如何在代码中添加点击监听器。我的问题是为什么 xml onClick 有错误。我很确定这是库中的错误。
【解决方案4】:

您可以在代码中编写您的方法,而无需在 XML 中提及它。在代码中,您只需使用代码

public void methodName()
{
//
}

View v = findViewById(R.id.view_id);
v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
methodName();
}
});

【讨论】:

  • 我知道我可以添加一个 onClickListener,这就是我已经在做的事情来解决这个问题。我想知道为什么 XML onClick 不起作用。我认为这可能是新支持库的错误。
  • @hungryghost 老实说,只要编写代码的方式对我来说看起来更漂亮并且可以正常工作,我就从来没有深入过它。但我会密切关注这篇文章,以防万一我发现一些有趣的事情
  • 编码它工作正常并且很容易。但在我的特定实现中,我实际上会做更复杂的布局交换等,而 XML onClick 会使它稍微容易一些。但这真的不是重点。对我来说,我只是对这个错误感到惊讶。我不知道为什么它不起作用。另外,我可能应该修改我的问题,以更清楚地说明我在问什么。我有一种感觉,除非我更明确,否则我会得到更多“只使用 OnClickLIstener”的答案!
  • @hungryghost 顺便说一句对不起,我做了一个答案。应该是评论。我只是没有 50 名声望,如果它可以帮助我必须回答
  • 哦,没问题。很好,你把它作为一个答案。我会将其标记为正确,但这并不是我真正要问的。我编辑了我原来的问题,以使我在说什么更清楚。祝你好运获得 50 个代表。我会赞成您的评论以提供帮助。快到了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-19
  • 1970-01-01
相关资源
最近更新 更多