Java安卓学习总结(十七)

第十三章 工具栏

有关工具栏菜单

定义资源

在XML中创建菜单资源,资源类型是Menu,且这个资源处于一个新的命名空间res\menu中。其中可以用Android Asset Studio来根据系统资源来创建自己想要的资源目标。

创建菜单

要用到三个方法。

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
...
setHasOptionsMenu(true);
}
public boolean onOptionsItemSelected(MenuItem item)

第一个方法是绑定视图资源;第二个是让这个Fragment接受调用菜单栏的指令;第三个是响应菜单项的选择事件。

有关实现层级式导航

层级式导航就是规定一个activity有一个上级activity,只要点击工具栏左边的按钮就可以向上导航。定义上层activity是在AndroidMainfest.xml添加android:parentActivityName:

<activity android:name=".CrimePagerActivity"
    android:parentActivityName=".CrimeListActivity"></activity>

有关可选菜单项(次标题)

过程大致上和创建第一个菜单的相同。其中用到这样几个方法:

设置次标题

AppCompatActivity activity=(AppCompatActivity) getActivity();
activity.getSupportActionBar().setSubtitle(subtitle);

重建OptionsMenu

invalidateOptionsMenu();

这个方法的作用是使原填充的菜单项无效,当用户再次访问菜单时,再次调用onCreateOptionsMenu(Menu menu)。此外还有一个onPrepareOptionsMenu()方法,可以看这里

更新菜单项

这一步是使得菜单项的名称发送改变。

MenuItem subtitleItem=menu.findItem(R.id.show_subtitle);
if (mSubtitleVisible)
{
subtitleItem.setTitle(R.string.hide_subtitle);
}
else
{
subtitleItem.setTitle(R.string.show_subtitle);
}

有关挑战练习 删除crime记录

过程和新建一个crime差不多,要在crimeLab中新建一个delete方法。onOptionsItemSelected内对应的代码是

case R.id.delete_crime:

    CrimeLab crimeLab=CrimeLab.get(getActivity());
    crimeLab.deleteCrime(mCrime);
    getActivity().finish();
    return true;

由于之前用hashMap优化过crime的查询方式,所以crimeLab.add()和delete()方法都要对其hashMap进行即是更新,否则会导致查询不到或下标越界的错误。

当我创建了多个crime时删除非最后一个,程序就会崩溃

 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{1006c628 position=1 id=-1, oldPos=1, pLpos:-1 scrap tmpDetached no parent}

原因是最后一个crime的View Holder的位置和Adapter不匹配,导致RecyclerView出现了问题。上网查询之后找到了解决方法

我用的是第一个方法,写了LinearLayoutManager的继承类。

class WrapContentLinearLayoutManager extends LinearLayoutManager {


    public WrapContentLinearLayoutManager(Context context) {
        super(context);
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        try {
            super.onLayoutChildren(recycler, state);
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
    }
}
...
mCrimeRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getActivity()));

很迷为什么只要继承一下之后就可以用了。

有关挑战练习 复数字符串资源

这么样定义字符串:

<plurals name="subtitle_plurals">
<item quantity="one">%1$d crime</item>
<item quantity="zero">%1$d crime</item>
<item quantity="other">%1$d crime</item>
</plurals>

这样调用:

int crimeCount=crimeLab.getCrimes().size();
String subtitle=getResources().getQuantityString(R.plurals.subtitle_plurals,crimeCount,crimeCount,crimeCount);

其中第二个参数开始每一个都对应第一种的每一行。

有关挑战练习 用于RecyclerView的空视图

我总感觉我写的做法不是题目要求的,但是效果是实现了。

在一个视图资源文件中包含recyclerView和空视图,在onCreateView中分别绑定。在空视图里的按钮设置监听器以创建新crime。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState)
{

    View view=inflater.inflate(R.layout.fragment_crime_list,container,false);

    mCrimeRecyclerView=(RecyclerView)view.findViewById(R.id.crime_recycler_view);
    mCrimeRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getActivity()));

    mDefaultLayoutView=(LinearLayout) view.findViewById(R.id.default_layout_view);
    mDefaultButton=(Button)view.findViewById(R.id.default_button);
    mDefaultButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Crime crime=new Crime();
            CrimeLab.get(getActivity()).addCrime(crime);
            Intent intent=CrimePagerActivity.newIntent(getActivity(),crime.getId());
            startActivity(intent);

        }
    });
    ...
    return view;
}

这两个视图只能二选一地显示,所以在onResume()中根据当前已经有的crime数量来选择使用哪一个。

@Override
public void onResume() {
super.onResume();
if (CrimeLab.get(getActivity()).getCrimes().size()==0)
{
mCrimeRecyclerView.setVisibility(View.GONE);
mDefaultLayoutView.setVisibility(View.VISIBLE);
}
else
{
mCrimeRecyclerView.setVisibility(View.VISIBLE);
mDefaultLayoutView.setVisibility(View.GONE);
updateUI();
}

}

效果应该是实现了。

2 thoughts on “Java安卓学习总结(十七)

发表评论