Android開發筆記(一百一十九)工具欄ToolBar
Toolbar
在前面的博文《Android開發筆記(二十)頂部導航欄》中,我們學習了ActionBar的用法,可是ActionBar著實是不怎麼好用,比如文字風格不能定製、圖示不能定製,而且還存在低版本的相容性問題,所以實際開發中大家還是不傾向使用ActionBar。為此,Android提供了加強版的工具欄控制元件即Toolbar,因為Toolbar繼承自ViewGroup,而且可在佈局檔案中像其它佈局檢視一樣使用,所以靈活性大大的提高了。既然Android都與時俱進了,那我們也不能落後,現在就來好好學學Toolbar的用法。匯入android-support-v7-appcompat
Toolbar包含在android-support-v7-appcompat.jar包中,但app工程還不能直接使用這個jar包,因為v7-appcompat是一個完整的工程,jar包裡面大量引用了工程中的圖片資源,所以我們要先把v7-appcompat匯入為一個庫工程,然後app工程再引用這個庫工程。具體步驟如下所示:1、SDK的Extra元件中的“Android Support Library”要更新到最新版本。
2、把v7-appcompat匯入為一個庫工程,v7-appcompat的源路徑是sdk\extras\android\support\v7\appcompat。
3、把project.properties中的target改為23(注意庫工程和app工程都要改),不然會出現如下錯誤:
Error:Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Inverse'.
Error:Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Material.Button.Colored'.
4、刪除values-v11與values-v14下面的styles.xml(注意庫工程和app工程都要刪),不然編譯報錯:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.exmtoolbar/com.example.exmtoolbar.MainActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
在專案中引入Toolbar
因為Toolbar與ActionBar都佔著頂部導航欄的位置,所以要想引入Toolbar就得先關閉ActionBar啦,具體步驟如下所示:1、在styles.xml中定義一個不包含ActionBar的風格樣式
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/blue_light</item>
<item name="colorPrimaryDark">@color/blue_light</item>
<item name="colorAccent">@color/blue_light</item>
</style>
2、修改AndroidManifest.xml,把application節點的android:theme屬性值改為第一步定義的風格,如android:theme="@style/AppBaseTheme"3、頁面佈局檔案的根節點改為LinearLayout,且為vertical垂直方向;然後增加一個Toolbar元素,因為Toolbar本質是個ViewGroup,所以也可在它下面新增別的控制元件。下面是個佈局例子片段:
<android.support.v7.widget.Toolbar
android:id="@+id/tl_head"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
4、Activity程式碼改為繼承AppCompatActivity,注意早期的v7包是沒有AppCompatActivity的,所以前面才說要先把v7包更新到最新版本。5、同樣修改AndroidManifest.xml,給該activity節點補充屬性值android:theme="@style/AppBaseTheme"
6、回到Activity程式碼,獲取一個Toolbar物件,並呼叫setSupportActionBar方法設定預設的導航欄為當前的Toolbar。
Toolbar的常用方法
Toolbar比ActionBar靈活,主要便是它提供了多個方法來修改控制元件風格,下面是Toolbar的常用方法:setLogo : 設定工具欄圖示。
setTitle : 設定標題文字。
setTitleTextAppearance : 設定標題的文字風格。
setTitleTextColor : 設定標題的文字顏色。
setSubtitle : 設定副標題文字。副標題在標題下方。
setSubtitleTextAppearance : 設定副標題的文字風格。
setSubtitleTextColor : 設定副標題的文字顏色。
setNavigationIcon : 設定導航圖示。導航圖示在工具欄圖示左邊。
setNavigationOnClickListener : 設定導航圖示的點選監聽器。
setOverflowIcon : 設定溢位選單的按鈕圖示。
showOverflowMenu : 顯示溢位選單圖示。
hideOverflowMenu : 隱藏溢位選單圖示。
dismissPopupMenus : 關閉已彈出的選單。
SearchView
v7包在帶來Toolbar的同時,也帶來了一個加強版的SearchView。有關原SearchView的使用說明參見《Android開發筆記(二十)頂部導航欄》,新舊兩個SearchView的用法其實大同小異,當然新版的功能會更強大些,下面是android.widget.SearchView與android.support.v7.widget.SearchView的主要區別:二者在呼叫時的區別:
1、選單佈局檔案中,舊SearchView的寫法是android:actionViewClass="android.widget.SearchView",而新SearchView的寫法是app:actionViewClass="android.support.v7.widget.SearchView"
2、程式碼中獲取SearchView物件,新控制元件還可通過v7類MenuItemCompat的getActionView方法來獲取。
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
二者在功能上的區別:
1、編輯框其實是個SearchAutoComplete控制元件,該控制元件在舊SearchView中是隱藏的,在新SearchView中是開放的,所以我們可隨意修改v7編輯框的顯示風格。
2、基於上一點,新控制元件可取到SearchAutoComplete的物件,因此我們可給該物件註冊自動完成的字串介面卡,在使用者輸入文字時,介面會自動彈出符合搜尋條件的關鍵詞列表;
3、setAppSearchData方法在舊SearchView中是隱藏的,在新SearchView中是開放的,所以舊控制元件只能傳遞搜尋文字給結果頁面,而新控制元件允許傳遞其他的額外資訊給搜尋結果頁面。
Toolbar執行問題處理集錦
更換導航欄還是存在一些相容問題的,下面是博主發現的幾個情況及其解決辦法:1、溢位選單的選單項已經設定為android:showAsAction="ifRoom",但即使工具欄上還有空間,該選單項也不會顯示在工具欄上。解決辦法:
在選單佈局檔案的menu根節點增加屬性xmlns:app="http://schemas.android.com/apk/res-auto",然後把android:showAsAction="ifRoom"改為app:showAsAction="ifRoom"。
2、溢位選單列表在選單文字左側顯示圖示的方法,使用ActionBar時正常,使用Toolbar時反而不會顯示圖示了。解決辦法:
ActionBar的featureId是8,Toolbar的featureId是108,所以在圖示顯示方法內部,要同時判斷這兩個數值,而不能像以前那樣僅僅判斷Window.FEATURE_ACTION_BAR。修改之後的圖示顯示方法如下:
//顯示OverflowMenu的Icon
public static void setOverflowIconVisible(int featureId, Menu menu) {
//ActionBar的featureId是8,Toolbar的featureId是108
if (featureId%100 == Window.FEATURE_ACTION_BAR && 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) {
Log.d(TAG, e.getMessage());
}
}
}
}
3、程式碼中呼叫getActionView方法獲取SearchView物件時,發現取到的SearchView為空。解決辦法:
把選單佈局檔案裡的android:actionViewClass="android.support.v7.widget.SearchView"改為app:actionViewClass="android.support.v7.widget.SearchView"。
下面是新版Toolbar與SearchView的使用截圖:
下面是新版Toolbar與SearchView的使用程式碼示例:
import java.util.Date;
import com.example.exmtoolbar.util.Utils;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
private TextView tv_desc;
private String[] mFormatArray = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd",
"yyyy年MM月dd日HH時mm分ss秒", "yyyy年MM月dd日"};
private String mFormat = mFormatArray[0];
private Date mNowTime = new Date();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_desc = (TextView) findViewById(R.id.tv_desc);
Toolbar tl_head = (Toolbar) findViewById(R.id.tl_head);
tl_head.setBackgroundResource(R.color.blue_light);
tl_head.setLogo(R.drawable.ic_launcher);
tl_head.setTitle("標題");
tl_head.setSubtitle("副標題");
tl_head.setNavigationIcon(R.drawable.ic_back);
setSupportActionBar(tl_head);
}
private void initSearchView(Menu menu) {
MenuItem menuItem = menu.findItem(R.id.menu_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
if(searchView == null){
Log.d(TAG, "Fail to get SearchView.");
} else {
//新舊SearchView公用程式碼開始
searchView.setIconifiedByDefault(true);
searchView.setSubmitButtonEnabled(true);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
ComponentName cn = new ComponentName(this, SearchResultActvity.class);
SearchableInfo info = searchManager.getSearchableInfo(cn);
if(info == null){
Log.d(TAG, "Fail to get SearchResultActvity.");
}
searchView.setSearchableInfo(info);
//新舊SearchView公用程式碼結束
sac_text = (SearchView.SearchAutoComplete) searchView.findViewById(R.id.search_src_text);
sac_text.setTextColor(Color.WHITE);
sac_text.setHintTextColor(Color.WHITE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
doSearch(newText);
return true;
}
});
Bundle bundle = new Bundle();
bundle.putString("hi", "hello");
searchView.setAppSearchData(bundle);
}
}
private SearchView.SearchAutoComplete sac_text;
private String[] hintArray = {"ab", "abc", "abcde", "abHtp", "aaeet", "aab"};
private void doSearch(String text) {
if (text.indexOf("a") == 0) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this, R.layout.list_auto, hintArray);
sac_text.setAdapter(adapter);
sac_text.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
TextView tv_item = (TextView) view;
sac_text.setText(tv_item.getText());
}
});
}
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
//顯示選單項左側的圖示
Utils.setOverflowIconVisible(featureId, menu);
return super.onMenuOpened(featureId, menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
//對搜尋框做初始化
initSearchView(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
} else if (id == R.id.menu_refresh) {
mNowTime = new Date();
tv_desc.setText("當前重新整理時間: "+Utils.getFormatDateTime(mNowTime, mFormat));
return true;
} else if (id == R.id.menu_about) {
Toast.makeText(this, "這個是工具欄的演示demo", Toast.LENGTH_LONG).show();
return true;
} else if (id == R.id.menu_quit) {
finish();
}
return super.onOptionsItemSelected(item);
}
}
下面是搜尋結果頁面的程式碼:
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class SearchResultActvity extends AppCompatActivity {
private static final String TAG = "SearchResultActvity";
private TextView tv_search_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_result);
tv_search_result = (TextView) findViewById(R.id.tv_search_result);
doSearchQuery(getIntent());
Toolbar tl_result = (Toolbar) findViewById(R.id.tl_result);
tl_result.setBackgroundResource(R.color.blue_light);
tl_result.setLogo(R.drawable.ic_launcher);
tl_result.setTitle("搜尋結果頁");
tl_result.setNavigationIcon(R.drawable.ic_back);
setSupportActionBar(tl_result);
}
private void doSearchQuery(Intent intent){
if(intent == null) {
return;
} else {
//如果是通過ACTION_SEARCH來呼叫,即如果通過搜尋呼叫
if(Intent.ACTION_SEARCH.equals(intent.getAction())){
//獲取額外資訊
Bundle bundle = intent.getBundleExtra(SearchManager.APP_DATA);
String value = bundle.getString("hi");
//獲取搜尋內容
String queryString = intent.getStringExtra(SearchManager.QUERY);
tv_search_result.setText("您輸入的搜尋文字是:"+queryString+", 額外資訊:"+value);
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.null_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
Log.d(TAG, "finish activity");
finish();
}
return super.onOptionsItemSelected(item);
}
}
點選下載本文用到的工具欄Toolbar的工程程式碼
點此檢視Android開發筆記的完整目錄
相關文章
- qml 導航欄TabBar 工具欄ToolBartabBar
- Android開發筆記Android筆記
- Android 開發學習筆記Android筆記
- Android開發筆記[17]-桌面小部件Android筆記
- Android開發筆記[10]-關於頁Android筆記
- Android開發筆記——TextView 多行時 ellipsizeAndroid筆記TextView
- Chrome 自帶開發者工具筆記Chrome筆記
- Android開發筆記[13]-圖案密碼Android筆記密碼
- Android開發筆記[18]-使用本地模組Android筆記
- Android ToolBar 使用完全解析Android
- django-debug-toolbar: django開發之效能強大的檢測工具Django
- Android 快取工具 DiskLruCache 學習筆記Android快取筆記
- 聚焦 Android 11: Android 開發者工具Android
- Android開發筆記——TextView文字設定不同顏色Android筆記TextView
- Android開發隨記Android
- Android開發筆記[16]-簡單使用wasmedge執行時Android筆記ASM
- Android開發筆記[12]-使用AAR方式嵌入flutter頁面Android筆記Flutter
- 張紹文android開發高手課讀書筆記1Android筆記
- 閱讀《阿里巴巴Android開發手冊1.0.1》筆記阿里Android筆記
- Android開發工具類之DownloadManagerProAndroid
- ToolBar、TabLayout、Fragment+ViewPager的開發實踐TabLayoutFragmentViewpager
- 馬克筆記—Android 端開源的 Markdown 筆記應用筆記Android
- Laravel 開發筆記Laravel筆記
- uinapp 開發筆記UIAPP筆記
- fyne 開發筆記筆記
- golang 開發筆記Golang筆記
- FFmpeg開發筆記(十六)Linux交叉編譯Android的OpenSSL庫筆記Linux編譯Android
- FFmpeg開發筆記(八)Linux交叉編譯Android的FFmpeg庫筆記Linux編譯Android
- android:ToolBar詳解(手把手教程)(2)Android
- Android AlertDialog筆記Android筆記
- C++ Qt開發:ToolBar與MenuBar選單元件C++QT元件
- 星雲 Android 開發工具箱Android
- Android 開發藝術探索筆記之一 -- Android 的生命週期和啟動模式Android筆記模式
- Android開發筆記——透明狀態列與透明虛擬按鍵Android筆記
- 阿里巴巴Android開發手冊V1.0.0隨手筆記阿里Android筆記
- Java 開發筆記16Java筆記
- 【Python】GUI開發筆記PythonGUI筆記
- 元件包開發筆記元件筆記
- ExtJS 6.2開發筆記JS筆記