ค้นหา Android ด้วย Fragments


161

มีใครรู้เกี่ยวกับการสอนหรือตัวอย่างของวิธีการใช้อินเตอร์เฟซการค้นหา Androidมาตรฐานด้วยFragments หรือไม่? กล่าวอีกนัยหนึ่งเป็นไปได้หรือไม่ที่จะทำการค้นหาแบบมาตรฐานด้วยSearchManagerการแยกส่วน?


ใครที่คุณจะให้โบนัสแก่ @blackbelt? Raghav ให้คำตอบที่ฉันต้องการ แต่ Alex LockWood ก็ตอบคำถามตอนแรกของคุณด้วย
Snicolas

ฉันยอมรับคำตอบของ LockWood มอบรางวัลให้เท่าที่คุณต้องการ (ฉันคิดว่าดีกว่า)
Blackbelt

4
ฉันดีใจที่เราได้คำตอบและวิธีแก้ไขปัญหาที่หลากหลายเช่นนี้! :)
Alex Lockwood

ใครช่วยตอบคำถามนี้ให้ฉันได้บ้าง .. ฉันติดอยู่ที่นี่stackoverflow.com/questions/10600660/…
Rookie

1
ฉันใช้เทคนิคนี้จะอยู่ในส่วนหลังจากบวก SearchView เพื่อ actionbar นี้: stackoverflow.com/a/6939735/1068167 ใบสมัครของฉันยังไม่เสร็จ แต่หวังว่ามันจะใช้ได้
ช่วง

คำตอบ:


91

ในระยะสั้นคุณไม่สามารถ มีสาเหตุสองประการที่ทำให้การสร้างอินเทอร์เฟซการค้นหาภายใน a Fragmentเป็นไปไม่ได้

  1. เมื่อสร้างอินเทอร์เฟซที่ค้นหาได้คุณต้องระบุ "กิจกรรมที่ค้นหาได้" เริ่มต้นในรายการ Android ของคุณ ในขณะที่ฉันแน่ใจว่าคุณรู้ว่าFragmentไม่มีอยู่โดยไม่มีผู้ปกครองActivityดังนั้นการแยกนี้เป็นไปไม่ได้

  2. หากคุณหาคำตอบได้แล้ว # 1 ฉันคิดว่าคุณถามคำถามนี้ด้วยความหวังว่าจะมี "แฮ็ค" ที่น่าอัศจรรย์ซึ่งสามารถทำงานให้เสร็จได้ อย่างไรก็ตามเอกสารระบุว่า

    เมื่อผู้ใช้ดำเนินการค้นหาในกล่องโต้ตอบการค้นหาหรือวิดเจ็ตระบบจะเริ่มต้นกิจกรรมที่ค้นหาได้ของคุณและส่งคำค้นหาใน Intent ด้วยการกระทำ ACTION_SEARCH กิจกรรมที่ค้นหาได้ของคุณจะดึงข้อความค้นหาจาก QUERY ที่ต้องการเพิ่มจากนั้นค้นหาข้อมูลของคุณและแสดงผลลัพธ์

    ที่อยู่ภายใต้ระบบภายในที่มีหน้าที่ในการให้ผลการค้นหาคาดว่าจะActivityไม่ได้Fragment; ดังนั้นการใช้อินเตอร์เฟซการค้นหาที่เป็นอิสระอย่างสมบูรณ์ของActivityเป็นไปไม่ได้ที่มันจะต้องมีการเปลี่ยนแปลงระบบพื้นฐานของตัวเอง ลองดูซอร์สโค้ดของSearchableInfoคลาสถ้าคุณไม่เชื่อฉัน :)

ที่ถูกกล่าวว่ามันไม่ดูเหมือนว่ามันจะยากเกินไปที่จะบรรลุสิ่งที่คล้ายกับสิ่งที่คุณกำลังอธิบาย ตัวอย่างเช่นคุณอาจพิจารณาการดำเนินการของคุณค้นหากิจกรรมเพื่อที่จะยอมรับandroid.intent.action.SEARCHความตั้งใจและ (แทนทันทีการแสดงผลในส่วนListViewตัวอย่างเช่น) จะผ่านคำค้นหาที่คุณFragments ตัวอย่างเช่นให้พิจารณากิจกรรมที่ค้นหาได้ดังต่อไปนี้:

