MenuItemCompat.getActionView จะส่งคืนค่าว่างเสมอ


142

ฉันเพิ่งติดตั้งv7 AppCompatไลบรารีการสนับสนุน แต่MenuItemCompat.getActionViewผลตอบแทนจะเป็นโมฆะใน Android ทุกรุ่นที่ฉันทดสอบ (4.2.2, 2.3.4 .... )

SearchViewจะแสดงในแถบการทำงาน แต่ก็ไม่ได้ตอบสนองต่อการสัมผัสการกระทำและไม่ขยายเพื่อแสดงตนEditTextและเป็นเช่นเดียวกับไอคอนที่เรียบง่าย

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

    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
    if (searchView != null) {
        SearchViewCompat.setOnQueryTextListener(searchView, mOnQueryTextListener);
        searchView.setIconifiedByDefault(false);
        Log.d(TAG,"SearchView not null");
    } else
        Log.d(TAG, "SearchView is null");
    }
    return super.onCreateOptionsMenu(menu);
}

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/action_search"
          app:showAsAction="always|collapseActionView"
          android:icon="@drawable/abc_ic_search"
          android:title="@string/action_bar_search"
          android:actionViewClass="android.support.v7.widget.SearchView"/>

    <item android:id="@+id/action_refresh"
          android:icon="@drawable/refresh"
          android:title="@string/action_bar_refresh"
          app:showAsAction="ifRoom"/>
</menu>

คำตอบ:


296

ในที่สุดฉันก็พบทางออก

  1. การเปลี่ยนเนมสเปซของactionViewClassจากandroid:actionViewClassเป็นapp:actionViewClass

  2. การนำandroid.support.v7.widget.SearchView.OnQueryTextListenerอินเตอร์เฟสไปใช้ สำหรับกิจกรรมปัจจุบัน

  3. ใช้โดยตรงsetOnQueryTextListenerแทนSearchViewCompat.setOnQueryTextListener

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.menu, menu);
    
      MenuItem searchItem = menu.findItem(R.id.action_search);
      SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
      if (searchView != null) {
         searchView.setOnQueryTextListener(this);
      }
    
      return super.onCreateOptionsMenu(menu);
    }
    

3
หากวิธีนี้ช่วยแก้ไขปัญหาของคุณได้คุณควรยอมรับคำตอบของคุณ ผมยังต้องการที่จะชี้ให้ทุกคนที่อื่น ๆ ที่มีปัญหาที่คล้ายกันให้เป็นหนึ่งในหัวข้อการหารือเรื่องอื่น ๆ ที่คล้ายกัน: stackoverflow.com/q/18407171/1108032 หากเธรดปัจจุบันไม่สามารถแก้ไขปัญหาของคุณลองพิจารณาวิธีแก้ไขที่นั่น
Boris Strandjev

4
คำตอบที่ดี! อาจจ่ายให้ชัดเจนเช่นกันว่า "แอป" ในแอป: actionViewClass ยังต้องมีการประกาศ xmlns เพิ่มเติมสำหรับเนมสเปซ "แอป"
jklp

3
จำเป็นต้องพูดว่าandroid.support.v7.widget.SearchViewคลาสไม่ควรสับสนกับคลาส 'android.support.v4.widget.SearchViewCompat' (ซึ่งเป็นที่รู้จักกันว่าเป็นข้อผิดพลาดทั่วไปเมื่อใช้ไลบรารี ActionBarCompat)
Alex Semeniuk

1
@jklp ฉันพยายามที่จะเพิ่ม xmlns ประกาศแต่รับข้อผิดพลาด<menu xmlns:app="http://schemas.android.com/apk/res/android" > Attribute is missing the Android namespace prefixคุณได้รับมันและคุณจะแก้ไขได้อย่างไร
anticafe

5
โปรดทราบว่า Android: showAsAction จำเป็นต้องเปลี่ยนเป็นแอป: showAsAction เช่นกัน ตรวจสอบให้แน่ใจว่าชุดรูปแบบของคุณสำหรับกิจกรรม (ไม่ใช่เฉพาะแอปพลิเคชัน) คือการอ้างอิงถึงธีมของ appcompat สิ่งสุดท้ายที่แอปประกาศคือ " schemas.android.com/apk/res-auto "
Kalel Wade

