您当前的位置: 首页 >  android

梁同学与Android

暂无认证

  • 5浏览

    0关注

    618博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android --- 详细介绍透明式状态栏和沉浸式状态栏

梁同学与Android 发布时间:2019-08-11 15:57:31 ,浏览量:5

今天来写一个类似于qq空间的那种沉浸式效果。先来看看qq空间的这种效果

我们看到,头部局上拉的时候有个头布局的透明是从0变化到1,当你下拉的时候,头部局透明度又从1变化到0了。始终效果看起来还是不错的,当然这种效果要配合透明状态栏才好看。而且我们可以再很多应用各种会看到这种广告遮住头布局的方式。比如160的软件。

看起来效果还是挺酷炫的。现在我们就来讲讲他的实现方式吧。首先来看下demo实现的效果图

居然说到了透明状态栏,也说一下关于透明状态栏和沉浸式状态栏吧。我们首先说一下他的概念。

1.沉浸式全屏模式隐藏status bar(状态栏)使屏幕全屏,让Activity接收所有的(整个屏幕的)触摸事件。相当于就是隐藏状态栏,让手机浏览进入全屏模式2.透明化系统状态栏透明化系统状态栏,使得布局侵入系统栏的后面,必须启用fitsSystemWindows属性来调整布局才不至于被系统栏覆盖。

透明状态栏的意思是指布局从状态栏开始。然后状态栏的一些东西比如电量那些基本信息会覆盖在布局上面。但透明状态栏是android 4.4及以上版本才有这种效果,4.4以下是不支持透明状态栏的。我们先看下不设置透明状态栏的效果。

布局文件是这样的

   

效果图:

此时没有设置状态栏,当我们设置透明状态栏的时候,会不一样。来看下设置透明状态栏的效果

设置透明状态栏中的两种方式

1.style文件中设置如下属性

    true

然后在manifiest文件设置activity的theme属性中引用它,就可以了

2.代码中设置

  //api大于19时设置才有效果

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {             getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE                     | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);             getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

来解释一下这几种设置中的含义吧,大家参照一下下面的属性对照。