public class SearchableActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) {
          String query = intent.getStringExtra(SearchManager.QUERY);
          doMySearch(query);
        }
    }

    /**
     * Performs a search and passes the results to the container
     * Activity that holds your Fragments.
     */
    public void doMySearch(String query) {
        // TODO: implement this
    }
}

เมื่อมีการร้องขอการค้นหาระบบจะเปิดกิจกรรมที่ค้นหาได้ของคุณดำเนินการค้นหาและจะส่งผลลัพธ์ไปยังกิจกรรมคอนเทนเนอร์บางส่วน (ขึ้นอยู่กับการใช้งานของคุณdoMySearch) กิจกรรมคอนเทนเนอร์จะส่งผ่านผลลัพธ์เหล่านี้ไปยังที่ค้นหาได้Fragmentซึ่งผลลัพธ์จะปรากฏขึ้น การนำไปใช้นั้นต้องใช้งานมากกว่าสิ่งที่คุณคาดหวัง แต่ฉันแน่ใจว่ามีวิธีที่คุณสามารถทำให้มันเป็นแบบแยกส่วนได้มากขึ้นและดูเหมือนว่านี่อาจเป็นวิธีที่ดีที่สุดที่คุณสามารถทำได้

ป.ล. หากคุณใช้วิธีการนี้คุณอาจต้องให้ความสนใจเป็นพิเศษในการเพิ่ม / ลบกิจกรรมที่แบ็คสแตค ดูโพสต์นี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำสิ่งนี้

PPS นอกจากนี้คุณอาจลืมเกี่ยวกับอินเตอร์เฟซการค้นหาแบบมาตรฐานสมบูรณ์และเพียงแค่ดำเนินการค้นหาง่ายภายในFragmentที่อธิบายไว้ในโพสต์ Raghav ด้านล่าง


@Alex เป็นไปได้ที่จะใช้อินเทอร์เฟซการค้นหามาตรฐานของ Android โดยใช้แฟรกเมนต์ แต่มันต้องใช้งานเยอะ ... :-)
Vinay S Shenoy

@VinaySShenoy ใช่ฉันหมายความว่าคุณจะต้องใช้อีกครั้งทั้งSearchManagerสำหรับFragments ใช่มั้ย? (หรืออะไรทำนองนั้น)
อเล็กซ์ล็อควู้ด

1
สำหรับการนำเสนอผลการค้นหาฉันได้ดำเนินการบางอย่างที่คล้ายกับสิ่งที่คุณแนะนำโดยส่งมอบความตั้งใจต่อกิจกรรมที่ส่งไปยังส่วนที่ถูกต้องหากสามารถมองเห็นได้ ส่วนที่ยากที่สุดคือ repopulating ตารางคำแนะนำในการโหลดชิ้นส่วนด้วยข้อมูลที่ถูกต้องเพื่อให้ฉันจัดการแสดงคำแนะนำเช่นเดียวกับการจัดการส่งการค้นหาและคลิกที่คำแนะนำ แต่ฉันมีกรอบที่ดีสำหรับแอพในอนาคตตอนนี้ .. :-)
Vinay S Shenoy

ฉันพบว่านี่เป็นคำตอบที่ดีกว่า: stackoverflow.com/questions/6938952/… ซึ่งจะช่วยให้ "การค้นหา" จากภายในแฟรกเมนต์ จริงไม่ใช่กลไกค้นหาอย่างเป็นทางการของ Google แต่ใช้ได้ดี
Kyle Falconer

76

นี่คือตัวอย่างการค้นหาสิ่งที่ใช้ชิ้นส่วน หวังว่าจะช่วยและนี่คือสิ่งที่คุณกำลังมองหา:

