NavigationView onClick จาก xml ทำให้เกิดข้อผิดพลาด

การใช้ NavigationView จากไลบรารีการออกแบบที่รองรับ Android ที่เพิ่งเปิดตัว หากเค้าโครงส่วนหัวการนำทางมี 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 สามารถใช้ไฟล์ทรัพยากรเมนูมาตรฐานได้ แต่มีปัญหาคล้ายกันหากใช้ onClick จากทรัพยากร XML ของเมนู ตามการอ้างอิงทรัพยากรเมนู แอตทริบิวต์ android: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

อัปเดต

ฉันทดสอบ xml onClick โดยใช้โปรเจ็กต์สาธิต "อย่างเป็นทางการ" สำหรับไลบรารีการออกแบบ Android ผลลัพธ์เดียวกัน: การเพิ่ม onClick (เป็น xml) ลงในเมนูหรือส่วนหัวของ NavigationView ทำให้แอปขัดข้อง ดูเหมือนว่าจะเป็นข้อบกพร่องของ NavigationView

แก้ไขแล้วในเวอร์ชัน 23.1

Google เปิดตัวการแก้ไขสำหรับข้อผิดพลาด XML onClick เหล่านี้ใน Support Library v23 .1.


comment
คุณใช้แฟรกเมนต์หรือไม่   -  person Elltz    schedule 31.05.2015
comment
ใช่ ฉันใช้แฟรกเมนต์และเพจเจอร์   -  person hungryghost    schedule 31.05.2015
comment
ดังนั้น onclick ใน xml จะไม่ทำงานในกิจกรรมเพราะเนื่องจากมุมมองส่วนหัวอาศัยอยู่ในคลาสส่วนย่อย มันสมเหตุสมผลไหม?   -  person Elltz    schedule 31.05.2015
comment
ฉันไม่เข้าใจสิ่งที่คุณกำลังพูด ฉันใช้วิวเพจเจอร์และแฟรกเมนต์ แต่เฉพาะในพื้นที่เนื้อหาหลักของฉันเท่านั้น ไม่ใช่ภายในลิ้นชัก มุมมองส่วนหัวของฉันถูกเพิ่มผ่าน XML ไปยังวิดเจ็ต NavigationView ใหม่ ส่วนหัวนั้นเป็นเพียงไฟล์เค้าโครง XML อีกไฟล์หนึ่ง ฉันพลาดอะไรไปรึเปล่า?   -  person hungryghost    schedule 31.05.2015
comment
บางที สิ่งนี้ อาจทำให้ @Elltz คำพูดที่ชัดเจนยิ่งขึ้น   -  person Simas    schedule 31.05.2015
comment
@Simas ขอบคุณสำหรับลิงก์ แต่ onClick นี้ไม่ได้มาจาก Fragment มันมาจาก NavigationView ในกิจกรรม   -  person hungryghost    schedule 31.05.2015
comment
คุณควรใช้ OnNavigationItemSelectedListener เพราะมันถูกต้อง สะอาด เรียบง่าย และช่วยให้ขยายและแก้ไขโค้ดได้ง่าย เกี่ยวกับปัญหาคุณควรโพสต์สแต็กเทรซทั้งหมด เราสามารถดูซอร์สโค้ดเพื่อรับคำแนะนำหรือส่วนใหญ่อาจจะแก้ไขได้   -  person    schedule 19.06.2015


คำตอบ (4)


ได้รับการยืนยันแล้ว นี่คือจุดบกพร่องในไลบรารีการสนับสนุน

เห็นได้ชัดว่าเกี่ยวข้องกับ ContextThemeWrapper และตามรายงานข้อผิดพลาดนี้ ปัญหามีอยู่ใน Support Library 22.1

คำตอบสั้นๆ คือ:

อย่าใช้ XML onClick กับ NavigationView (หรือส่วนประกอบอื่นๆ เช่น EditText) จนกว่าจะได้รับการแก้ไข

วิธีแก้ปัญหา:

ตั้งค่าตัวฟังการคลิกในโค้ด สำหรับ NavigationView ให้ใช้ setNavigationItemSelectedListener().

อัปเดต: ข้อผิดพลาดนี้ได้รับการแก้ไขแล้ว