85

ในกรณีของฉันมันเป็นไฟล์ ProGuard คุณต้องเพิ่มบรรทัดนี้:

-keep class android.support.v7.widget.SearchView { *; }

2
ว้าวทำไมเป็นสิ่งนี้ นี่เป็นสิ่งเดียวที่ทำงานให้ฉัน
Claud

2
+1 ค่อนข้างชัดเจน แต่ฉันจะพูดถึง - ในกรณีที่คุณขยาย SearchView ไปยังคลาสอื่นให้เก็บเส้นทางไปยังคลาสนั้นใน proguard!
2520215

42

สำหรับฉันmenu.xmlการนำเข้าเนมสเปซที่ไม่ถูกต้องทำให้เกิดปัญหานี้

ต้นฉบับของฉันmenu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/tools">
        <item android:id="@+id/action_search"
              android:title="@string/map_option_search"
              android:icon="@drawable/ic_action_search"
              app:showAsAction="collapseActionView|ifRoom"
              app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

ดูเหมือนว่าxmlns:app="http://schemas.android.com/tools"เป็นสาเหตุที่จะกลับมาMenuItemCompat.getActionView() nullการเปลี่ยนการนำเข้านี้เพื่อxmlns:app="http://schemas.android.com/apk/res-auto"แก้ไขปัญหา

ใหม่ที่ทำงานmenu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
       <item android:id="@+id/action_search"
              android:title="@string/map_option_search"
              android:icon="@drawable/ic_action_search"
              app:showAsAction="collapseActionView|ifRoom"
              app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

5

ฉันคิดว่าปัญหาคือคุณใช้ SearchView จากแพ็คเกจ Support V7 และบางทีระดับ API ของคุณอาจถูกตั้งเป็น ..... 22 ??

การเปลี่ยนรหัสของคุณเป็นสิ่งต่อไปนี้เพื่อแก้ไขปัญหา:

menu.xml

<?xml version="1.0" encoding="UTF-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item 
        android:id="@+id/action_search"
        android:icon="@drawable/actionbar_button_search"
        android:title="Search"
        android:showAsAction="always"
        android:actionViewClass="android.widget.SearchView" />
</menu> 

1
คุณช่วยอธิบายได้หรือไม่ว่าทำไมตัวอย่างโค้ดที่คุณให้เพื่อแก้ปัญหา (ฉันถือว่ามันใช้ได้)
เอ็ดการ์ N

4

ฉันมีข้อผิดพลาดเดียวกันวิธีการของฉันgetActionView()คืนค่าว่างเสมอ ดังนั้นฉันทำสิ่งต่อไปนี้:

<item android:id="@+id/action_search"
      android:icon="@drawable/abc_ic_search"
      android:title="@string/search_title"
      android:showAsAction="always"
      android:actionViewClass="android.widget.SearchView"/>

ผมเห็นในโพสต์บางอย่างที่คนที่มีการใช้ app หรือ yourapp android:ActionVewClassแต่ฉันได้ใช้ตามปกติ

ในonCreateOptionsMenuวิธีการของฉัน:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.feed, menu);

    // Associate searchable configuration with the SearchView
    SearchManager searchManager = 
        (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.action_search)
            .getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));

    return true;
}

และอย่าลืมใส่ในonCreateวิธีการ:

// enabling action bar app icon and behaving it as toggle button
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);

นี้ทำงานได้เป็นอย่างดีสำหรับกิจกรรมของฉัน "ขยาย" สำหรับและFragmentActivityActionBarActivity


2

