[譯]SearchFragment --Android TV 開發手冊十二

weixin_33670713發表於2017-06-06

版權宣告:本文為博主原創翻譯文章,轉載請註明出處。

推薦:
歡迎關注我建立的Android TV 簡書專題,會定期給大家分享一些AndroidTv相關的內容:
https://www.jianshu.com/c/3f0ab61a1322


1927803-c860b69b36b7b9f0.png
search

Android TV 應用內搜尋

Android手機和Android TV之間最大的區別之一就是他們的輸入法。 由於電視不支援觸控板,我們不應該期望使用者使用電視鍵盤,為電視輸入字詞很麻煩。

Google建議在電視應用中使用語音輸入進行搜尋

BrowseFragment上的應用內搜尋圖示

BrowseFragment包含搜尋功能的設計佈局,並且在應用程式上顯示應用內圖示非常簡單。 只需要實現setOnSearchClickedListener就可以了。

// Existence of this method make In-app search icon visible
   setOnSearchClickedListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
                
          }
     });

setSearchAffordanceColor方法可用於指定搜尋圖示顏色。

  // set search icon color
  setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
1927803-42dce910f5f8549c.png
search1

當呼叫setOnSearchClickedListener時,應用內搜尋圖示將顯示在BrowseFragment的右上角。

SearchFragment

需要實現搜尋功能來回答使用者的搜尋查詢。 為了顯示搜尋查詢輸入UI和搜尋結果UI,LeanbackLibrary提供了SearchFragment。 這一次,當請求搜尋(通過語音搜尋按鈕或顯式按搜尋按鈕圖示)時,我們從SearchActivity呼叫此SearchFragment。

private void setupEventListeners() {
        setOnItemViewSelectedListener(new ItemViewSelectedListener());
        setOnItemViewClickedListener(new ItemViewClickedListener());

        // Existence of this method make In-app search icon visible
        setOnSearchClickedListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), SearchActivity.class);
                startActivity(intent);
            }
        });
    }

通過右鍵單擊包名稱 Create → New Activity → Blank Activity →鍵入“SearchActivity”,開始建立SearchActivity。 在建立了SearchActivity類和activity_search.xml佈局之後,按如下所示修改res / acitivity_search.xml。

<?xml version="1.0" encoding="utf-8"?>

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.corochann.androidtvapptutorial.SearchFragment"
    android:id="@+id/search_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

它附加SearchFragment。 再次,通過Create → New → Java class → SearchFragment,並使其成為android.support.v17.leanback.app.SearchFragment的子類。

如果您在這裡構建和執行應用程式,則應用程式將崩潰,因為SearchFragment會自動從內部語音識別器開始獲取搜尋查詢。

實現語音輸入/語音搜尋 - setSpeechRecognitionCallback

官方檔案說,

如果您不通過setSpeechRecognitionCallback(SpeechRecognitionCallback)提供回撥,則將使用內部語音識別器,您的應用程式將需要它來請求android.permission.RECORD_AUDIO。

所以你需要:

  • 實現setSpeechRecognitionCallback
  • 在AndroidManifest.xml上請求android.permission.RECORD_AUDIO

如下。

public class SearchFragment extends android.support.v17.leanback.app.SearchFragment {

    private static final String TAG = SearchFragment.class.getSimpleName();

    private static final int REQUEST_SPEECH = 0x00000010;

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

        if (!Utils.hasPermission(getActivity(), Manifest.permission.RECORD_AUDIO)) {
            // SpeechRecognitionCallback is not required and if not provided recognition will be handled
            // using internal speech recognizer, in which case you must have RECORD_AUDIO permission
            setSpeechRecognitionCallback(new SpeechRecognitionCallback() {
                @Override
                public void recognizeSpeech() {
                    Log.v(TAG, "recognizeSpeech");
                    try {
                        startActivityForResult(getRecognizerIntent(), REQUEST_SPEECH);
                    } catch (ActivityNotFoundException e) {
                        Log.e(TAG, "Cannot find activity for speech recognizer", e);
                    }
                }
            });
        }
    }

