編輯:關於Android編程
在 Android 3.0 開始,App Bar的功能逐漸被加入到 ActionBar中,而這個 ActionBar 被包含在 Theme 中,不過對於開發者來說,缺乏的靈活性, 而且伴隨著每個版本的發布,ActionBar 也表現出差異,因此我們經常自定義一個 Topbar 來取代傳統的 ActionBar。伴隨著 android.support.v7.widget.Toolbar 的出現,這2個問題得以解決。這篇文章就來探討如何把之前 ActionBar 上的功能用在 Toolbar 上。
為了兼容低版本,需要使用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
既然要用 Toolbar 取代 ActionBar,就需要設計一個沒有 ActionBar 的 Theme
為 Activity 添加 Theme
既然用 Toolbar 取代 ActionBar,基本的需要做到以下三點:
1. Toolbar 顏色(android:background)與原來一致
2. Toolbar 高度(android:layout_height)與原來一致
3. 按照md風格,我們增加一個投影(android:elvation 一般為 4dp)。
mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar);
當我們把上面的做完了之後 ,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);
效果如下
vczYtqi1xNKzw+ahozwvcD4NCjxociAvPg0KPGgyIGlkPQ=="使用-toolbar-上的返回鍵">使用 Toolbar 上的返回鍵
先看一個使用 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 為了兼容低版本)
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);
}
這裡特別提一下,關於 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
我們再監聽下 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
看下效果
這個顯示效果相比較 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 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 {
private List mDatas;
private onItemListener mListener;
private SparseBooleanArray mSelectedItems;
public MyAdapter(List 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 positions = getPositions();
//清除所有的狀態
mSelectedItems.clear();
// 更新背景
for (int i = 0; i < positions.size(); i++) {
notifyItemChanged(positions.get(i));
}
}
/**
* 刪除選中的Item
*/
public void removeSelectedItems() {
List positions = getPositions();
// 從大到小排序
Collections.sort(positions, new Comparator() {
@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 getPositions() {
List 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;
}
}
今天天氣不錯 蝦米 來講解 Android中輸入的控件 在 Android中輸入控件是常見的 隨處可見 今天又時間 寫一篇Android中輸入控件的集合 了解他們
一些IM聊天軟件我們發現,他的展現形式,是左右分開的形式,而我們的listview很多時候是顯示同一個布局,其實BaseAdapter中有2個重要的方法在大多數情況下我們
ListView是安卓中非常常用的一個控件。安卓設計使用Adapter來對ListView進行管理。但是系統提供的Adapter無法滿足一些復雜的顯示情況,這個時候我們就
異步任務 AsyncTask使用 android中實現異步機制主要有Thread加Handler和AsyncTask,今天主要記錄一下A