一、Contacts應用的主界面和聯繫人詳情界面增加頂部菜單添加退出按鈕 通過Hierarchy View 工具可以發現 主界面對應的類為 PeopleActivity 聯繫人詳情界面對應的類為 QuickContactActivity 左上角的退出按鈕其實很簡單,系統actionBar已經幫我們實 ...
一、Contacts應用的主界面和聯繫人詳情界面增加頂部菜單添加退出按鈕
通過Hierarchy View 工具可以發現
主界面對應的類為 PeopleActivity
聯繫人詳情界面對應的類為 QuickContactActivity
左上角的退出按鈕其實很簡單,系統actionBar已經幫我們實現了這一功能,只是沒有顯示出來而已。在onCreate()方法中,在setContentView()方法之後,添加如下代碼即可顯示返回的箭頭
ActionBar mActionBar = getActionBar();
if (mActionBar != null) {
Log.i(TAG, "getSupportActionBar != null....");
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(true);
}
接下來在onOptionsItemSelected()中監聽返回按鈕的事件即可
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
finish();
}
return true;
}
....
}
圖1 左上角返回退出功能
二、第三方app拉起主界面時直接顯示模糊查詢對應的聯繫人列表
簡單分析一下,模糊查詢需要對應的查詢聯繫人名稱,可以通過intent傳遞參數,這裡定義為String類型,當傳遞參數不為null時,模擬手動點擊搜索框對應的邏輯。如下在 PeopleActivity 的 onCreate()方法中增加獲取參數的代碼
final String queryString = getIntent().getStringExtra("queryString");
if (!TextUtils.isEmpty(queryString)) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
showQueryTextFragment(queryString);
}
}, 100);//讓搜索邏輯延遲100ms執行
}
通過測試發現,不加延遲觸發搜索框對應的邏輯並不會顯示模糊查詢結果界面。接下來我們分析點擊搜索框對應的邏輯代碼,找到搜索框對應的控制項id,menu_search, 回到剛剛的菜單監聽方法 onOptionsItemSelected()中
@Override
public boolean onOptionsItemSelected(MenuItem item) {
...
switch (item.getItemId()) {
case R.id.menu_search: {
onSearchRequested();
return true;
}
}
...
}
@Override
public boolean onSearchRequested() { // Search key pressed.
Log.d(TAG, "[onSearchRequested]");
//不在搜索模式下,也就是沒有點擊過搜索框
if (!mActionBarAdapter.isSelectionMode()) {
//獲取焦點,彈出鍵盤
mActionBarAdapter.setSearchMode(true);
}
return true;
}
從上面不難看出最終調用 mActionBarAdapter 的方法,我們接著跟進去
源碼位置 packages/apps/Contacts/src/com/android/contacts/activities/ActionBarAdapter.java
public void setSearchMode(boolean flag) {
if (mSearchMode != flag) {
mSearchMode = flag;
update(false /* skipAnimation */);
if (mSearchView == null) {
return;
}
if (mSearchMode) {
mSearchView.setEnabled(true);
setFocusOnSearchView();
} else {
// Disable search view, so that it doesn't keep the IME visible.
mSearchView.setEnabled(false);
}
setQueryString(null);
} else if (flag) {
// Everything is already set up. Still make sure the keyboard is up
//需要註釋此處,不然多次調用並退出再次拉起容易出現鍵盤彈出的情況
//if (mSearchView != null) setFocusOnSearchView();
}
}
public void setFocusOnSearchView() {
//mSearchView獲取焦點(先獲取焦點才能彈出鍵盤)
mSearchView.requestFocus();
//彈出鍵盤
showInputMethod(mSearchView); // Workaround for the "IME not popping up" issue.
}
private void showInputMethod(View view) {
final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(view, 0);
}
}
看到這裡我們可以猜想到 mSearchView 肯定設置了文字改變監聽,繼續查找 addTextChangedListener
...
mSearchView.setInputType(EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
mSearchView.addTextChangedListener(new SearchTextWatcher());
...
private class SearchTextWatcher implements TextWatcher {
@Override
public void onTextChanged(CharSequence queryString, int start, int before, int count) {
if (queryString.equals(mQueryString)) {
return;
}
//當前輸入的模糊查詢的名稱
mQueryString = queryString.toString();
if (!mSearchMode) {
if (!TextUtils.isEmpty(queryString)) {
setSearchMode(true);
}
} else if (mListener != null) {
//回調通知 PeopleActivity 改變界面
mListener.onAction(Action.CHANGE_SEARCH_QUERY);
}
mClearSearchView.setVisibility(
TextUtils.isEmpty(queryString) ? View.GONE : View.VISIBLE);
}
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
}
回到 PeopleActivity 中找到監聽 Action.CHANGE_SEARCH_QUERY 的代碼如下
@Override
public void onAction(int action) {
Log.d(TAG,"[onAction]action = " + action);
/// M: [vcs] @{
if (mVcsController != null) {
mVcsController.onActionVcs(action);
}
/// @}
switch (action) {
...
case ActionBarAdapter.Listener.Action.CHANGE_SEARCH_QUERY:
//獲取當前輸入的模糊查詢姓名
final String queryString = mActionBarAdapter.getQueryString();
//顯示對應的fragment
setQueryTextToFragment(queryString);
updateDebugOptionsVisibility(
ENABLE_DEBUG_OPTIONS_HIDDEN_CODE.equals(queryString));
break;
default:
throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
}
}
到此,搜索框模糊查詢對應的邏輯就分析完了,那麼我們就模擬調用對應的邏輯就ok了,再來把整體流程捋一遍,
點擊搜索框->獲取焦點->彈出鍵盤->輸入姓名->收到文字內容改變的監聽->將輸入的內容回調給 PeopleActivity->收到回調顯示對應的結果Fragment
好了,通過調用EditText.setText()方法也能觸發文字內容改變的監聽,前提是要先獲取焦點,那麼我們的 showQueryTextFragment() 實現如下
private void showQueryTextFragment(String queryString){
Log.d(TAG, "[showQueryTextFragment]");
if (!mActionBarAdapter.isSelectionMode()) {
Log.e(TAG, "[queryString==]"+queryString);
mActionBarAdapter.setSearchMode(true);
mActionBarAdapter.setQueryString(queryString);
}
}
圖2 第三方app拉起主界面顯示對應的聯繫人
三、第三方app拉起聯繫人詳情界面只滑動到一半顯示的問題
-
圖3 拉起只顯示一半
圖4 拉起完全顯示
首先從系統的聯繫人列表界面點擊進入詳情界面是能完整顯示的,所以猜想應該是傳遞的參數不太一樣。所以還是從onCreate()方法看下來
public class QuickContactActivity extends ContactsActivity {
/**
* QuickContacts immediately takes up the full screen. All possible information is shown.
* This value for {@link android.provider.ContactsContract.QuickContact#EXTRA_MODE}
* should only be used by the Contacts app.
*/
public static final int MODE_FULLY_EXPANDED = 4;
//看上面的註釋就知道了肯定是跟這個變數有關係, 立刻顯示全屏,應當只用於 聯繫人 app 使用
@Override
protected void onCreate(Bundle savedInstanceState) {
Trace.beginSection("onCreate()");
super.onCreate(savedInstanceState);
if (RequestPermissionsActivity.startPermissionActivity(this)) {
return;
}
getWindow().setStatusBarColor(Color.TRANSPARENT);
//處理Intent傳遞的參數
processIntent(getIntent());
.....
//Scroller初始化,傳遞滾動模式
mScroller.initialize(mMultiShrinkScrollerListener, mExtraMode == MODE_FULLY_EXPANDED);
// mScroller needs to perform asynchronous measurements after initalize(), therefore
// we can't mark this as GONE.
mScroller.setVisibility(View.INVISIBLE);
...
}
private void processIntent(Intent intent) {
...
//獲取傳遞的EXTRA_MODE,不傳預設為large,查看api對應的int值為3,MODE_FULLY_EXPANDED為4, 所以不傳遞參數或者參數對應值不為4就只顯示半屏
mExtraMode = getIntent().getIntExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_LARGE);
...
}
}
通過上面的分析 intent需要傳遞 QuickContact.EXTRA_MODE 參數, 當你點進去 QuickContact中發現並沒有對應4的變數(猜想應該是留了一手不讓第三方app直接全屏顯示)
正確的打開姿勢
private void gotoContact(){
Uri personUri = ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 1);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(personUri);
//這句比較關鍵
intent.putExtra(ContactsContract.QuickContact.EXTRA_MODE, 4);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
總結
1、話說當把navigationBar去掉以後,給每個activity添加返回按鈕是個很麻煩的工作,可以借鑒一下蘋果的思路,直接在屏幕(Window)中添加一個懸浮的按鈕處理返回點擊事件。具體實現可以看這篇Android6.0 源碼修改之 仿IOS添加全屏可拖拽浮窗返回按鈕
2、源碼沒那麼可怕,幹起來。