ตอนนี้คุณสามารถใช้ XML onClick ใน Support Library 23.1 ได้แล้ว (รายงานข้อบกพร่อง) ฉันตรวจสอบแล้วว่าใช้งานได้ในแอปของฉัน แต่ดูเหมือนว่าจะมีปัญหา XML อื่นๆ (ใหม่กว่า) กับ NavView ในเวอร์ชัน 23.1 (ดูด้านล่าง) แม้ว่าข้อผิดพลาด onClick นี้ได้รับการแก้ไขแล้วก็ตาม

เพื่อความสมบูรณ์:

ดูเหมือนว่าจะมีข้อผิดพลาดอื่น (ที่เกี่ยวข้อง) เมื่อขยายส่วนหัว NavigationView ผ่าน XML การใช้ XML app:headerLayout ทำให้เกิดข้อผิดพลาดกับ 23.1 แม้ว่า XML onClick จะทำงานแล้วก็ตาม เนื่องจากปัญหาเงินเฟ้อ คุณจะต้องใช้วิธี NavigationView.inflateHeaderView() ในโค้ด วิธีการใหม่นี้ถูกเพิ่มเข้ามาใน 23.1 และเห็นได้ชัดว่าการขยาย XML ก่อนหน้านี้ใช้งานไม่ได้แล้ว (หรืออาจเลิกใช้ app:headerLayout โดยไม่บอกใครเลย) รายละเอียดข้อมูลเพิ่มเติมที่นี่

person hungryghost    schedule 05.06.2015
comment
ฉันได้ใช้ตัวพิมพ์สวิตช์บน setNavigationItemSelected..() เพื่อเปิดชิ้นส่วนต่างๆ มันทำงานได้ดีสำหรับรูปแบบโทรศัพท์ แต่เมื่อเป็นรูปแบบ twopane รหัสเดียวกันจะใช้ไม่ได้ กรณีเริ่มต้นจะถูกทริกเกอร์ หมายถึงรหัสสำหรับ MenuItem มีการเปลี่ยนแปลง - person Y2K; 14.09.2015

สวัสดี: โซลูชันของฉันถูกลบออก

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=====");
    }
});

สิ่งนี้ใช้ได้กับฉัน

person Summer    schedule 22.10.2015
comment
ขอโทษ. อย่างที่ผมบอกไปในโพสต์ต้นฉบับว่า เราสามารถเพิ่ม onClick ใน Java ได้อย่างชัดเจน จุดบกพร่องคือ onClick ไม่ทำงานจาก XML อย่างไรก็ตาม จุดนี้ยังเป็นที่น่าสงสัยเนื่องจาก Google ได้ออกการแก้ไขข้อบกพร่องแล้ว ดูโพสต์ที่อัปเดตของฉันสำหรับข้อมูล - person hungryghost; 23.10.2015
comment
ฉันเห็นข้อผิดพลาดที่ Google แก้ไขแล้ว ฉันใช้ Support Library 23.1 แต่ไม่สามารถเพิ่ม onClick ได้เว้นแต่คุณจะใช้ navigationView.inflateHeaderView(R.layout.nav_header); เพื่อโหลดมุมมอง ผ่าน xml ไม่สามารถตั้งค่า onClick ใน NavigationView สำหรับ headerView - person Summer; 23.10.2015
comment
นั่นดูเหมือนจะเป็นข้อบกพร่องอีกประการหนึ่งที่ทำให้ส่วนหัว NavigationView ขยายตัวผ่าน XML ฉันมีปัญหาเดียวกันกับเวอร์ชัน 23.1 แต่ตอนนี้ XML onClick ทำงานได้ดี (ฉันได้ตรวจสอบในแอปของฉันแล้ว) เพียงแต่ว่าตอนนี้ XML app:headerLayout ใช้งานไม่ได้ ดังนั้นคุณจึงถูกบังคับให้ใช้ inflateHeaderView() ในโค้ด วิธีการนี้เพิ่งเพิ่มเข้ามาในเวอร์ชั่น 23.1 ดูเหมือนว่ามันจะทำลายบางสิ่งในการใช้งาน ก้าวไปข้างหน้าหนึ่งก้าวถอยหลังหนึ่งก้าว ฉันค้นหาข้อมูลเกี่ยวกับปัญหา XML app:headerLayout นี้เมื่อสัปดาห์ที่แล้ว แต่ไม่พบอะไรเลย บางทีคุณอาจต้องการโพสต์คำถามใหม่เกี่ยวกับเรื่องนี้? - person hungryghost; 23.10.2015
comment
โอ้ ดูเหมือนว่าคนอื่นจะโพสต์เกี่ยวกับปัญหาที่เพิ่มขึ้นนี้แล้วตั้งแต่ฉันดูครั้งล่าสุด stackoverflow.com/a/33163288/3449044 - person hungryghost; 23.10.2015