public class LoaderCursor extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FragmentManager fm = getFragmentManager();

        // Create the list fragment and add it as our sole content.
        if (fm.findFragmentById(android.R.id.content) == null) {
            CursorLoaderListFragment list = new CursorLoaderListFragment();
            fm.beginTransaction().add(android.R.id.content, list).commit();
        }
    }

    public static class CursorLoaderListFragment extends ListFragment
            implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {

        // This is the Adapter being used to display the list's data.
        SimpleCursorAdapter mAdapter;

        // If non-null, this is the current filter the user has provided.
        String mCurFilter;

        @Override public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);

            // Give some text to display if there is no data.  In a real
            // application this would come from a resource.
            setEmptyText("No phone numbers");

            // We have a menu item to show in action bar.
            setHasOptionsMenu(true);

            // Create an empty adapter we will use to display the loaded data.
            mAdapter = new SimpleCursorAdapter(getActivity(),
                    android.R.layout.simple_list_item_2, null,
                    new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
                    new int[] { android.R.id.text1, android.R.id.text2 }, 0);
            setListAdapter(mAdapter);

            // Start out with a progress indicator.
            setListShown(false);

            // Prepare the loader.  Either re-connect with an existing one,
            // or start a new one.
            getLoaderManager().initLoader(0, null, this);
        }

        @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            // Place an action bar item for searching.
            MenuItem item = menu.add("Search");
            item.setIcon(android.R.drawable.ic_menu_search);
            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
            SearchView sv = new SearchView(getActivity());
            sv.setOnQueryTextListener(this);
            item.setActionView(sv);
        }

        public boolean onQueryTextChange(String newText) {
            // Called when the action bar search text has changed.  Update
            // the search filter, and restart the loader to do a new query
            // with this filter.
            mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
            getLoaderManager().restartLoader(0, null, this);
            return true;
        }

        @Override public boolean onQueryTextSubmit(String query) {
            // Don't care about this.
            return true;
        }

        @Override public void onListItemClick(ListView l, View v, int position, long id) {
            // Insert desired behavior here.
            Log.i("FragmentComplexList", "Item clicked: " + id);
        }

        // These are the Contacts rows that we will retrieve.
        static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
            Contacts._ID,
            Contacts.DISPLAY_NAME,
            Contacts.CONTACT_STATUS,
            Contacts.CONTACT_PRESENCE,
            Contacts.PHOTO_ID,
            Contacts.LOOKUP_KEY,
        };

        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            // This is called when a new Loader needs to be created.  This
            // sample only has one Loader, so we don't care about the ID.
            // First, pick the base URI to use depending on whether we are
            // currently filtering.
            Uri baseUri;
            if (mCurFilter != null) {
                baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                        Uri.encode(mCurFilter));
            } else {
                baseUri = Contacts.CONTENT_URI;
            }

            // Now create and return a CursorLoader that will take care of
            // creating a Cursor for the data being displayed.
            String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                    + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                    + Contacts.DISPLAY_NAME + " != '' ))";
            return new CursorLoader(getActivity(), baseUri,
                    CONTACTS_SUMMARY_PROJECTION, select, null,
                    Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
        }

        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            // Swap the new cursor in.  (The framework will take care of closing the
            // old cursor once we return.)
            mAdapter.swapCursor(data);

            // The list should now be shown.
            if (isResumed()) {
                setListShown(true);
            } else {
                setListShownNoAnimation(true);
            }
        }

        public void onLoaderReset(Loader<Cursor> loader) {
            // This is called when the last Cursor provided to onLoadFinished()
            // above is about to be closed.  We need to make sure we are no
            // longer using it.
            mAdapter.swapCursor(null);
        }
    }
}

OP ขอคำว่า "อินเทอร์เฟซการค้นหามาตรฐาน" แต่สิ่งนี้จะทำให้ "ค้นหา" ง่าย ๆ ภายในFragmentดังนั้นฉันจะไม่บ่น ยินดีด้วย! : P
Alex Lockwood

30
ถัดไปเวลาที่คุณอาจต้องการที่จะอ้างอิงแหล่งข้อมูลของคุณ
Adrian Monk

ดูการสร้างอินเทอร์เฟซการค้นหาบนเว็บไซต์ของผู้พัฒนา OP ถามว่าเป็นไปได้หรือไม่ที่จะสร้าง "searchable-Fragment" ที่ทำงานกับการค้นหา Android มาตรฐานตามที่อธิบายไว้ในเอกสารประกอบ
Alex Lockwood

ข้อผิดพลาดบางอย่าง: การใช้ไอคอนค้นหาแบบกำหนดเองไม่ได้ผล 2-SearchView จำเป็นต้องมีรหัสการจัดการบางอย่างเช่นการปิดใช้งานเนื้อหาการจัดการกลับ ฯลฯ
AlikElzin-kilaka

ในกรณีของฉันonQueryTextChangeไม่ได้ถูกเรียกวิธี
Shajeel Afzal

57

