AndroidTV用の検索画面を実装する方法を紹介します。

AndroidTV用の検索画面を実装する方法を紹介します。

今回はAndroid StudioのAndroidTVサンプルのCardPresenterとMainFragmentに含まれるGridItemPresenterを使って動画の検索画面を実装しました。

まず3つのクラスを作成する必要があります

  • 検索画面のActivity
  • SearchFragmentを継承したクラス
  • SearchFragment.SearchProviderをimplementsしたクラス

私はそれぞれSearchActivity、SearchFragment、SearchProviderと名前をつけました。

Activityのコードです

import androidx.fragment.app.FragmentActivity;
public class SearchActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle saved InstanceState){
super.onCreate(savedInstanceState);
SearchProvider.cnt=this;
setContentView(R.layout.search);
}
}

Activityはこれだけです。次はActivityで利用しているレイアウトです

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_browse_fragment"
    android:name="com.example.SearchFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Search"
    tools:deviceIds="tv"
    tools:ignore="MergeRootFrame" />

次にSearchFragmentを実装します。以下がコードです

import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.app.ActivityOptionsCompat;
import androidx.leanback.widget.ImageCardView;
import androidx.leanback.widget.OnItemViewClickedListener;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.Row;
import androidx.leanback.widget.RowPresenter;

public class SearchFragment extends androidx.leanback.app.SearchFragment{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setSearchResultProvider(new SearchProvider());
        setOnItemViewClickedListener(new ItemViewClickedListener());
    }

    private final class ItemViewClickedListener implements OnItemViewClickedListener {
        @Override
        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
                                  RowPresenter.ViewHolder rowViewHolder, Row row) {

            if (item instanceof Movie) {
                Movie movie = (Movie) item;
                Intent intent = new Intent(getActivity(), DetailsActivity.class);
                intent.putExtra(DetailsActivity.MOVIE, movie);

                Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
                        getActivity(),
                        ((ImageCardView) itemViewHolder.view).getMainImageView(),
                        DetailsActivity.SHARED_ELEMENT_NAME)
                        .toBundle();
                getActivity().startActivity(intent, bundle);
            } else if (item instanceof String) {
                if (((String) item).contains(getString(R.string.error_fragment))) {
                    Intent intent = new Intent(getActivity(), BrowseErrorActivity.class);
                    startActivity(intent);
                } else {
                    Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
}

DetailsActivityとBrowseErrorActivityはサンプルに付属しています。ここでは動画が選択されたらDetailsActivityに移動させています。

次にSearchProviderの実装です。

import android.graphics.Color;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.core.content.ContextCompat;
import androidx.leanback.app.SearchFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
import androidx.leanback.widget.HeaderItem;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.ListRowPresenter;
import androidx.leanback.widget.ObjectAdapter;
import androidx.leanback.widget.Presenter;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;



public class SearchProv implements SearchFragment.SearchResultProvider {
    string[] rar;//検索結果の動画の識別番号等、rar[0]を""にするとNoResultが表示されます
    ArrayObjectAdapter mAdapter;
    ArrayObjectAdapter arrayObjectAdapter;
    private static final int GRID_ITEM_WIDTH = 200;
    private static final int GRID_ITEM_HEIGHT = 200;
  public static Context cnt;
    @Override
    public ObjectAdapter getResultsAdapter()
    {
//表示されるPresenterを設定。ここではsampleVideoをはじめに表示する
        CardPresenter cardPresenter = new CardPresenter();
         arrayObjectAdapter=new ArrayObjectAdapter(cardPresenter);
         mAdapter=new ArrayObjectAdapter(new ListRowPresenter());
        List<Movie> list = MovieList.setupMovies();
        arrayObjectAdapter = new ArrayObjectAdapter(cardPresenter);
        for (int j = 0; j < list.size(); j++) {
            arrayObjectAdapter.add(list.get(j));
        }
        HeaderItem header = new HeaderItem(0, "新着動画");
        mAdapter.add(new ListRow(header, arrayObjectAdapter));

        return mAdapter;
    }

    @Override
    public boolean onQueryTextChange(String newQuery) {
        try {
            mAdapter.clear();
            arrayObjectAdapter.clear();
            rar=doquery(newQuery);
            List<Movie> m=getMovieList(rar);
            if(rar[0].equals("")) {
                HeaderItem gridHeader = new HeaderItem(0,  cnt.getResources().getString(R.string.searchres));

                GridItemPresenter mGridPresenter = new GridItemPresenter();
                ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
                //gridRowAdapter.add(getResources().getString(R.string.grid_view));
                //gridRowAdapter.add(getString(R.string.error_fragment));
                gridRowAdapter.add("N");
                gridRowAdapter.add("o");
                gridRowAdapter.add("R");
                gridRowAdapter.add("e");
                gridRowAdapter.add("s");
                gridRowAdapter.add("u");
                gridRowAdapter.add("l");
                gridRowAdapter.add("t");
                mAdapter.add(new ListRow(gridHeader, gridRowAdapter));
            }else{

            for (int j = 0; j < m.size(); j++) {
                arrayObjectAdapter.add(m.get(j ));
            }
            HeaderItem header = new HeaderItem(0, cnt.getResources().getString(R.string.searchres));
            mAdapter.add(new ListRow(header, arrayObjectAdapter));
            }
            //mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        try {
            mAdapter.clear();
            arrayObjectAdapter.clear();
            rar=doquery(query);

            List<Movie> m=getMovieList(rar);
            if(rar[0].equals("")) {
                HeaderItem gridHeader = new HeaderItem(0,  cnt.getResources().getString(R.string.searchres));

                GridItemPresenter mGridPresenter = new GridItemPresenter();
                ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
                //gridRowAdapter.add(getResources().getString(R.string.grid_view));
                //gridRowAdapter.add(getString(R.string.error_fragment));
                gridRowAdapter.add("N");
                gridRowAdapter.add("o");
                gridRowAdapter.add("R");
                gridRowAdapter.add("e");
                gridRowAdapter.add("s");
                gridRowAdapter.add("u");
                gridRowAdapter.add("l");
                gridRowAdapter.add("t");
                mAdapter.add(new ListRow(gridHeader, gridRowAdapter));
            }else{
                for (int j = 0; j < m.size(); j++) {
                    arrayObjectAdapter.add(m.get(j));
                }
                HeaderItem header = new HeaderItem(0, cnt.getResources().getString(R.string.searchres));
                mAdapter.add(new ListRow(header, arrayObjectAdapter));
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return false;
    }
    private class GridItemPresenter extends Presenter {
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent) {
            TextView view = new TextView(parent.getContext());
            view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT));
            view.setFocusable(true);
            view.setFocusableInTouchMode(true);
            view.setBackgroundColor(
                    ContextCompat.getColor(cnt, R.color.default_background));
            view.setTextColor(Color.WHITE);
            view.setGravity(Gravity.CENTER);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(ViewHolder viewHolder, Object item) {
            ((TextView) viewHolder.view).setText((String) item);
        }

        @Override
        public void onUnbindViewHolder(ViewHolder viewHolder) {
        }
    }
    public List<Movie> getMoieList(String[] res){
    //ここでMovieクラスのリストを作成し返します
    }
    public String[] doquery(String q){
    //検索の実行動画の識別コードを返す
    }
}

下にあるdoqueryとgetMovieListはアプリによって変更する必要があります。

これで検索画面の実装が出来ます。

最後にManifestにSearchActivityを追加してアプリからSearchActivityを呼び出せば検索画面を開くことが出来ます

“AndroidTV用の検索画面を実装する方法を紹介します。”へのコメント4

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です