2、修改主题 ,去掉默认的 ActionBar,v7 兼容库给我们提供了一个默认的没有 ActionBar 的主题
<application
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>
在这里,我把 application 的设置为没有 ActionBar 的主题 ,这样所有的 Activity 都会应用这个主题 ,但是实际中并不是所有的 Activity 都需要自己设计 ActionBar,因此我们最好把这个主题应用到单独 Activity 上。
例如
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme.NoActionbar">
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionbar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
3、在布局中添加 Toolbar
<android.support.v7.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
我们可以看到,ToolBar 的高度用的是系统的 ActionBar的高度,在 Material Design 中,需要为一个视图设计 一个投掷阴影 android:elevation 通常为4dp,为了与 Material Design 设计规则一致 ,我们还需要为 ToolBar 设计着色,取的就是 colorPrimary 的颜色 。
4、在代码中把 Toolbar 设置为 App Bar ,并设置它的 Navigation Icon, Logo,Title,SubTitle
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationIcon(R.mipmap.ic_action_back);
toolbar.setLogo(R.mipmap.ic_launcher);
toolbar.setTitle("Toolbar");
toolbar.setSubtitle("Toolbar SubTitle");
setSupportActionBar(toolbar);
看下效果
可是标题的颜色和 overflow 的颜色并不统一,全改为白色或许可以
<style name="AppTheme.NoActionbar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- title -->
<item name="android:textColorPrimary">@android:color/white</item>
<!--subtitle-->
<item name="android:textColorSecondary">@android:color/white</item>
</style>
还可以吧~
如何使用Toolbar
一旦我们设置了 ToolBar 作为了App Bar,那么就可以使用 v7 兼容包中的 ActionBar 类的方法
例如
private void setupActionbar() {
android.support.v7.app.ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.hide();
}
我们在操作ActionBar的时候,也就相当于在操作Toolbar,因此在 Acionbar 上设置 title,Logo 都会覆盖 toolbar 上的显示
在 Toolbar 上增加 action menu 中的 options menu (>=3.0)
在上面的图中,可以看到 action menu 出现在 toolbar 上,这与之前 action menu 添加到 action bar 上一样操作
定义menu 菜单
<?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/delete"
android:icon="@mipmap/ic_action_favorite"
android:title="Favorite"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@mipmap/ic_launcher"
android:title="Settings" />
</menu>
显示menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
响应menu事件
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.favorite:
Toast.makeText(this, "Favorite", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
在 Toolbar 中增加 action menu 中的 contextual menu 之 contextual action mod ( >= 3.0)
先来看下效果
传统的是用 ListView,但是为了跟上时代的脚步,我想是时候用 RecyclerView 了,但是它没有提供如 ListView 一样的方法
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener();
突然发现 ,RecyclerView没有这个方法,只能自己来做了,那么我们就需要想想如何设计这个问题。
首先,长按事件,可以在 ViewHolder 中提供接口
然后在 Activity 实现,通过实现长按来开启contextual action mode
这个时候,我们需要在 adapter 中改变 item 的颜色 ,我们可以用 notifyItemChanged(position) 来让 RecyclerView 重新调用 onBindViewHolder() 方法来给 item 设置背景色,然后,我们可以选择其它的 item 并同时让它们变色,再响应 contextual action mode 的 delete 响应事件来删除 item。这样看来一切很完美 ,那我们来一步一步实现。
1、先实现 RecyclerView
item 布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_cardview"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="2dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/maintitle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="123"
android:textSize="20sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
实现 Recycler.Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private recyclerViewListener mListener;
private List<String> mDatas;
public MyAdapter(List<String> list, MyAdapter.recyclerViewListener listener) {
mDatas = list;
mListener = listener;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
holder.title.setText(mDatas.get(position));
}
@Override
public int getItemCount() {
return mDatas.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView title;
CardView cardView;
public ViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.maintitle);
cardView = (CardView) itemView.findViewById(R.id.item_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 recyclerViewListener {
void onClick(int position);
boolean onLongClick(int position);
}
}
在MainActivity.java中添加Adapter,并添加空的 onClick() 和 onLongClick() 实现
private void setupRecyclerView() {
mDatas = new ArrayList<>();
for (int i = 0; i < 100; i++) {
mDatas.add(String.valueOf(i));
}
mRecyclerView = (RecyclerView) findViewById(R.id.my_recyclerView);
mAdapter = new MyAdapter(mDatas, this);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mRecyclerView.setAdapter(mAdapter);
}
这样,RecyclerView就已经显示出来了
2、实现长按和短按
mCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
getMenuInflater().inflate(R.menu.action_mode_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:
mActionMode.finish();
return true;
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
@Override
public void onClick(int position) {
toggleSelection(position);
}
@Override
public boolean onLongClick(int position) {
if (mActionMode == null) {
mActionMode = startSupportActionMode(mCallback);
}
toggleSelection(position);
return true;
}
private void toggleSelection(int position) {
mAdapter.toggleSelection(position);
int count = mAdapter.getSelectedItemCount();
if (count == 0) {
mActionMode.finish();
} else {
mActionMode.setTitle(String.valueOf(count));
}
}
3、在 Adapter 中添加实现变色
mSelectedItems = new SparseBooleanArray();
public void toggleSelection(int position) {
if (mSelectedItems.get(position, false)) {
mSelectedItems.delete(position);
} else {
mSelectedItems.put(position, true);
}
notifyItemChanged(position);
}
通过调用 notifyItemChanged() 来让 RecyclerView 重新调用 onBindViewHolder(),然后让背景变色
@Override
public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
holder.title.setText(mDatas.get(position));
holder.cardView.setBackgroundColor(mSelectedItems.get(position, false) ? Color.parseColor("#883a44b7") : Color.parseColor("#ffffffff"));
}
这个时候,可以看下效果
现在出现两个问题,出现2个 "actionbar" ,而且我们要操作的 action bar 背景颜色与我们设计的主题不一致 。另外,当我们点击了 delete 菜单的时候 ,被选中的 item 颜色并没有撤消?
如何解决出现2个 "actionbar" 问题
<style name="AppTheme.NoActionbar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- title -->
<item name="android:textColorPrimary">@android:color/white</item>
<!--subtitle-->
<item name="android:textColorSecondary">@android:color/white</item>
<item name="windowActionModeOverlay">true</item>
<item name="actionModeBackground">@color/colorPrimary</item>
</style>
windowActionModeOverlay 是表示 action mode 覆盖 actionbar,actionModeBackground 当然就是 action mode的背景啦,别问我为什么知道,因为我就是随便试试就出来了。
如何解决在action mode消失后,选中的 item 背景颜色没有撤消?我们可以想想,在 ActionModeCallback 消失后,这个时候我们应该通过 notifyItemChanged() 再次让 recyclerview 来调用 onBindViewHolder() 来刷新 item
@Override
public void onDestroyActionMode(ActionMode mode) {
mAdapter.clearSelectedItems();
mActionMode = null;
}
public void clearSelectedItems() {
for (int i = 0; i < mSelectedItems.size(); i++) {
notifyItemChanged(mSelectedItems.keyAt(i));
}
mSelectedItems.clear();
}
onBindViewHolder()就可以再次刷新了
@Override
public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
holder.title.setText(mDatas.get(position));
holder.cardView.setBackgroundColor(mSelectedItems.get(position, false) ? Color.parseColor("#883a44b7") : Color.parseColor("#ffffffff"));
}
是不是很 perfect ~
4、最后一步,我们要做到删除选中的 item,这个操作当然是在 ActionMode.Callback中的
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
mAdapter.removeSelectedItems();
mActionMode.finish();
return true;
}
return false;
}
常规的想,我们可以根据
mSelectedItems = new SparseBooleanArray();
mSelectedItems中的 key 值 ,也就是 item 的 postion ,来一个一个删除 ,但是并不能很好如我们如愿,这就是涉及到 recyclerview 的一个 update 过程 ,当我们删除了其中一个 item 时候 ,它会重新排列 item ,这个时候第个 item 的 positon 就变了,也就是说,如果 key 值依次为 [1,4,3] ,那么实际中我们要删除的 positon 为 [1,3,2],当时我有点懵B了,后来 google 了下,在 这个项目中找到答案 ,我们可以对这个 key 值进行从大到小排序 ,这样 [1,.4,3] 就变为了 [4,3,1] ,这样我们在删除第5个的时候 ,前面的顺序还是没变,这样没不影响了,实在是屌 ~
public void removeItem(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
public void removeSelectedItems() {
List<Integer> positions = new ArrayList<>();
for (int i = 0; i < mSelectedItems.size(); i++) {
positions.add(mSelectedItems.keyAt(i));
}
Collections.sort(positions, new Comparator<Integer>() {
@Override
public int compare(Integer lhs, Integer rhs) {
return rhs - lhs;
}
});
for (int i = 0; i < positions.size(); i++) {
removeItem(positions.get(i));
}
}
从这篇我们可以看到了 RecyclerView 和 Toolbar 的灵活性,但是这里讲述的也只是一角,后续我会继续完善,并对Android support Library 的新控件进行探讨~