在Toolbar中放置Spinner

  在展示列表时,可以通过在Toolbar中放置Spinner的形式,提供对列表进行过滤和分类的功能。本文在RecyclerView使用方法举例(2)的基础上,为Toolbar添加一个用于选择电影排序方法的Spinner,如图1所示。

图1

图1

0. 关于排序字符串的处理

  之前在MovieService.java中定义了三种排序方式:按照流行度降序、按照投票平均分降序、按照投票量降序,如下所示:

String SORT_BY_POPULARITY_DESC = "popularity.desc";
String SORT_BY_VOTE_AVERAGE_DESC = "vote_average.desc";
String SORT_BY_VOTE_COUNT_DESC = "vote_count.desc";

【完整文件】

对应这三种排序方式,在res/values/array.xml中定义字符串数组,用于显示:

<resources>
    <string-array name="sort_array">
        <item>Popularity</item>
        <item>Vote Average</item>
        <item>Vote Count</item>
    </string-array>
</resources>

【完整文件】

1. 添加Spinner

  首先在Toolbar中添加Spinner,直接把Spinner放置在Toolbar里面即可:

...
<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:popupTheme="@style/AppTheme.PopupOverlay" >

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.v7.widget.Toolbar>
...

【完整文件】

2. 配置Spinner

2.1. 禁止显示Toolbar标题

  首先设置Toolbar不显示标题,否则Spinner会被标题挤到旁边:

public class MainActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new MainActivityFragment())
                .commit();
    }
    ...
}

由于列表的显示逻辑位于MainActivityFragment ,所以之后对Spinner点击事件的处理也要由它完成,MainActivityFragment需要获取位于MainActivity的Spinner的实例。注意上面使用了FragmentManager来添加MainActivityFragment,这样之后在MainActivityFragment中,就可以通过(Spinner) getActivity().findViewById(R.id.spinner) 获取Spinner;如果只是在layout中定义MainActivityFragment位于MainActivity的布局里,那么之后在MainActivityFragment中调用(Spinner) getActivity().findViewById(R.id.spinner) 只会返回null 。

【完整文件】

2.2. 配置Spinner

  这里Spinner的使用方法并没有不同:

Spinner spinner = (Spinner) getActivity().findViewById(R.id.spinner);

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getContext(),
        R.array.sort_array, R.layout.spinner_item);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);

spinner.setAdapter(adapter);

在创建ArrayAdapter时,sort_array 是之前定义的用于显示的字符串数据,spinner_item 是收缩状态时的布局(如2中红框),而setDropDownViewResource() 用到的spinner_dropdown_item 是下拉状态时的布局(如3中红框)。

图2

图2

图3

图3

spinner_item 的定义见这里,粘贴并修改自Android自带的android.R.layout.simple_spinner_item,spinner_dropdown_item 的定义见这里,粘贴并修改自Android自带的android.R.layout.simple_spinner_dropdown_item。

2.3. 处理Spinner事件

  当Spinner中的item被点击时,可以通过position来选择对应的排序方式:

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        switch (position) {
            case 0:
                mSort = MovieService.SORT_BY_POPULARITY_DESC;
                break;
            case 1:
                mSort = MovieService.SORT_BY_VOTE_AVERAGE_DESC;
                break;
            case 2:
                mSort = MovieService.SORT_BY_VOTE_COUNT_DESC;
                break;
        }

        fetchInitialMovies(mSort);
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}
});

【完整文件】

3. 完整代码

  完整代码可以参考这里