คำตอบของ Mohsen Afshin ด้านบนเป็นจุดเริ่มต้นของฉันและฉันได้ปรับแต่งบางอย่างเพื่อให้มันทำงานกับการตั้งค่าของฉัน:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    // SearchView searchView = (SearchView) MenuItemCompat
    //    .getActionView(searchItem);
    SearchView searchView = (SearchView) searchItem.getActionView();
    if (searchView != null) {
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                // do something with s, the entered string
                query = s;
                Toast.makeText(getApplicationContext(), 
                    "String entered is " + s, Toast.LENGTH_SHORT).show();
                return true;
            }
            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });
    }
    return super.onCreateOptionsMenu(menu);
}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity" >

<item android:id="@+id/action_search"
    android:orderInCategory="5"
    android:title="Search"
    android:icon="@drawable/ic_action_search"
    android:showAsAction="ifRoom|collapseActionView"
    android:actionViewClass="android.widget.SearchView" />
</menu>

1

ฉันมีรหัสเดียวกัน แต่แทนที่จะใช้การนำเข้าที่android.support.v7.widget.SearchView;ฉันใช้import android.widget.SearchView;อยู่ สิ่งนี้แก้ไขปัญหาของฉันด้วยnullค่า ดังนั้นเพียงแค่เปลี่ยนรหัสนี้ในกิจกรรมการค้นหาของคุณและมันจะทำงานและเปลี่ยนเนมสเปซในไฟล์ xml


นี่คือปัญหาของเราเรามี android.widget.SearchView ในกิจกรรม แต่มีการใช้ v7 บางส่วนในไฟล์ menu_main.xml ของเรา เพียงตรวจสอบให้แน่ใจว่าไฟล์. xml กำลังใช้งานแอป: actionViewClass = "android.support.v7.widget.SearchView" ด้วย
gmcc051

0

ต่อไปนี้เป็นตัวอย่างข้อมูลวิธีจัดการ searchView จากห้องสมุดสนับสนุน v7:

@Override
public void onCreateOptionsMenu(final Menu menu,final MenuInflater inflater)
  {
  menu.clear();
  getActivity().getMenuInflater().inflate(...,menu);
  _searchView=(SearchView)MenuItemCompat.getActionView(_searchMenuItem);
  _searchView.setQueryHint(...);

  if(VERSION.SDK_INT<VERSION_CODES.HONEYCOMB)
    {
    final EditText searchTextView=(EditText)searchView.findViewById(R.id.search_src_text);
    if(searchTextView!=null)
      {
      searchTextView.setScroller(new Scroller(_context));
      searchTextView.setMaxLines(1);
      searchTextView.setVerticalScrollBarEnabled(true);
      searchTextView.setMovementMethod(new ScrollingMovementMethod());
      searchTextView.setTextColor(_context.getResources().getColor(App.getResIdFromAttribute(_context,android.R.attr.textColorPrimary)));
      }
    }
  _searchView.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener()
    {
    ...
    });
  MenuItemCompat.setActionView(_searchMenuItem,_searchView);
  MenuItemCompat.setOnActionExpandListener(_searchMenuItem,new OnActionExpandListener()
    {
    ...
    });
  super.onCreateOptionsMenu(menu,inflater);
  }


public static int getResIdFromAttribute(final Activity activity,final int attr)
  {
  if(attr==0)
    return 0;
  final TypedValue typedvalueattr=new TypedValue();
  activity.getTheme().resolveAttribute(attr,typedvalueattr,true);
  return typedvalueattr.resourceId;
  }

นอกจากนี้หากคุณใช้ Proguard ให้เพิ่มสิ่งนี้ลงในการกำหนดค่า:

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.widget.SearchView { *; }
-keepattributes *Annotation*

สำหรับใครก็ตามที่ต้องการจัดรูปแบบรหัสนี่เป็นรูปแบบที่รู้จักกันดีมากในชื่อ "WhiteSmith" การเปลี่ยนไปใช้รูปแบบอื่นไม่ได้ทำให้ดีขึ้นเนื่องจากเป็นเรื่องของรสนิยม
นักพัฒนา android

@JJD ใช่ แก้ไข. มันไม่ธรรมดาเหมือนคนอื่น ๆ แต่ฉันใช้มันมานานมาก คุณสามารถตั้งค่าเป็น Eclipse ได้หากต้องการ
นักพัฒนา android