utils.java

    public static boolean hasPermission(final Context context, final String permission) {
        return PackageManager.PERMISSION_GRANTED == context.getPackageManager().checkPermission(
                permission, context.getPackageName());
    }

覆蓋onSearchRequeseted以啟用應用內搜尋

當使用者嘗試語音輸入搜尋時,執行onSearchRequested回撥,預設情況下將啟動Google的全域性內容搜尋。


1927803-92e40722e36041f1.png
search2

語音搜尋功能與Google的預設語音搜尋結果相關。

如果要啟用應用內應用程式搜尋,則需要重寫此方法。

它是寫在startSearch方法的描述中

它通常從onSearchRequested()直接從Activity.onSearchRequested()或任何給定的Activity中的覆蓋版本呼叫。 如果您的目標只是啟用搜尋,則最好呼叫onSearchRequested(),這可能已被您的Activity中的其他地方覆蓋。 如果您的目標是注入上下文資料等特定資料,則優先覆蓋onSearchRequested(),以便任何呼叫者將從覆蓋中獲益。

我們覆蓋MainActivity和SearchActivity的onSearchRequested方法。

    @Override
    public boolean onSearchRequested() {
        startActivity(new Intent(this, SearchActivity.class));
        return true;
    }

自定義應用內搜尋 - SearchResultProvider

SearchResultProvider介面是Leanback庫的介面,用於監聽搜尋相關事件。 我們需要重寫3種方法。

  • getResultsAdapter - 返回包含搜尋結果的介面卡,以顯示SearchFragment上的搜尋結果。
  • onQueryTextChange - 當使用者更改搜尋查詢文字時呼叫的事件偵聽器。
  • onQueryTextSubmit - 當使用者提交搜尋查詢文字時呼叫的事件偵聽器。

我們需要使用setSearchResultProvider方法註冊這個SearchResultProvider,最小化的實現就是這樣,

public class SearchFragment extends android.support.v17.leanback.app.SearchFragment
        implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {

    private static final String TAG = SearchFragment.class.getSimpleName();

    private static final int REQUEST_SPEECH = 0x00000010;
    private ArrayObjectAdapter mRowsAdapter;

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

        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());

        setSearchResultProvider(this);

        ...
    }

    ... 

    @Override
    public ObjectAdapter getResultsAdapter() {
        Log.d(TAG, "getResultsAdapter");
        Log.d(TAG, mRowsAdapter.toString());

        // It should return search result here,
        // but static Movie Item list will be returned here now for practice.
        ArrayList<Movie> mItems = MovieProvider.getMovieItems();
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
        listRowAdapter.addAll(0, mItems);
        HeaderItem header = new HeaderItem("Search results");
        mRowsAdapter.add(new ListRow(header, listRowAdapter));

        return mRowsAdapter;
    }

    @Override
    public boolean onQueryTextChange(String newQuery){
        Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        Log.i(TAG, String.format("Search Query Text Submit %s", query));
        return true;
    }

構建並執行

SearchActivity可以通過兩種方式啟動,

1.單擊BrowseFragment的搜尋圖示。
2.當使用者從特定控制器啟動語音輸入搜尋*1(將呼叫onSearchRequested。)

*1這取決於Android TV裝置。 例如,SONY BRAVIA提供觸控板遙控器,可以從該遙控器完成語音搜尋。


1927803-ec80663b8deb2b05.jpg
OneTouchPadRemote

SearchFragment現在顯示模擬搜尋結果。

1927803-aac0201bbd9f163f.png
search3

原始碼在github上。

我們應該實現OnItemViewClickedListener來定義點選這些搜尋結果的動作。 這個OnItemViewClickedListener可以被設定

setOnItemViewClickedListener(new ItemViewClickedListener());

(在這種情況下)在onCreate的BrowseFragment。

關注微信公眾號,定期為你推薦移動開發相關文章。


1927803-0603f7d44dd403d0.jpg
songwenju

相關文章