ค่อนข้างเป็นไปได้ที่จะค้นหาในส่วนโดยใช้มาตรฐาน ActionBar SearchView ActionView API สิ่งนี้จะใช้งานได้กับ Android 2.1 (API ระดับ 7) เช่นกันโดยใช้ AppCompat support classes v7

ในส่วนของคุณ:

@Override
public void onCreateOptionsMenu (Menu menu, MenuInflater inflater){
    inflater.inflate(R.menu.search, menu);
    MenuItem item = menu.findItem(R.id.action_search);
    SearchView sv = new SearchView(((YourActivity) getActivity()).getSupportActionBar().getThemedContext());
    MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
    MenuItemCompat.setActionView(item, sv);
    sv.setOnQueryTextListener(new OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            System.out.println("search query submit");
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            System.out.println("tap");
            return false;
        }
    });
}

ในเมนู XML ของคุณ

<item
    android:id="@+id/action_search"
    android:icon="@drawable/ic_action_search"
    android:title="Search Waste Items"
    android:showAsAction="ifRoom|collapseActionView"
    nz.govt.app:actionViewClass="android.support.v7.widget.SearchView"
    nz.govt.app:showAsAction="ifRoom|collapseActionView" />

ใช้งานได้ดีกับ ActionBarActivity appcompat v7 ใหม่ขอบคุณ
Pelanes

1
การอ่านคำตอบที่ยอมรับฉันสูญเสียความหวัง .. คำตอบอื่นนั้นซับซ้อนฉันอ่านคำตอบของคุณ !!! ง่ายมาก! ขอบคุณ ... ขอบคุณมาก
MBH

2
ฉันคิดว่าเราต้องเพิ่ม setHasOptionsMenu (จริง) ใน onActivityCreated ตามที่เห็นโดย @MBH
Raymond Lukanta

2
@GowthamanM เพียงแค่ใช้ MenuItem.SHOW_AS_ACTION .... ถ้าคุณสามารถ AppCompat จะเลิกเกี่ยวกับ API ภายหลัง
เดวิด

1
เฮ้ @GowthamanM ใช้แบบนี้: item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItem.SHOW_AS_ACTION_IF_ROOM); item.setActionView(searchView);
Rod Lima

15

การใช้คลาสสนับสนุน AppCompat v7 เพียงแค่เพิ่มสิ่งที่จะ@ Davidวิธีการแก้ปัญหาของจาก@Rookieวิธีการแก้ปัญหาจะได้รับมันทำงานอย่างถูกต้องในลักษณะที่ง่ายและนี่คือส่วนของโค้ดของฉัน:

MyFragment :

public class MyFragment extends Fragment implements SearchView.OnQueryTextListener {

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // What i have added is this
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) {

        //inflater.inflate(R.menu.main, menu); // removed to not double the menu items
        MenuItem item = menu.findItem(R.id.action_search);
        SearchView sv = new SearchView(((MainActivity) getActivity()).getSupportActionBar().getThemedContext());
        MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
        MenuItemCompat.setActionView(item, sv);
        sv.setOnQueryTextListener(this);
        sv.setIconifiedByDefault(false);
        sv.setOnSearchClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Utils.LogDebug("Clicked: ");
            }
        });

        MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                // Do something when collapsed
                Utils.LogDebug("Closed: ");
                return true;  // Return true to collapse action view
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                // Do something when expanded
                Utils.LogDebug("Openeed: ");
                return true;  // Return true to expand action view
            }
        });

        super.onCreateOptionsMenu(menu,inflater);
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        Utils.LogDebug("Submitted: "+query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        Utils.LogDebug("Changed: "+newText);
        return false;
    }
}

ฉันเพิ่มonActivityCreated, cuz โดยไม่ต้องโทรsetHasOptionsMenu(true);ระบบจะไม่ทราบว่าส่วนนี้ต้องโต้ตอบกับเมนู

จากนั้นฉันก็ลบบรรทัด inflater.inflate(R.menu.main, menu);เพราะมันเพิ่มรายการเมนูเป็นสองเท่าเนื่องจากกิจกรรมขยายตัวเมนูจากนั้นแฟรกเมนต์ขยายอีกเมนูหนึ่ง

ขอบคุณ @David และ @Rookie


7

