第十三章 工具栏
有关工具栏菜单
定义资源
在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安卓学习总结(十七)”
复数字符串资源在中文情况下是无效的,需要切换成英文才能看出效果