[java] 조각으로 Android 검색

튜토리얼 또는 표준 구현하는 방법에 대한 예제의 누군가 알고합니까 안드로이드 검색 인터페이스Fragment들? 다시 말해, SearchManagerFragment에 표준 검색을 넣을 수 있습니까?



답변

요컨대, 당신은 할 수 없습니다. 에 검색 인터페이스를 만들 수없는 데는 몇 가지 이유 Fragment가 있습니다.

  1. 검색 가능한 인터페이스를 만들 때 Android 매니페스트에 기본 “검색 가능한 활동”을 지정해야합니다. 아시다시피 Fragment부모 없이는 존재할 수 Activity없으므로이 분리는 불가능합니다.

  2. 이미 # 1을 이미 알고 있다면 작업을 수행 할 수있는 마법의 “해킹”이 있기를 바랍니다. 그러나 설명서에는

    사용자가 검색 대화 상자 또는 위젯에서 검색을 실행하면 시스템은 검색 가능한 활동을 시작하고 ACTION_SEARCH 조치를 사용하여 검색 쿼리를 인 텐트로 전달합니다. 검색 가능한 활동은 의도의 QUERY Extra에서 쿼리를 검색 한 다음 데이터를 검색하고 결과를 제공합니다.

    검색 결과를 제공하는 기본 내부 시스템 ActivityFragment; 따라서 기본 시스템 자체를Activity 변경해야하므로 완전히 독립적 인 검색 인터페이스를 구현할 수 없습니다 . 나를 믿지 않으면 클래스 의 소스 코드를 확인하십시오 . :).SearchableInfo

말하자면, 당신이 묘사 한 것과 비슷한 것을 달성하기가 너무 어려워 보이지는 않습니다. 예를 들어, 검색 가능한 활동을 구현하여 android.intent.action.SEARCH의도 를 수용 하고 ( ListView예를 들어 결과를 즉시 표시하는 대신 ) 검색 쿼리를에 전달하도록 고려할 수 있습니다 Fragment. 예를 들어 다음과 같은 검색 가능한 활동을 고려하십시오.

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표시합니다. 구현에는 기대했던 것보다 약간 더 많은 작업이 필요하지만 더 모듈화 할 수있는 방법이 있다고 확신하며 이것이 최선의 방법 인 것처럼 보입니다.

ps이 접근법을 사용하는 경우 활동이 백 스택에 추가 / 제거되는 것에 특별한주의를 기울여야 할 수도 있습니다. 이 작업을 수행하는 방법에 대한 자세한 내용 은이 게시물 을 참조하십시오 .

pps 또한 표준 검색 인터페이스를 완전히 잊어 버릴 수 있으며 아래 Raghav의 게시물에Fragment 설명 된대로 간단한 검색을 구현할 수도 있습니다 .


답변

다음은 조각을 사용하여 무언가를 검색하는 예입니다. 그것이 도움이되기를 희망하며 이것이 당신이 찾고있는 것입니다 :

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


답변

표준 ActionBar SearchView ActionView API를 사용하여 조각을 검색하는 것이 가능합니다. 이것은 AppCompat 지원 클래스 v7을 사용하여 Android 2.1 (API 레벨 7)로 다시 작동합니다.

당신의 조각에서 :

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


답변

AppCompat 지원 클래스 v7 사용 그냥 뭔가 추가 @ 데이비드 에서의 솔루션을 @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);Activity가 메뉴를 팽창시킨 후 Fragment가 다른 메뉴를 팽창시킨 후 메뉴 항목을 두 배로 늘렸으므로 줄을 제거했습니다

@David와 @Rookie 덕분에


답변

작업 할 때 Fragments여전히을 사용 Activity하여을 제어하고 할당해야합니다 Fragments. 이것은 Activity이전과 검색 기능을 가질 수 있습니다.

최근에 ‘일반’ Activity기반 앱에서Fragment 했으며 검색 기능이 나에게도 똑같이 작동했습니다.

그 일을 시도했지만 성공하지 못했습니까? 그렇다면 귀하의 질문에 좀 더 자세히 설명하십시오.

편집하다:

프래그먼트 특정 검색을 원하면 모든 Fragments확장 메소드를 MyFragment사용하여 startSearch메소드를 확장하고 ActivitystartSearch메소드가 현재 프래그먼트의 startSearch메소드를 호출하게하십시오 .


답변

나는 그것을 달성했다고 생각합니다 : 실제로 조각을 사용하고 작업 표시 줄에 검색 아이콘을 추가하여 조각 내에서 검색 할 수 있습니다. 요령은 액션 바, 액션 뷰, 리스너, 로더 및 어댑터를 사용하는 것입니다.

이것은 안드로이드 플랫폼 검색 메커니즘을 완전히 우회하지만 잘 작동합니다 (그러나 @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

검색 조각 res / menu / menu_search.xml의 메뉴에 대한 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>


답변

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

사용자 정의 검색에 대한 자세한 내용 은 게시물을 참조하십시오.