編輯:關於Android編程
這裡不討論[沉浸式]這個詞用得好不好, 大家聽得懂就行. 這篇文章主要是我在實際項目中的一些經驗, 整理出來和大家分享, 歡迎探討. 由於實習一直是996, 沒時間做總結, 今天突然覺得這樣的工作讓我都忘了生活了, 是時候做個了斷了. 寫這篇文章的時候已經是23:44, 來不及貼一些demo, 但是這裡的代碼都是曾經的項目中摘出來的, 是可以運行的, 但我現在沒有真的執行一遍. 注意所有的代碼都只在android 4.4及以上有效.
根據實際項目的不同, 可能選擇的沉浸式實現策略也會有所不同.
如果你的app使用的是遵循android規范的actionbar或者有一個純色layout放在屏幕頂部, 那麼這裡有一個入侵較小的方案, 這個方案的實現方式是參考的開源項目SystemBarTint.
讓你的activity繼承一個BaseActivity, 在BaseActivity裡面重寫onPostCreate
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ImmerseHelper.setSystemBarTransparent(this);
}
}
重點在ImmerseHelper這個類裡, 先貼代碼再講解.
public class ImmerseHelper {
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void setSystemBarTransparent(Activity paramActivity)
{
Window window = paramActivity.getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
window.setAttributes(layoutParams);
hackStatusBarTransparent(paramActivity);
setContentPadding(paramActivity);
}
public static void hackStatusBarTransparent(Activity paramActivity) {
ViewGroup localViewGroup = (ViewGroup) paramActivity.getWindow().getDecorView()
.findViewById(android.R.id.content);
View colorview = new View(paramActivity);
colorview.setBackgroundResource(R.color.statusbar_color);
localViewGroup.addView(colorview, ViewGroup.LayoutParams.MATCH_PARENT,
ImmerseHelper.getStatusBarHeight(paramActivity));
}
public static void setContentPadding(Activity activity) {
((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0)
.setPadding(0, ImmerseHelper.getStatusBarHeight(activity)
+ ImmerseHelper.getActionBarHeight(activity), 0, 0);
}
/**
* 獲取狀態欄高度, 單位px
* @param context
* @return
*/
public static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier(status_bar_height, dimen, android);
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
/**
* 獲取actionbar高度, 單位px
* @param context
* @return
*/
public static int getActionBarHeight(Context context)
{
TypedValue localTypedValue = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, localTypedValue, true)) {
return TypedValue.complexToDimensionPixelSize(localTypedValue.data, context.getResources().getDisplayMetrics());
}
return 0;
}
}
簡單來說就是在postCreate
時對activity做手腳, 這樣組內其他開發者幾乎感受不到變化, 只需要將activity的基類指定成BaseActivity
就好
ImmerseHelper
這個類主要做了三件事
- 將window的FLAG_TRANSLUCENT_STATUS標志打開
- 給某個View中添加了一個與狀態欄大小完全相同的純色塊
- 給activity的根View設置paddingTop
FLAG_TRANSLUCENT_STATUS這個標志打開之後, 狀態欄就透明了, 同時我們的activity的主體布局, 也就是setContentView傳入的那個布局, 會頂到屏幕最上方, 被狀態欄蓋住一部分, 注意actionbar是不會受影響的. 所以我們在第三步給activity的根view設了paddingTop, 高度是狀態欄的高度加上actionbar的高度, 這樣activity中的內容才會回到之前的正常位置. 但此時狀態欄下方透明了, 所以我們給某個View中添加了一個與狀態欄大小完全相同的色塊, 顏色和actionbar一致, 這樣就有了沉浸式效果.
當然這裡的效果是狀態欄下面有一層半透明黑底, 之後才是我們添加的view, 所以不用擔心看不到狀態文字, 在4.4上只能做到這個效果, 5.0上可以讓狀態欄底部完全透明, 這個等會兒說.
不過光有實現不行, 還需要知道為什麼我們要這麼做
先看一下hierarchy view的截圖
我們getDecorView拿到的是最左邊的DecorView, 而setContentView影響的是id/content那個view的直接子view, 和id/content平級的view是actionbar. 如果你要做到向上圖這樣, 圖片完全頂在頂部, 那麼就不建議使用actionbar了, 同時也不需要setContentPadding這步. 有時這樣會導致某些頁面的內容過分偏上, 這個時候建議用一個dimen, 在正常情況下是0dp, v19及以上時是24dp, 這也是狀態欄高度, 哪些頁面要隔開狀態欄, 就用這個dimen做marginTop, 或者include一個高度為這個dimen的layout. 上面說的都是api level 19的方法, 唯一的缺陷是狀態欄並非完全透明, 而是底部有個半透明的黑條, 在api level 21上, 我們可以去掉這個半透明黑條, 讓狀態欄完全透明. api 21的解決方案理論上是可以用xml完成的, 但是我實際測試發現並不能, 只有用代碼才有效.
activity.getWindow().getDecZ喎?/kf/ware/vc/" target="_blank" class="keylink">vclZpZXcoKS5maW5kVmlld0J5SWQoYW5kcm9pZC5SLmlkLmNvbnRlbnQpOzwvY29kZT7V4r7kxMO1vbXEysdpZC9jb250ZW501eK49nZpZXcsIM7Sw8fP8sbk1tDM7bzT0ru49rS/yat2aWV3LCDTydPatPK/qsHLRkxBR19UUkFOU0xVQ0VOVF9TVEFUVVMsINXiuPa0v8mrdmlld77N1rG907al1NrX7snPw+YsINKyvs3Kx9e0zKzAuLiyuMe1xLXYt70uPGJyIC8+DQpTeXN0ZW1CYXJUaW501tCyorfHysfP8mlkL2NvbnRlbnTW0GFkZFZpZXcsILb4ysfWsb3Tz/I8Y29kZT5nZXREZWNvclZpZXcoKTwvY29kZT7W0GFkZFZpZXcsILb4U3dpcGVCYWNrTGF5b3V01PLKx9TaRGVjb3JWaWV3us3L+7XE19NWaWV31q685LLlyOvX1Ly6tcRsYXlvdXQsIM/gtbHT2r3Zs9bBy0RlY29yVmlld7XE19NWaWV3LCDL+dLUyOe5+82syrHKudPD1eLBvbj2v6rUtM/uxL+yu7zT0N64xCwg0qrDtLustq+3tbvYu67X37XEysfXtMyswLgsINKqw7TXtMyswLjLusHRLiDI57n7z/HO0tXiw7TQtCwgvs2yu7vhus1Td2lwZUJhY2tMYXlvdXSz5c27LjwvcD4NCjxoMiBpZD0="非傳統">非傳統
這樣子的入侵比較強, 做新的頁面需要時刻注意和狀態欄是否需要保持距離, 很容易忘記, 不過也不算什麼困難, 畢竟一運行就看出來了.Lolipop+特有方法
在onCreate
的setContentView調用之後, 將activity做參數傳給下面這個方法, 就可以讓你的app在api level 21上擁有完全透明的狀態欄, 同時在api 19上使用上面的實現
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setSystemBarTransparent(Activity paramActivity)
{
if (shouldUseTransparentSystemBar()) {
Window window = paramActivity.getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//api 21 解決方案
View systemdecor = window.getDecorView();
systemdecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
layoutParams.flags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
window.setStatusBarColor(0x00000000);
} else {
//api 19 解決方案
layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
}
window.setAttributes(layoutParams);
}
}
微信附近的人是一個可以看到周邊人也在玩這個功能的人。有朋友說他可以看到別人,但是別人看不到他,這是為什麼呀?我的微信能看到附近的人,但附近的人看不見我,怎麼
前言最近一段時間在研究EventBus和Retrofit 的過程中,都遇到了注解這個概念。由於在學習Java的時候對這方面沒有深入了解過,所以看起相關的代碼來,總會有點不
之前寫過一篇關於Android 繼承DialogFragment彈出dialog對話框一,這次是在上次的基礎上修改了一些東西,就是怎樣在DialogFragment中獲取
Android的PopupWindow是個很有用的widget,利用它可以實現懸浮窗體的效果,比如實現一個懸浮的菜單,最常見的應用就是在視頻播放界面裡,做一個工具欄,用來