เมื่อทำงานร่วมกับFragmentsคุณยังคงต้องใช้ในการควบคุมและกำหนดActivity Fragmentsสิ่งนี้Activityสามารถมีฟังก์ชั่นการค้นหาเหมือนเดิม

ฉันเพิ่งเปลี่ยนจากแอพ 'ปกติ' Activityเป็นFragmentแอพพื้นฐานและฟังก์ชั่นการค้นหาใช้งานได้เหมือนกันสำหรับฉัน

คุณลองทำมันแล้ว แต่ไม่ประสบความสำเร็จ? ถ้ามีโปรดให้รายละเอียดเพิ่มเติมในคำถามของคุณ

แก้ไข:

หากคุณต้องการที่จะมีการค้นหาชิ้นส่วนที่เฉพาะเจาะจงได้ทั้งหมดของคุณFragmentsขยายอินเตอร์เฟซMyFragmentกับstartSearchวิธีการและมีคุณActivity's startSearchวิธีการเรียกส่วนปัจจุบันstartSearchวิธีการ


ความต้องการคือการค้นหา android นั้นถูกผูกไว้กับส่วนที่ระบุไม่ใช่กิจกรรม ดังนั้นไม่ฉันไม่ได้ลอง
Blackbelt

ฉันยังไม่ได้ลอง แต่ดูเหมือนว่าสิ่งที่ฉันกำลังมองหา ฉันมีลิ้นชักการนำทางที่มีแฟรกเมนต์ที่แต่ละอันมีคุณลักษณะการค้นหาที่ไม่เกี่ยวข้อง ฉันไม่ต้องการข้ามระบบค้นหา android ทั้งหมดดังนั้นฉันต้องการอะไรแบบนี้
Bassinator

5

ฉันคิดว่าฉันทำสำเร็จคุณสามารถใช้แฟรกเมนต์และเพิ่มไอคอนค้นหาลงในแถบการกระทำเพื่อให้สามารถค้นหาได้ภายในแฟรกเมนต์ เคล็ดลับคือการใช้แถบการกระทำมุมมองการดำเนินการฟังมันโหลดเดอร์และอะแดปเตอร์แน่นอน

วิธีนี้ใช้งานได้ดีแม้ว่ามันจะผ่านกลไกการค้นหาแพลตฟอร์ม Android อย่างสมบูรณ์ (แต่มันอาจจะแล้วเสร็จพร้อมงานบางอย่างเพื่อค้นหาสิ่งที่ @Alex Lockwood อธิบายและส่งผ่านการค้นหาไปยังส่วนต่างๆ) มันจะไม่ตอบสนองต่อเจตนาตามที่คาดไว้ในกรณีของกิจกรรม แต่ใช้งานได้: ผู้ใช้สามารถค้นหาชิ้นส่วนภายใน

นี่คือรหัส:

SearchInFragmentActivity

package com.sof.test.searchfragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.View;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.ActionBar.TabListener;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.sof.test.searchfragment.SearchFragment;
import com.sof.test.R;


public class SearchInFragmentActivity extends SherlockFragmentActivity implements TabListener {

    private SearchFragment tab1 = new SearchFragment();
    private SearchFragment tab2 = new SearchFragment();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView( R.layout.search_in_fragments );

        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        createTab( R.string.tab1, R.drawable.ic_menu_search );
        createTab( R.string.tab2, R.drawable.ic_menu_search );
        getSupportActionBar().setSelectedNavigationItem( 0 );
        invalidateOptionsMenu();
    }

    private void createTab(int tabNameResId, int tabIconResId) {
        ActionBar.Tab tab = getSupportActionBar().newTab();
        tab.setText( tabNameResId );
        tab.setTabListener(this);
        getSupportActionBar().addTab(tab);
    }// met

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if( ft == null ) {
            return;
        }//if
        View fragmentSlot = findViewById( R.id.fragment );
        Fragment newFragment = null;
        if( fragmentSlot != null ) {
            newFragment = (tab.getPosition() == 0) ? tab1 : tab2;
            ft.replace(R.id.fragment, newFragment );
            ft.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }//if
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }

}//class

SearchFragment คลาสแฟรกเมนต์ (ฉันใช้ 2 อินสแตนซ์ภายในกิจกรรมด้านบน)

package com.sof.test.searchfragment;


import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.SearchView;
import android.widget.TextView;

import com.sof.test.R;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;