setSystemUiVisibility这个方法参数表示的状态比较多,具体如下:     1. View.SYSTEM_UI_FLAG_VISIBLE:显示状态栏,Activity不全屏显示(恢复到有状态的正常情况)。     2. View.INVISIBLE:隐藏状态栏,同时Activity会伸展全屏显示。     3. View.SYSTEM_UI_FLAG_FULLSCREEN:Activity全屏显示,且状态栏被隐藏覆盖掉。     4. View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。     5. View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN     6. View.SYSTEM_UI_LAYOUT_FLAGS:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN     7. View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:隐藏虚拟按键(导航栏)。有些手机会用虚拟按键来代替物理按键。     8. View.SYSTEM_UI_FLAG_LOW_PROFILE:状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。 * window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);   Flag表明这个窗口负责绘制系统状态栏标题栏的背景。如果设置,系统bar绘制成透明背景,在这个窗口相应的地方会填充{@link Window#getStatusBarColor()}和       {@link Window#getNavigationBarColor()}对应的颜色。

但是大家有没有注意到,有时候布局内容从状态栏开始排布会很奇怪,比如内容布局的东西会被状态栏的信息覆盖。此时你想要的效果可能只是让状态栏变个颜色。这时候我们就需要这个属性了。将这个属性设置在根布局。

 android:fitsSystemWindows="true"

这时候状态栏的颜色就会跟随主布局。而且内容布局将不会从状态栏开始排布,将会从状态栏之下开始排布。我们看下效果。

这才是我们想要的效果。当然有的人会说我想自定义状态颜色。当然可以。不过4.4系统没有方法自定义状态栏的颜色。5.1以上有方法可以设置状态栏的颜色,等会我会说。不过有个很好的开源库帮我们实现了。我们可以用它来自定义状态栏的颜色。就是SystemBarTinManger。关于这个开源库的使用方法也很简单。只需要导包使用就行,使用它的前提要前提是先要设置透明状态栏。有兴趣的大家去网上看看使用方法就行了,很简单的。接下来我们看下5.0之后设置状态栏颜色的方法。

1.在Manifest文件中配置Activity的theme,设置状态栏颜色,主题颜色等。

 

                  true                                  #FF6600                        #e86053                        #BFDF0F                                                                                       

然后在文件中设置相应颜色即可。 

2.下面是一个设置系统工具栏的比较通用的代码:


  
  
  1. if(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
  2. Windowwindow = getWindow();
  3. //清除系统提供的默认保护色,After LOLLIPOP not translucent status bar
  4. window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
  5. | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
  6. //设置系统UI的显示方式
  7. window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  8. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  9. | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
  10. //添加属性可以自定义设置系统工具栏颜色
  11. window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
  12. window.setStatusBarColor(color_status_bar);
  13. window.setNavigationBarColor(color_navigation_bar);
  14. }

其中getWindow.setStatusBarColor()要5.0以上才有效果。

                             好的,状态栏的知识就先说到这里了。我们来看看今天demo的实现吧。

1.实现原理

   其实实现原理还是挺简单的。我们用FrameLayout作为根布局,然后设置透明状态栏,设置一个头布局。用头布局覆盖内容布局。接着在向下滑动或者向上滑动的时候,我们可以自行设置头布局的透明度。可以利用scrollview的滑动监听来设置。这样就可以看到头部局若隐若现的效果啦。

布局文件:



  
  

封装的帮助器类:


  
  
  1. package com.example.administrator.mystatusbar;
  2. import android.content.Context;
  3. import android.graphics.Color;
  4. import android.graphics.drawable.Drawable;
  5. import android.os.Build;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.view.ViewGroup;
  10. import android.view.ViewTreeObserver;
  11. import java.lang.reflect.Field;
  12. public class ImmersiveHelper {
  13. private Context mContext;
  14. private int mAlpha;
  15. private View mStatusBar;
  16. private View mContentView;
  17. private ObservableScrollView mScrollView;
  18. private int mStatusHeight;
  19. private int mTotalHeight;
  20. private boolean isImmersived;
  21. private ObservableScrollView.ScrollViewListener listener;
  22. public ImmersiveHelper(Context mContext, View mStatusBar, final View mContentView, ObservableScrollView mScrollView) {
  23. this.mContext = mContext;
  24. this.mStatusBar = mStatusBar;
  25. this.mContentView = mContentView;
  26. this.mScrollView = mScrollView;
  27. }
  28. public void init(final Runnable runnable){
  29. mStatusHeight = setStatusViewHeight(mContext,mStatusBar);
  30. mContentView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() {
  31. @Override
  32. public boolean onPreDraw() {
  33. if (mContentView.getMeasuredHeight() != 0){
  34. mTotalHeight = mStatusHeight + mContentView.getMeasuredHeight();
  35. runnable.run();
  36. }
  37. mContentView.getViewTreeObserver().removeOnPreDrawListener( this);
  38. return false;
  39. }
  40. });
  41. }
  42. public void onRestoreData(Bundle bundle){
  43. mTotalHeight = bundle.getInt( "totalHeight");
  44. }
  45. public void onSaveData(Bundle bundle){
  46. bundle.putInt( "totalHeight",mTotalHeight);
  47. }
  48. public boolean isImmersived() {
  49. return isImmersived;
  50. }
  51. public int getTotalHeight() {
  52. return mTotalHeight;
  53. }
  54. /**
  55. * 设置当前沉浸的状态
  56. */
  57. public void setImmversive(boolean isOpen, final Runnable runnable){
  58. if(isOpen){
  59. if(!isImmersived) {
  60. mContentView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() {
  61. @Override
  62. public boolean onPreDraw() {
  63. int immerseHeight = mContext.getResources().getDisplayMetrics().widthPixels / 2 - mContentView.getMeasuredHeight() - mStatusHeight;
  64. listener = setImmersiveEnabled(mScrollView, mStatusBar, mContentView, immerseHeight);
  65. logD( "setImmersive-->true");
  66. isImmersived = true;
  67. if( null != runnable){
  68. runnable.run();
  69. }
  70. mScrollView.scrollTo( 0, 0);
  71. mScrollView.invalidate();
  72. mContentView.getViewTreeObserver().removeOnPreDrawListener( this);
  73. return false;
  74. }
  75. });
  76. }
  77. } else if(isImmersived){
  78. mScrollView.scrollTo( 0, 0);
  79. mScrollView.invalidate();
  80. mScrollView.removeScrollViewListener(listener);
  81. mAlpha = 255;
  82. mStatusBar.getBackground().mutate().setAlpha(mAlpha);
  83. mContentView.getBackground().mutate().setAlpha(mAlpha);
  84. logD( "setImmersive-->false");
  85. isImmersived = false;
  86. if( null != runnable){
  87. runnable.run();
  88. }
  89. }
  90. }
  91. /**
  92. * 设置沉浸式交互
  93. * @param height 沉浸的总高度
  94. */
  95. public ObservableScrollView. ScrollViewListener setImmersiveEnabled(ObservableScrollView scrollView, final View status, final View content, final int height){
  96. mAlpha = 0;
  97. content.getBackground().mutate().setAlpha(mAlpha);
  98. status.getBackground().mutate().setAlpha(mAlpha);
  99. ObservableScrollView.ScrollViewListener listener = new ObservableScrollView.ScrollViewListener() {
  100. @Override
  101. public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
  102. int alpha = Math.max( 0,Math.min( 255,( int) ( 255 * (scrollView.getScrollY()) * 1.0f / height)));
  103. if(mAlpha != alpha) {
  104. content.getBackground().mutate().setAlpha(alpha);
  105. status.getBackground().mutate().setAlpha(alpha);
  106. mAlpha = alpha;
  107. }
  108. }
  109. };
  110. scrollView.addScrollViewListener(listener);
  111. return listener;
  112. }
  113. private void logD(String text){
  114. Log.d( "ImmersiveHelper", text);
  115. }
  116. /**
  117. * 设置需要充当状态栏的视图高度
  118. * @param viewStatus 视图
  119. */
  120. public static int setStatusViewHeight(Context mContext,View viewStatus){
  121. int statusHeight = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT?getStatusBarHeight(mContext): 0;
  122. ViewGroup.LayoutParams params = viewStatus.getLayoutParams();
  123. if(statusHeight != params.height) {
  124. params.height = statusHeight;
  125. viewStatus.requestLayout();
  126. }
  127. return statusHeight;
  128. }
  129. /**
  130. * 获取状态栏高度
  131. *
  132. * @param context
  133. * @return
  134. */
  135. public static int getStatusBarHeight(Context context) {
  136. /*Rect rect = new Rect();
  137. activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
  138. return rect.top;*/
  139. try {
  140. Class c = Class.forName( "com.android.internal.R$dimen");
  141. Object obj = c.newInstance();
  142. Field field = c.getField( "status_bar_height");
  143. int x = Integer.parseInt(field.get(obj).toString());
  144. int y = context.getResources().getDimensionPixelSize(x);
  145. return y;
  146. } catch (Exception e) {
  147. e.printStackTrace();
  148. }
  149. return 0;
  150. }
  151. }