ขอบคุณสำหรับการแบ่งปัน. ฉันอยู่กับค่าเริ่มต้นเพราะหลีกเลี่ยงการพูดคุยที่ไม่พึงประสงค์กับสมาชิกในทีมหรือผู้มีส่วนร่วม
JJD

@JJD นั่นก็จริงเช่นกัน ที่สำนักงานเราทำงานด้วยสไตล์ที่แตกต่างเล็กน้อยกว่าสไตล์เริ่มต้น อย่างไรก็ตามนักพัฒนาที่ดีควรสามารถจัดการรูปแบบการจัดรูปแบบทั่วไปทั้งหมดและหาก "เจ็บตา" คุณสามารถคัดลอกรหัสและจัดรูปแบบในเครื่องมือการจัดรูปแบบต่าง ๆ (ออนไลน์หรือบน IDE)
นักพัฒนา android

0

ฉันมีปัญหาที่คล้ายกันมากกับความแตกต่างเนื่องจากฉันพยายามใช้คลาสที่ขยายออกไป android.widget.ImageView

หากคุณใช้ ProGuard คุณจะต้องระบุเพื่ออนุญาตวิธีการที่เกี่ยวข้องในคลาสนี้

-keep public class * extends android.widget.ImageView{
  public <init>(android.content.Context);
  public <init>(android.content.Context, android.util.AttributeSet);
  public <init>(android.content.Context, android.util.AttributeSet, int);
  public void set*(...);
}

http://proguard.sourceforge.net/manual/examples.html

สิ่งนี้กล่าวว่า "อนุญาตให้ตัวสร้างที่จำเป็นทั้งหมดที่อาจถูกเรียกจาก xml และอนุญาตให้ตัวตั้งค่าแบบกำหนดเองใด ๆ ที่ใช้เช่นกัน (เพิ่มมากขึ้นตามต้องการ)"


0

ฉันทำโดยชุดคู่มือในรหัส java:

<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/user_info"
        android:title="@string/user_name_title"
        app:actionLayout="@layout/menu_item_username"
        android:showAsAction="always" />
</menu>

ไฟล์เลย์เอาต์:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/usr_name_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:contentDescription="@string/user_info_image_des"
        android:padding="5dp"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:text="@string/user_name_title"
        android:textStyle="bold"
        android:visibility="visible" />
</LinearLayout>

จากนั้นในรหัส java:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.connect_menu, menu);
        // show user name on the top of menu
        Log.e("menu", "Size: " + menu.size());
        MenuItem item = menu.getItem(0);
        item.setActionView(R.layout.menu_item_username);
        View v = item.getActionView();
        if (null == v) {
            Log.e("NULL POINTER EX", "NULL MENU VIEW");
        } else {
            TextView usrNameTitle = v.findViewById(R.id.usr_name_title);
            if (null != usrName && usrName.length() > 0) {
                usrNameTitle.setText(usrName);
            }
        }
        return true;
    }

ป้อนคำอธิบายรูปภาพที่นี่


-1

ลบรหัส: DemoActivity ระดับสาธารณะขยายActionBarActivity

แทนที่โดย: DemoActivity ชั้นเรียนสาธารณะขยายกิจกรรม


2
ทำไมเขาต้องทำอย่างนั้น? โปรดอธิบายรายละเอียดของคำตอบของคุณอีกเล็กน้อย
Robin Ellerkmann

เมื่อฉันขยาย ActionBarActivity มันจะคืนค่าว่างเสมอ แต่ฉันขยายกิจกรรมเท่านั้นมันใช้งานได้ปกติ
Hieu

คุณต้องใช้เนมสเปซของคุณเองเมื่อใช้ ActionBarActivity เนื่องจากเป็นส่วนหนึ่งของไลบรารีการสนับสนุน เนื่องจากคุณใช้ Android: showAsAction ใน xml ของคุณมันใช้งานได้กับกิจกรรม (ซึ่งไม่ได้มาจากห้องสมุดสนับสนุน) และไม่สามารถใช้งานกับ ActionBarActivity ได้
Dennis K
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.