public class SearchFragment extends SherlockListFragment {

    private StringLoader loader = null;
    private StringAdapter adapter = null;
    private List<String> listData = new ArrayList<String>();
    private String query;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = super.onCreateView(inflater, container, savedInstanceState);
        createListData();

        loader = new StringLoader( getActivity(), this );
        adapter = new StringAdapter(listData);
        setListAdapter(adapter);

        getLoaderManager().initLoader(0, null,  new LoaderCallBacks() );
        loader.forceLoad();
        setHasOptionsMenu( true );
        return view;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater ) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate( R.menu.menu_search, menu);
        System.out.println( "inflating menu");

        final SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        final SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                showFilteredItems( newText );
                return true;
            }

            @Override
            public boolean onQueryTextSubmit(String query) {
                return true;
            }
        };

        searchView.setOnQueryTextListener(queryTextListener);

        return;
    }//met

    private void showFilteredItems( String query ) {
        this.query = query;
        loader.onContentChanged();
    }

    private void createListData() {
        for( int i = 0; i < 100 ; i ++ ) {
          listData.add( "String "+ i ); 
        }
    }

    public List<String> getData() {
        List<String> listFilteredData = new ArrayList<String>();
        for( String string : listData ) {
            if( query == null || string.contains( query ) ) {
                listFilteredData.add( string );
            }
        }
        return listFilteredData;
    }//met

    private class LoaderCallBacks implements LoaderCallbacks< List<String>> {
        @Override
        public void onLoadFinished(Loader<List<String>> loader,
                List<String> listData) {
            adapter.setListData( listData );
        }// met

        @Override
        public void onLoaderReset(Loader<List<String>> listData) {
            adapter.setListData( new ArrayList<String>() );
        }// met

        @Override
        public Loader<List<String>> onCreateLoader(int arg0,
                Bundle arg1) {
            return loader;
        }// met
    }//class

    private class StringAdapter extends ArrayAdapter< String > {

        private List<String> listDataToDisplay = new ArrayList<String>();
        private LayoutInflater mInflater;

        public StringAdapter( List<String> listData ) {
            super( getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, listData );
            listDataToDisplay = listData;
            mInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }//cons

        private void setListData( List<String> newListData ) {
            this.listDataToDisplay.clear();
            this.listDataToDisplay.addAll( newListData );
            notifyDataSetChanged();
        }//met

          /**
         * Populate new items in the list.
         */
        @Override public View getView(int position, View convertView, ViewGroup parent) {
            View view;

            if (convertView == null) {
                view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
            } else {
                view = convertView;
            }

            ((TextView)view.findViewById( android.R.id.text1)).setText( listDataToDisplay.get( position ) );

            return view;
        }
    }//inner class
}//class

class StringLoader extends AsyncTaskLoader<List<String>> {

    SearchFragment fragment = null;

    public StringLoader(Context context, SearchFragment fragment) {
        super(context);
        this.fragment = fragment;
    }// cons

    @Override
    public List<String> loadInBackground() {
        return fragment.getData();
    }// met
}// class

ไฟล์ xml สำหรับเมนูของการค้นหาแฟรกเมนต์ res / menu / menu_search.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >
    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="0px"
        android:layout_height="match_parent"
        android:layout_weight="1" />
</LinearLayout>

และไฟล์เค้าโครง xml res / layout / search_in_fragments.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >
    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="0px"
        android:layout_height="match_parent"
        android:layout_weight="1" />
</LinearLayout>

ฉันต้องการที่จะชี้ให้เห็นว่า Jake Wharton ตัดสินใจที่จะไม่ใช้SearchViewห้องสมุด ActionBarSherlock ของเขาเนื่องจากความซับซ้อน ( ดูความคิดเห็นของเขาที่นี่ ) อย่างที่คุณเห็น (และอย่างที่ฉันอธิบายไว้ในคำตอบของฉันด้วย) การใช้งานการค้นหาของ Android เป็นอะไรที่ไม่สำคัญ ... มันฝังอยู่ในระบบพื้นฐานและสิ่งนี้ทำให้แม้แต่ห้องสมุดบุคคลที่สามยากที่จะเขียน .. Jake Wharton เปรียบเสมือน Chuck Norris ของห้องสมุดบุคคลที่สาม!: D)
Alex Lockwood

