如何用Toolbar取代ActionBar
来源:互联网 发布:aspen软件介绍 编辑:程序博客网 时间:2024/06/04 17:56
在 Android 3.0 开始,App Bar的功能逐渐被加入到 ActionBar中,而这个 ActionBar 被包含在 Theme 中,不过对于开发者来说,缺乏的灵活性, 而且伴随着每个版本的发布,ActionBar 也表现出差异,因此我们经常自定义一个 Topbar 来取代传统的 ActionBar。伴随着 android.support.v7.widget.Toolbar 的出现,这2个问题得以解决。这篇文章就来探讨如何把之前 ActionBar 上的功能用在 Toolbar 上。
如何添加Toolbar
使用 v7 support library
为了兼容低版本,需要使用v7兼容库,在Android Studio中,通过F4按键为项目添加Dependencies,来添加com.android.support:appcompat-v7。这样,就会在build.gradle中自动添加下面的一段
compile 'com.android.support:appcompat-v7:24.2.1'
然后 Activity 要继承自 AppcompatActivity
MainActivity extends AppCompatActivity
去掉 Theme 中默认包含的 ActionBar
既然要用 Toolbar 取代 ActionBar,就需要设计一个没有 ActionBar 的 Theme
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
为 Activity 添加 Theme
<activity android:name=".MainActivity" android:theme="@style/AppTheme">
布局中添加 Toolbar
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?android:attr/actionBarSize" android:background="@color/colorPrimary" android:elevation="4dp" app:titleTextColor="@android:color/white"/>
既然用 Toolbar 取代 ActionBar,基本的需要做到以下三点:
1. Toolbar 颜色(android:background)与原来一致
2. Toolbar 高度(android:layout_height)与原来一致
3. 按照md风格,我们增加一个投影(android:elvation 一般为 4dp)。
在 Activity 中,用 Toolbar 取代 ActionBar
mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar);
当我们把上面的做完了之后 ,Toolbar 就显示出来了,效果如下。
怎么使用 Toolbar
既然我们用 Toolbar 取代了 ActionBar,那么我们操作 Toolbar 就应该是操作 ActionBar了。
mToolbar = (Toolbar) findViewById(R.id.toolbar); mToolbar.setNavigationIcon(R.mipmap.ic_home_black_24dp); mToolbar.setLogo(R.mipmap.ic_launcher); mToolbar.setTitle("HelloToolbar"); mToolbar.setSubtitle("SubTitle"); setSupportActionBar(mToolbar);
得到效果如下
这是提一下的是这个最左边的导航图标,默认的话就是一个向左的箭头,如果我们不在 Toolbar 中设置,也可以在 ActionBar 中设置
mToolbar = (Toolbar) findViewById(R.id.toolbar); //在 Toolbar 中设置返回图标 //mToolbar.setNavigationIcon(R.mipmap.ic_home_black_24dp); mToolbar.setTitle("HelloToolbar"); setSupportActionBar(mToolbar); android.support.v7.app.ActionBar actionbar = getSupportActionBar(); //用 ActionBar 设置返回图标 actionbar.setDisplayHomeAsUpEnabled(true);
效果如下
那么现在问题来了,这个返回按键和硬件上的返回键有什么区别?硬件上的返回键就是如同人的逻辑思维一样,按照操作顺序依次返回。Toolbar 上的返回键一般就是返回到主 Home 页面,当然我们也可以选择让它返回到特定的页面。
使用 Toolbar 上的返回键
先看一个使用 Toolbar 上返回键的图
Activity 设置 Toolbar
SecondActivity 的 Toolbar 设置如下
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar1); toolbar.setNavigationIcon(R.mipmap.home); setSupportActionBar(toolbar); getSupportActionBar().setTitle("SecondActivity");
从这个代码可以看到toolbar.setNavigationIcon(R.mipmap.home);
就是等于 getSupportActionBar().setDisplayHomeAsUpEnabled(true);
, 只不过我们就是替换了一个图标。
AndroidManifest.xml 声明返回的 Activity
在 AndroidManifest.xml 文件中,设置 activity的 parentActivityName 属性(meta-data 为了兼容低版本)
<activity android:name=".MyChildActivity" android:parentActivityName=".MainActivity"> <!--meta-data兼容低版本--> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"/> </activity>
Toolbar 添加 Menu
基本的Menu
这与原来设置 Menu 的方式一致
/** * 为Toolbar设置Menu */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar_menu, menu); return super.onCreateOptionsMenu(menu); } /** * 处理选中的菜单 */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.delete1: break; } return super.onOptionsItemSelected(item); }
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/settings" android:icon="@mipmap/ic_menu_settings_holo_light" android:title="设置" app:showAsAction="never" /> <item android:id="@+id/sync" android:icon="@mipmap/sync_settings" android:title="同步" app:showAsAction="never" /> <item android:id="@+id/share" app:actionProviderClass="android.support.v7.widget.ShareActionProvider" android:icon="@mipmap/ic_menu_share" android:title="分享" app:showAsAction="ifRoom" /> <item android:id="@+id/action_search" android:icon="@mipmap/ic_menu_search" android:title="搜索" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="ifRoom|collapseActionView" /></menu>
这里特别提一下,关于 android.support.v7.widget.SearchView,我之前在 xml 文件中,用的是 android:actionViewClass,然后无论怎么点搜索按钮都没有用。 正确的写法是 app:actionViewClass
效果如下
从第二张图中,我们可以看到,在 overflow 中,默认是不显示图标的,那么我们怎么让它默认显示图标呢?
/** * 显示 OverFlow 中的图标 */ @Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { if (menu != null) { if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { Method m = menu.getClass().getDeclaredMethod( "setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch (Exception e) { } } } return super.onPrepareOptionsPanel(view, menu); }
通过反射,我们让图标显示了,现在的效果是这样的
发现图标不对称,这是因为图片大小不一致导致的。
添加ActionProvider
上面我们添加过 ShareActionProvider , 但是点击是没有效果的,因为我们还没有给它设置 Intent
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); MenuItem shareItem = menu.findItem(R.id.share); ShareActionProvider shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("image/*"); //shareIntent.putExtra(Intent.EXTRA_STREAM, myImageUri); shareActionProvider.setShareIntent(shareIntent); return super.onCreateOptionsMenu(menu); }
上面的代码中注释了一段,既然是分享,要有分享的东西,一般为图片或者文字信息,注释的代码是代表分享图片
当我们点击后,效果如下
添加ActionView
上面的代码中,我们添加过 SearchView
<item android:id="@+id/action_search" android:icon="@mipmap/ic_menu_search" android:title="搜索" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="ifRoom|collapseActionView" />
我们再监听下 SearchView 的展开收缩事件
MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { return false; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { return false; } });
Toolbar 上实现 PopMenu
PopMenu 是锚到 View 的菜单 ,如果空间足够,就显示在 View 的下方,否则显示在上方。有时候我们想定制自己的 Menu,我们需要在 ActionBar 上加上一个控件,如 ImageView,然后做出一个自己想要的弹出菜单的样式 。 在 ActionBar 上是很难定制的,我们往往选择自己写一个 Topbar,但是现在,我们用 Toolbar 可以实现。
在 Toolbar 上添加 ImageView,并实现 Popmenu 效果
mToolbar = (Toolbar) findViewById(R.id.toolbar); //在Toolbar上添加ImageView ImageView button = new ImageView(this); button.setImageResource(R.mipmap.ic_input_add); mToolbar.addView(button); //为ImageView设置参数 Toolbar.LayoutParams layoutParams = (Toolbar.LayoutParams) button.getLayoutParams(); layoutParams.gravity = GravityCompat.END; layoutParams.rightMargin = 20; //监听点击事件实现Popmenu效果 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PopupMenu popup = new PopupMenu(MainActivity.this, v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.toolbar_menu, popup.getMenu()); popup.show(); } }); setSupportActionBar(mToolbar);
res/menu/toolbar_menu.xml
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:icon="@mipmap/ic_launcher" android:title="设置" app:showAsAction="never"/> <item android:icon="@mipmap/ic_search_black_24dp" android:title="搜索" app:showAsAction="never"/></menu>
看下效果
这个显示效果相比较 overflow 的显示方式,是否看起来舒服一点?因为现在的显示方式是在 ImageView 的下方,而 overflow 的显示方式是覆盖了 overflow 图标了。 不过还有一点,我们还要给它设置图标了,那又如何设置了,这里需要用到反射。
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PopupMenu popup = new PopupMenu(MainActivity.this, v); try { Field[] fields = popup.getClass().getDeclaredFields(); for (Field field : fields) { if ("mPopup".equals(field.getName())) { field.setAccessible(true); Object menuPopupHelper = field.get(popup); Class<?> classPopupHelper = Class.forName(menuPopupHelper .getClass().getName()); Method setForceIcons = classPopupHelper.getMethod( "setForceShowIcon", boolean.class); setForceIcons.invoke(menuPopupHelper, true); break; } } } catch (Exception e) { e.printStackTrace(); } MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.toolbar_menu, popup.getMenu()); popup.show(); } });
现在我们来看下自己实现的 overflow 和 系统原本的 overflow的对比图
从效果看,是不是我们自定义的 overflow 已经没有了系统 overflow的缺点了?
当然最后我们还可以添加 Popmenu 的点击事件
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { return false; } });
Toolbar 实现 ActionMode Menu
之前由于都是采用 ListView,这篇文章我将用 RecyclerView,与时俱进吧。
效果如下
在写代码前,我们考虑如何做
- Adapter 提供长按和短按接口给 Activity,用于开启 ActionMode
- Activity实现两个接口,并在长按和短按中保存postion,并更新RecyclerView的Item背景色
- 开启ActionMode后,点击 delete menu,删除选中的选项
思路大致就是这样,我试过细分每个步骤的代码,但是整体性不强,所以直接上了所有代码
/** * Created by David Chow on 2016/10/9. */public class MainActivity extends AppCompatActivity implements MyAdapter.onItemListener { private Toolbar mToolbar; private RecyclerView mRecyclerView; private MyAdapter mAdapter; private List<String> mDatas; private ActionMode mActionMode; private ActionMode.Callback mCallback; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar); ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setTitle("Toolbar"); mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mDatas = new ArrayList<>(); for (int i = 0; i < 20; i++) { mDatas.add(String.valueOf(i)); } mAdapter = new MyAdapter(mDatas); mAdapter.setOnItemClickListener(this); mRecyclerView.setAdapter(mAdapter); mCallback = new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.delete: Toast.makeText(MainActivity.this, "Delete~~~", Toast.LENGTH_SHORT).show(); // 删除数据 mAdapter.removeSelectedItems(); // 退出ActionMode mActionMode.finish(); return true; } return false; } @Override public void onDestroyActionMode(ActionMode mode) { // 重置ActionMode mActionMode = null; // 取消所有选中状态 mAdapter.clearAllSelectedItems(); } }; } @Override public void onClick(int position) { if (mActionMode != null) { toggleSelection(position); } } private void toggleSelection(int position) { // 根据position ,用Adapter更新Item选中状态和背景色 mAdapter.toggleSelection(position); // 更新 ActionMode 上的计数 mActionMode.setTitle(String.valueOf(mAdapter.getSelectedCount())); } @Override public boolean onLongClick(int position) { //开启 ActionMode if (mActionMode == null) { mActionMode = startSupportActionMode(mCallback); } toggleSelection(position); return true; }}
/** * Created by David Chow on 2016/10/9. */public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mDatas; private onItemListener mListener; private SparseBooleanArray mSelectedItems; public MyAdapter(List<String> mDatas) { this.mDatas = mDatas; mSelectedItems = new SparseBooleanArray(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false)); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(mDatas.get(position)); holder.mCardView.setBackgroundColor(mSelectedItems.get(position) ? Color.parseColor("#ff575bd4") : Color.parseColor("#ffffffff")); } /** * 获取选中Item的数量 */ @Override public int getItemCount() { return mDatas.size(); } /** * 更新选中Item的状态和背景色 */ public void toggleSelection(int position) { // 更新选中的状态 if (mSelectedItems.get(position)) { mSelectedItems.delete(position); } else { mSelectedItems.put(position, true); } // 更新Item notifyItemChanged(position); } /** * 获取选中Item的个数 */ public int getSelectedCount() { return mSelectedItems.size(); } /** * 取消所有选中的状态并更新背景 */ public void clearAllSelectedItems() { List<Integer> positions = getPositions(); //清除所有的状态 mSelectedItems.clear(); // 更新背景 for (int i = 0; i < positions.size(); i++) { notifyItemChanged(positions.get(i)); } } /** * 删除选中的Item */ public void removeSelectedItems() { List<Integer> positions = getPositions(); // 从大到小排序 Collections.sort(positions, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); for (int i = 0; i < positions.size(); i++) { int position = positions.get(i); mDatas.remove(position); notifyItemRemoved(position); } } /** * 获取选中Item的positions */ @NonNull private List<Integer> getPositions() { List<Integer> positions = new ArrayList<>(); // 获取选中的position集合 for (int i = 0; i < mSelectedItems.size(); i++) { positions.add(mSelectedItems.keyAt(i)); } return positions; } public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { TextView mTextView; CardView mCardView; public ViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.item_tv); mCardView = (CardView) itemView.findViewById(R.id.cardView); itemView.setOnClickListener(this); itemView.setOnLongClickListener(this); } @Override public void onClick(View v) { if (mListener != null) { mListener.onClick(getLayoutPosition()); } } @Override public boolean onLongClick(View v) { if (mListener != null) { return mListener.onLongClick(getLayoutPosition()); } return false; } } public interface onItemListener { void onClick(int position); boolean onLongClick(int position); } public void setOnItemClickListener(onItemListener listener) { mListener = listener; }}
项目地址:https://github.com/buxiliulian/Toolbar-RecyclerView
- 如何用Toolbar取代ActionBar
- 使用ToolBar取代过去Actionbar(material design)
- ToolBar(ActionBar)
- Toolbar,ActionBar
- ActionBar and ToolBar
- 利用Toolbar替换ActionBar
- ActionBar和Toolbar
- ToolBar替代ActionBar
- Toolbar与Actionbar
- ActionBar 和 Toolbar详解
- toolbar 替代actionbar
- ActionBar/Toolbar定制ui
- ToolBar(5.0以后替代ActionBar)
- Android:Material系列:ActionBar-->Toolbar
- 修改Toolbar/Actionbar的图标
- Android:Material系列:ActionBar-->Toolbar
- Android toolbar与actionbar区别
- Android UI(ActionBar+Toolbar)详解
- maven构建Spring4+SpringMVC+Mybatis3
- ceil、floor
- CSS3快速上手之12:2D 转换
- Android-新建的项目有错
- 不用submit的validate验证
- 如何用Toolbar取代ActionBar
- sql——查询大于、小于某个日期的写法
- (3)nginx的虚拟主机配置
- 巧用循环不变式书写正确的二分查找算法(看不懂我撞墙)
- 将博客搬至CSDN
- linux文件读写的流程
- Java基础--访问修饰符
- Android JNI知识简介
- PHP网页的工作原理