使用类:

   
   
  1. emptypackage com.example.administrator.mystatusbar;
  2. import android.annotation.TargetApi;
  3. import android.app.Activity;
  4. import android.os.Build;
  5. import android.os.Bundle;
  6. import android.support.annotation.Nullable;
  7. import android.view.View;
  8. import android.view.Window;
  9. import android.view.WindowManager;
  10. import android.widget.FrameLayout;
  11. import android.widget.LinearLayout;
  12. import android.os.Handler;
  13. public class MyStatusBar extends Activity {
  14. ObservableScrollView scrollView;
  15. LinearLayout contentView;
  16. View stabarView;
  17. MyStatusBar mContext;
  18. @Override
  19. protected void onCreate(@Nullable Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.status_bar);
  22. mContext = this;
  23. initView();
  24. }
  25. private void initView(){
  26. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  27. getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  28. | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  29. getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  30. }
  31. scrollView = (ObservableScrollView) findViewById(R.id.scrollView);
  32. contentView = (LinearLayout) findViewById(R.id.ll_tab_top_search_parent);
  33. stabarView = findViewById(R.id.view_status);
  34. final ImmersiveHelper immersiveHelper = new ImmersiveHelper(mContext,stabarView,contentView,scrollView);
  35. immersiveHelper.init( new Runnable() {
  36. @Override
  37. public void run() {
  38. FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) scrollView.getLayoutParams();
  39. params.topMargin = immersiveHelper.getTotalHeight();
  40. scrollView.requestLayout();
  41. }
  42. });
  43. new Handler().postDelayed( new Runnable() {
  44. @Override
  45. public void run() {
  46. immersiveHelper.setImmversive( true, new Runnable() {
  47. @Override
  48. public void run() {
  49. if(immersiveHelper.isImmersived()){
  50. FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) scrollView.getLayoutParams();
  51. params.topMargin = 0;
  52. scrollView.requestLayout();
  53. } else{
  54. FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) scrollView.getLayoutParams();
  55. params.topMargin = immersiveHelper.getTotalHeight();
  56. scrollView.requestLayout();
  57. }
  58. }
  59. });
  60. }
  61. }, 3000);
  62. }
  63. }
关键代码就是这个方法了
public ObservableScrollView.ScrollViewListener setImmersiveEnabled(ObservableScrollView scrollView, final View status, final View content, final int height){         mAlpha = 0;         content.getBackground().mutate().setAlpha(mAlpha);         status.getBackground().mutate().setAlpha(mAlpha);         ObservableScrollView.ScrollViewListener listener = new ObservableScrollView.ScrollViewListener() {             @Override             public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {                 int alpha = Math.max(0,Math.min(255,(int) (255 * (scrollView.getScrollY()) * 1.0f / height)));                 if(mAlpha != alpha) {                     content.getBackground().mutate().setAlpha(alpha);                     status.getBackground().mutate().setAlpha(alpha);                     mAlpha = alpha;                 }             }         };         scrollView.addScrollViewListener(listener);         return listener;     }
这里就是根据滑动监听自由设置头布局的透明实现的。
当然里面还有方法时自行控制是否需要这样的效果的。如果不需要,我们可以让内容布局从头布局下面开始排列。里面还做了4.4以下的处理。大家可以看看里面的实现。应该可以看懂的....
今天的博客写到这里,项目地址:下次给上..

关注
打赏
1660730345
查看更多评论
立即登录/注册

微信扫码登录

0.1226s