編輯:關於Android編程
大家都知道,Android從3.0版本開始就加入了NavigationBar,主要是為那些沒有實體按鍵的設備提供虛擬按鍵,但是,它始終固定在底部,占用48dp的像素高度,盡管從android 4.4開始可以全透明,使用這一部分像素,但三個按鈕始終懸浮在屏幕上,這對於有強迫症的朋友來說是無法忍受的。因此,本文的目的就是修改framework部分代碼,可以動態隱藏和顯示NavigationBar,同時又盡量不影響系統的正常。
主要思路:
在NavigationBar的布局左部加入一個Button(在SystemUI模塊實現),點擊隱藏NavigationBar,即將NavigationBar從WindowManager中移除掉。需要的時候,通過一個從屏幕底部向上的滑動手勢(在policy模塊實現)調出NavigationBar。如下兩圖對比所示:一張為移除前,另一張為移除後。
具體實現:
①.增加按鈕實現動態隱藏,主要修改在frameworks/base/packages/SystemUI模塊,首先我們增加一個按鈕,主要修改
frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml文件,圖片資源和字符串我就不提了,具體如下:
diff --git a/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml b/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml index 16027d9..326aafc 100644 --- a/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml +++ b/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml @@ -42,12 +42,28 @@ > + + <framelayout android:layout_height="match_parent" android:layout_weight="0" android:layout_width="@dimen/navigation_extra_key_width"> ++ + </framelayout> ++ + <framelayout android:layout_height="40dp" android:layout_weight="0" android:layout_width="match_parent"> + + + </framelayout> +
diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 88e71e2..7545984 100644 --- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -45,6 +45,7 @@ import com.android.systemui.R; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.DelegateViewHelper; import com.android.systemui.statusbar.policy.DeadZone; +import com.android.systemui.statusbar.policy.KeyButtonRipple; import com.android.systemui.statusbar.policy.KeyButtonView; import java.io.FileDescriptor; @@ -265,6 +266,13 @@ public class NavigationBarView extends LinearLayout { public View getImeSwitchButton() { return mCurrentView.findViewById(R.id.ime_switcher); } + //BEGIN liweiping + public View getHideBarButton() { + View view = mCurrentView.findViewById(R.id.hide_bar_btn); + view.setBackground(new KeyButtonRipple(getContext(), view)); + return view; + } + //END liweiping private void getIcons(Resources res) { mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back); @@ -412,7 +420,6 @@ public class NavigationBarView extends LinearLayout { mCurrentView = mRotatedViews[Surface.ROTATION_0]; getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener); - updateRTLOrder(); }
+ private final OnClickListener mHideBarClickListener = new OnClickListener() { + @Override + public void onClick(View view) { + Log.i(way, mHideBarClickListener onClick...); + removeNavigationBar(); + } + }; + private void removeNavigationBar() { + if (DEBUG) Log.d(TAG, removeNavigationBar: about to remove + mNavigationBarView); + if (mNavigationBarView == null) return; + + mWindowManager.removeView(mNavigationBarView); + mNavigationBarView = null; + }
②.接下來便是顯示NavigationBar,這個修改相對復雜一點。因為此時NavigationBar處於不可見狀態,我們無法通過增加按鈕的方式讓其顯示,但是我們知道,狀態欄下拉通過手勢向下滑動即可。因此很容易便想到通過手勢從屏幕底部向上滑動來顯示NavigationBar。我的想法是在policy模塊中增加一個接口,通過frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java服務傳遞到狀態欄中,從而觸發顯示NavigationBar事件。
也許大家會有疑問,為什麼是在policy模塊修改?其實我這只是一種解決方案,因為我知道
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java 有現成的手勢滑動接口。其實你也可以SystemUI中增加一個這樣的事件,我們需要的就是這麼一個觸發事件。
PhoneWindowManager.java的修改主要是實現onSwipeFromBottom(豎屏時)和onSwipeFromRight(橫屏時)兩個接口,然後調用showNavigationBar,在showNavigationBar函數中,我們調用StatusBarManagerService服務中的showNavigationBar函數,具體如下:
diff --git a/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index bb53e12..907202d 100644 --- a/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1241,13 +1241,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onSwipeFromBottom() { if (mNavigationBar != null && mNavigationBarOnBottom) { requestTransientBars(mNavigationBar); + Log.i(way, onSwipeFromBottom... mNavigationBar != null && mNavigationBarOnBottom); } + //BEGIN liweiping + else{ + Log.i(way, onSwipeFromBottom...); + showNavigationBar(); + } + //END liweiping } @Override public void onSwipeFromRight() { if (mNavigationBar != null && !mNavigationBarOnBottom) { requestTransientBars(mNavigationBar); + Log.i(way, onSwipeFromRight... mNavigationBar != null && !mNavigationBarOnBottom); + } + //BEGIN liweiping + else{ + Log.i(way, onSwipeFromRight...); + showNavigationBar(); } + //END liweiping } @Override public void onDebug() { @@ -1293,7 +1307,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER); } } - + //BEGIN liweiping + private void showNavigationBar(){ + mHandler.post(new Runnable() { + @Override + public void run() { + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.showNavigationBar(); + } + } catch (RemoteException e) { + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + }); + } + //END liweiping private void updateKeyAssignments() { final boolean hasMenu = (mDeviceHardwareKeys & KEY_MASK_MENU) != 0; final boolean hasHome = (mDeviceHardwareKeys & KEY_MASK_HOME) != 0;
diff --git a/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f85e2d9..3f75840 100644 --- a/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -366,6 +366,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub { WindowManager.LayoutParams); } } + //BEGIN liweiping + @Override + public void showNavigationBar() { + enforceStatusBar(); + + android.util.Log.d(way, TAG + showNavigationBar...); + + synchronized(mLock) { + mHandler.post(new Runnable() { + public void run() { + if (mBar != null) { + try { + mBar.showNavigationBar(); + } catch (RemoteException ex) { + } + } + } + }); + } + } + //END liweiping private void updateUiVisibilityLocked(final int vis, final int mask) { if (mSystemUiVisibility != vis) {
diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 9db875f..4f24b6e 100644 --- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -56,6 +56,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_BUZZ_BEEP_BLINKED = 15 << MSG_SHIFT; private static final int MSG_NOTIFICATION_LIGHT_OFF = 16 << MSG_SHIFT; private static final int MSG_NOTIFICATION_LIGHT_PULSE = 17 << MSG_SHIFT; + private static final int MSG_SHOW_NAVIGATIONBAR = 18 << MSG_SHIFT;//ADD liweiping public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -83,6 +84,7 @@ public class CommandQueue extends IStatusBar.Stub { public void animateCollapsePanels(int flags); public void animateExpandSettingsPanel(); public void setSystemUiVisibility(int vis, int mask); + public void showNavigationBar();//ADD liweiping public void topAppWindowChanged(boolean visible); public void setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher); @@ -154,6 +156,14 @@ public class CommandQueue extends IStatusBar.Stub { mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget(); } } + //BEGIN liweiping + public void showNavigationBar() { + synchronized (mList) { + mHandler.removeMessages(MSG_SHOW_NAVIGATIONBAR); + mHandler.sendEmptyMessage(MSG_SHOW_NAVIGATIONBAR); + } + } + //END liweiping public void topAppWindowChanged(boolean menuVisible) { synchronized (mList) { @@ -283,6 +293,11 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_SET_SYSTEMUI_VISIBILITY: mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2); break; + //BEGIN liweiping + case MSG_SHOW_NAVIGATIONBAR: + mCallbacks.showNavigationBar(); + break; + //END liweiping case MSG_TOP_APP_WINDOW_CHANGED: mCallbacks.topAppWindowChanged(msg.arg1 != 0); break;
CommandQueue.java收到了這個消息之後,又回調給了base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java,繞了大半天,消息終於回來了,我們就是需要在PhoneStatusBar.java實現顯示NavigationBar的函數了:
+ @Override // CommandQueue + public void showNavigationBar() { + Log.i(way, TAG + showNavigationBar...); + forceAddNavigationBar(); + } + private void forceAddNavigationBar() { + // If we have no Navbar view and we should have one, create it + if (mNavigationBarView != null) { + return; + } + + mNavigationBarView = + (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null); + mNavigationBarView.setDisabledFlags(mDisabled); + mNavigationBarView.setBar(this); + addNavigationBar(true); // dynamically adding nav bar, reset System UI visibility! + } + private void prepareNavigationBarView(boolean forceReset) { + mNavigationBarView.reorient(); + mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); + mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); + mNavigationBarView.getRecentsButton().setLongClickable(true); + mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener); + mNavigationBarView.getBackButton().setLongClickable(true); + mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener); + mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); + mNavigationBarView.getHideBarButton().setOnClickListener(mHideBarClickListener);//ADD liweiping + + if (forceReset) { + // Nav Bar was added dynamically - we need to reset the mSystemUiVisibility and call + // setSystemUiVisibility so that mNavigationBarMode is set to the correct value + Log.i(way, prepareNavigationBarView mNavigationBarMode = + mNavigationBarMode + mSystemUiVisibility = + mSystemUiVisibility + mNavigationIconHints = + mNavigationIconHints); + mNavigationBarMode = 0; + + int newVal = mSystemUiVisibility; + mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; + setSystemUiVisibility(newVal, /*SYSTEM_UI_VISIBILITY_MASK*/0xffffffff); + int hints = mNavigationIconHints; + mNavigationIconHints = 0; + setNavigationIconHints(hints); + topAppWindowChanged(mShowMenu); + } + + updateSearchPanel(); + } + + // For small-screen devices (read: phones) that lack hardware navigation buttons + private void addNavigationBar(boolean forceReset) { + if (DEBUG) Log.v(TAG, addNavigationBar: about to add + mNavigationBarView); + if (mNavigationBarView == null) return; + + prepareNavigationBarView(forceReset); + + mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); + } + //END liweiping
①顯示NavigationBar時,需要重新實例化一次NavigationBarView,我之前有試過移除NavigationBarView後未置空,下次添加時直接使用,會出現狀態欄重啟的情況,具體原因未知,log顯示動畫播放錯誤之類。
②重新添加NavigationBarView時需要恢復NavigationBarView之前的狀態,比如說隱藏前時是透明的、顯示輸入法按鈕、菜單鍵等等。③本文是在Android5.0的代碼上修改的,其他版本未驗證。
④本文僅是提供一種思路,並非最優方案。
一、前言MVP模式是當前比較主流的框架,主要是由它的優點來決定的吧。本文結合了MVP+Retrofit+RxJava三大主流框架(MVP應該叫模式吧)寫了一個demo【裡
本篇博客要做的效果圖:來個低質量動圖:這個動圖效果不是很好,實際上模糊效果應該是像上面第一張圖那樣的,後面會放出代碼,有興趣的可以試著運行一下看看效果。 先說一
Android實習札記(8)---ViewPager+Fragment實例講解 在札記(5)中我們就說過要弄一個模仿微信頁面切換的東東,就是V
一 摘要晚上看了關於代理模式的一篇文章,寫的非常生動,來過來分享給大家.這裡我就PHP代理模式給大家進行詳細說明.下面我們來看一看這幾天王寶強妻子出軌經紀人事件惹盡了眼球