คุณสามารถเขียนวิธีการของคุณเป็นโค้ดโดยไม่ต้องกล่าวถึงใน XML ในรหัสคุณเพียงแค่ใช้รหัส

public void methodName()
{
//
}

View v = findViewById(R.id.view_id);
v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
methodName();
}
});
person Vendetta8247    schedule 31.05.2015
comment
ฉันรู้ว่าสามารถเพิ่ม onClickListener ได้ และนั่นคือสิ่งที่ฉันกำลังทำอยู่แล้วเพื่อแก้ไขปัญหานี้ ฉันสงสัยว่าเหตุใด XML onClick จึงไม่ทำงาน ฉันคิดว่าอาจเป็นจุดบกพร่องกับไลบรารีการสนับสนุนใหม่ - person hungryghost; 31.05.2015
comment
@hungryghost พูดตามตรงว่าฉันไม่เคยสนใจมันมากนักตราบใดที่วิธีการเข้ารหัสในการทำมันดูสวยกว่าสำหรับฉันและมันก็ใช้ได้ผล แต่ฉันจะจับตาดูโพสต์นี้เผื่อฉันพบสิ่งที่น่าสนใจ - person Vendetta8247; 31.05.2015
comment
การเขียนโค้ดทำงานได้ดีและง่ายพอ แต่ในการใช้งานเฉพาะของฉัน จริงๆ แล้วฉันจะทำการสลับเลย์เอาต์ที่ซับซ้อนกว่านี้ และ XML onClick จะทำให้ง่ายขึ้นเล็กน้อย แต่นั่นไม่ใช่ประเด็นจริงๆ สำหรับฉัน ฉันแค่แปลกใจกับข้อผิดพลาดนี้ ฉันไม่รู้ว่าทำไมมันไม่ทำงาน นอกจากนี้ ฉันควรแก้ไขคำถามเพื่อให้ชัดเจนยิ่งขึ้นในสิ่งที่ฉันถาม ฉันรู้สึกว่าฉันจะได้รับมากขึ้นเพียงแค่ใช้คำตอบของ OnClickLIstener เว้นแต่ว่าฉันจะชัดเจนกว่านี้! - person hungryghost; 31.05.2015
comment
@hungryghost ขออภัยที่ฉันตอบ มันควรจะเป็นความคิดเห็น ฉันแค่ไม่มีชื่อเสียง 50 และเผื่อว่าจะช่วยได้ฉันต้องตอบ - person Vendetta8247; 31.05.2015
comment
โอ้ ไม่มีปัญหา ไม่เป็นไรคุณตอบได้แล้ว ฉันจะทำเครื่องหมายว่าถูกต้อง แต่ก็ไม่ใช่สิ่งที่ฉันถามจริงๆ ฉันแก้ไขคำถามเดิมเพื่อให้ชัดเจนยิ่งขึ้นว่าฉันกำลังพูดถึงอะไร โชคดีที่ได้ 50 ครั้ง ฉันจะโหวตความคิดเห็นของคุณเพื่อช่วย เกือบจะมี! - person hungryghost; 31.05.2015

NavigationView มี OnNavigationItemSelectedListener สำหรับรายการเมนู

e.g.

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;
    }

}

สำหรับ Header คุณสามารถทำสิ่งนี้ได้เช่น

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" />

person Hiroga Katageri    schedule 04.06.2015
comment
ขออภัย ฉันคิดว่าคุณเข้าใจคำถามผิด ฉันไม่ได้ถามวิธีเพิ่มตัวฟังการคลิกในโค้ด คำถามของฉันคือเหตุใดจึงมีข้อผิดพลาดกับ xml onClick ฉันค่อนข้างแน่ใจว่ามันเป็นข้อบกพร่องในห้องสมุด - person hungryghost; 04.06.2015