ดูSearchView.javaซอร์สโค้ดที่นี่
Alex Lockwood

2
อเล็กซ์ดูเหมือนว่า Jake Wharton เปลี่ยนใจ: twitter.com/JakeWharton/status/221169921235755009
Jose_GD

ไฟล์ xml ทั้งสองนี้เหมือนกันหรือไม่
Clocker

@Clocker ดูเหมือนว่าพวกเขาเป็น สุจริตหลังจาก 2 ปีฉันไม่สามารถพูดได้
Snicolas

5

ใช้และActionBar SearchViewคุณจะสามารถจัดการการค้นหาโดยไม่ต้องเชื่อมต่อกับกิจกรรม เพียงตั้งค่าเป็นOnQueryTextListenerSearchView

MenuItem item = menu.add("Search");
SearchView sv = new SearchView(getActionBar().getThemedContext());
item.setActionView(sv);
item.setIcon(R.drawable.ic_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
        | MenuItem.SHOW_AS_ACTION_IF_ROOM);
sv.setOnQueryTextListener(new OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        //...
        return false;
    }
    @Override
    public boolean onQueryTextChange(String newText) {
        //...
        return false;
    }
});

ดูโพสต์นี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการค้นหาที่กำหนดเอง


3

วิธีการแก้ปัญหาอื่น ๆ ..... ฉันไม่ชอบมัน ง่ายกว่านี้สำหรับฉัน แต่มันเป็นความคิดของฉันฉันกำลังรอความคิดเห็นของคุณ

public interface SearchImpl {
    public void searchQuery(String val);
}

ส่วน

public class MyFragment extends Fragment implements SearchImpl {
    View view;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_almanca, container, false);
        return view;
    }

    @Override
    public void searchQuery(String val) {
        Log.e("getted", val);
    }
}

Acitivty

 @Override
public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.main, menu);

    SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            Log.e("setted", "" + query);
            try {
                MyFragment myFGM=new MyFragment();
                myFGM.searchQuery(query);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            return false;
        }
    });
    return super.onCreateOptionsMenu(menu);
}

1

Fragmentไม่สามารถอยู่นอกActivityหรือที่สามารถFragmentจะเชื่อมโยงกับคนอื่น ๆandroid.intent.action.SEARCH หรือใด ๆintent-filter

ดังนั้นหากไม่ใช้การActivityห่อหุ้มFragmentสิ่งที่คุณต้องการจะเป็นไปไม่ได้


1

ในกรณีที่ชิ้นส่วนต่างๆกลายเป็น ViewPager ฉันสามารถทำได้โดยบล็อกปุ่มค้นหาเมื่อฉันไม่ได้อยู่ในส่วนที่ฉันต้องการให้แถบการค้นหา เข้าสู่กิจกรรม:

@Override
public boolean onSearchRequested() {

    if (mPager.getCurrentItem() == mAdapter.getPosition(FragmentType.VIDEO))
        return super.onSearchRequested();
    else
        return false;
}

และในกรณีที่ไม่มีปุ่มค้นหาทางกายภาพฉันได้เพิ่มรายการการกระทำลงในส่วนที่เรียกรหัสนี้:

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    if (item.getItemId() == R.id.search_item) {

        return getSherlockActivity().onSearchRequested();
    }
    return super.onOptionsItemSelected(item);
}

1

ฉันพบวิธีแก้ไข :) คุณสามารถแทนที่เมธอดนี้ (startActivity (Intent)) ใน BaseActivity ของคุณแล้วตรวจสอบว่าการกระทำนั้นเป็น ACTION_SEARCH หรือไม่แล้วทำหน้าที่พิเศษของคุณ: D

@Override
    public void startActivity(Intent intent) {
        try {
            if (intent.getAction().equals(Intent.ACTION_SEARCH))
                toast("hello");
        } catch (Exception e) {

        }
    }

0

ใช่มันเป็นไปได้

กรุณาใช้ค้นหามุมมองในกิจกรรมของคุณ 'onQueryTextChange' ในกิจกรรมจะฟังการค้นหาในส่วนคุณสามารถตรวจสอบการมองเห็นชิ้นส่วนใน 'onQueryTextChange' ถ้ามันมองเห็นคุณสามารถเรียกวิธีการค้นหาของคุณสำหรับชิ้นส่วนการทำงานที่สมบูรณ์แบบในรหัสของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.