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