Android中的沉浸式状态栏效果

摘要:
一个Android应用程序的界面上其实是有很多系统元素的,有状态栏、ActionBar、导航栏等。另外,根据Android的设计建议,ActionBar是不应该独立于状态栏而单独显示的,因此状态栏如果隐藏了,我们同时也需要调用ActionBar的hide()方法将ActionBar也进行隐藏这种效果不叫沉浸式状态栏,也完全没有沉浸式状态栏这种说法,我们估且可以把它叫做透明状态栏效果吧。这样,我在github上找到一个很好的沉浸状态栏效果,来看一下。

无意间了解到沉浸式状态栏,感觉贼拉的高大上,于是就是试着去了解一下,就有了这篇文章。下面就来了解一下啥叫沉浸式状态栏。传统的手机状态栏是呈现出黑色条状的,有的和手机主界面有很明显的区别。这一样就在一定程度上牺牲了视觉宽度,界面面积变小。Google从android kitkat(Android 4.4)开始,给我们开发者提供了一套能透明的系统ui样式给状态栏和导航栏,这样的话就不用向以前那样每天面对着黑乎乎的上下两条黑栏了,还可以调成跟Activity一样的样式,形成一个完整的主题,和IOS7.0以上系统一样了,沉浸式状态栏和主界面颜色和谐一体,视觉效果更加炫酷。不过虽然听上去好像是很高大上的沉浸式效果,实际看上去貌似就是将内容全屏化了而已嘛。其实这算是一个争议点了。不少人纠结于沉浸式状态栏到底是将屏幕显示内容扩大还是仅仅是改变状态栏、标题栏的颜色。其实我更倾向于后者。在4.4之前状态栏一直是黑色的,在4.4中带来了 windowTranslucentStatus 这一特性,因此可以实现给状态栏设置颜色,视觉上的效果,感觉容器部分和状态栏、标题栏融为一体,更加直接的说就是改变状态栏、标题栏的颜色,当时可以根据界面颜色改变状态栏、标题栏的颜色实现跟加完整的界面显示,这应该是沉浸式状态栏受追捧的原因吧。

谷歌并没有给出沉浸式状态栏这个概念,谷歌只说了沉浸式模式(Immersive Mode)。不过沉浸式状态栏这个名字其实挺不错,只能随大众,但是Android的环境并没有IOS环境一样特别统一,比如华为rom的跟小米rom的虚拟按键完全不一样,并且安卓版本众多涉及到版本兼容问题,所有Android开发者不容易。这点在沉浸式状态栏的开发中显得尤为重要。如果你在4.4之前的机子上显示沉浸式状态栏的话,经常出现一些意想不到的结果。沉浸式是APP界面图片延伸到状态栏, 应用本身沉浸于状态栏,所以如果第三方的软件没有为状态栏分配图片,那么自然就是黑色。顶端的状态栏和下面的虚拟按键都隐藏,需要的时候从边缘划出。沉浸模式。当启用该模式,应用程序的界面将占据整个屏幕,系统自动将隐藏系统的状态栏和导航栏,让应用程序内容可以在最大显示范围呈现,增加大屏体验,而当需要查看通知的时候只需要从顶部向下滑动就能呼出通知栏。沉浸模式实际上有两种:一种叫“沉浸模式”,状态栏和虚拟按钮会自动隐藏、应用自动全屏,这种模式下,应用占据屏幕的全部空间, 只有当用户从屏幕的上方边沿处向下划动时, 才会退出沉浸模式, 用户触摸屏幕其它部分时, 不会退出该模式, 这种模式比较适用于阅读器、 杂志类应用。另外一种叫“黏性沉浸模式”,让状态栏和虚拟按钮半透明,应用使用屏幕的全部空间, 当用户从屏幕的上方边沿处向下滑动时,也不会退出该模式, 但是系统界面 (状态栏、 导航栏) 将会以半透明的效果浮现在应用视图之上 , 只有当用户点击系统界面上的控件时, 才会退出黏性沉浸模式。

下面来说一说具体的实现。一个Android应用程序的界面上其实是有很多系统元素的,有状态栏、ActionBar、导航栏等。而打造沉浸式模式的用户体验,就是要将这些系统元素进行整合,当主界面改变时,状态栏、ActionBar、导航栏同时也发生改变。这里先调用getWindow().getDecorView()方法获取到了当前界面的DecorView,然后调用它的setSystemUiVisibility()方法来设置系统UI元素的可见性。其中,SYSTEM_UI_FLAG_FULLSCREEN表示全屏的意思,也就是会将状态栏隐藏。另外,根据Android的设计建议,ActionBar是不应该独立于状态栏而单独显示的,因此状态栏如果隐藏了,我们同时也需要调用ActionBar的hide()方法将ActionBar也进行隐藏这种效果不叫沉浸式状态栏,也完全没有沉浸式状态栏这种说法,我们估且可以把它叫做透明状态栏效果吧。

隐藏状态栏:

setContentView(R.layout.activity_main);  //再该方法后执行
if (Build.VERSION.SDK_INT >= 21) {
    View decorView =getWindow().getDecorView();
    int option =View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            |View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    decorView.setSystemUiVisibility(option);
    getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar =getSupportActionBar();
actionBar.hide();

具体的沉浸效果该如何实现呢,系统提供实现沉浸式状态栏的方法,通过WindowManager来实现,可分为两步:
1. 在需要实现沉浸式状态栏的Activity的布局中添加以下参数

android:fitsSystemWindows="true"
 android:clipToPadding="true"

2. 在Activity的setContentView()方法后面调用初始化的方法即可。

 private voidinitState() {
 if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT) {
 //透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
 //透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
 }
 }

当上述的实现效果,其实并不好,没有在布局中设置clipToPadding为true的时候,会对应用的顶部Toolbar进行拉伸,在布局中两个参数都进行设置后,顶部状态栏变成了白色。这样,我在github上找到一个很好的沉浸状态栏效果,来看一下。

首先添加依赖,导入下面的包。有时候可能会出现版本不统一的问题,依次保证联网的情况下点击一下同步android studio会自动下载包。

compile 'com.jaeger.statusbaruitl:library:1.2.5'

在自定义控件中实现的进本逻辑,代码较长。

packagecom.xiaoyuan;

importandroid.content.Context;
importandroid.content.res.TypedArray;
importandroid.graphics.Canvas;
importandroid.graphics.drawable.Drawable;
importandroid.os.Build;
importandroid.util.AttributeSet;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.view.animation.AlphaAnimation;
importandroid.widget.ScrollView;

importjava.util.ArrayList;

/*** @authorEmil Sj�lander - sjolander.emil@gmail.com
 */
public class StickyScrollView extendsScrollView {

    /*** Tag for views that should stick and have constant drawing. e.g.
     * TextViews, ImageViews etc
     */
    public static final String STICKY_TAG = "sticky";

    /*** Flag for views that should stick and have non-constant drawing. e.g.
     * Buttons, ProgressBars etc
     */
    public static final String FLAG_NONCONSTANT = "-nonconstant";

    /*** Flag for views that have aren't fully opaque
     */
    public static final String FLAG_HASTRANSPARANCY = "-hastransparancy";

    /*** Default height of the shadow peeking out below the stuck view.
     */
    private static final int DEFAULT_SHADOW_HEIGHT = 10; //dp;
    /*** XKJ add for add 50dp offset of top
     */
    private static int MIN_STICK_TOP = 100;//px
    //private static final int MIN_STICK_TOP = 0;
    private ArrayList<View>stickyViews;
    privateView currentlyStickingView;
    private floatstickyViewTopOffset;
    private intstickyViewLeftOffset;
    private booleanredirectTouchesToStickyView;
    private booleanclippingToPadding;
    private booleanclipToPaddingHasBeenSet;

    private intmShadowHeight;
    privateDrawable mShadowDrawable;
    private OnScrollChangedListener mOnScrollHandler = null;
    private IOnScrollToEnd mOnScrollToEnd = null;

    private final Runnable invalidateRunnable = newRunnable() {

        @Override
        public voidrun() {
            if (currentlyStickingView != null) {
                int l =getLeftForViewRelativeOnlyChild(currentlyStickingView);
                int t =getBottomForViewRelativeOnlyChild(currentlyStickingView);
                int r =getRightForViewRelativeOnlyChild(currentlyStickingView);
                int b = (int) (getScrollY() + (currentlyStickingView.getHeight() +stickyViewTopOffset));
                invalidate(l, t, r, b);
            }
            postDelayed(this, 16);
        }
    };

    publicStickyScrollView(Context context) {
        this(context, null);
    }

    publicStickyScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.scrollViewStyle);
    }

    public StickyScrollView(Context context, AttributeSet attrs, intdefStyle) {
        super(context, attrs, defStyle);
        setup();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StickyScrollView, defStyle, 0);

        final float density =context.getResources().getDisplayMetrics().density;
        int defaultShadowHeightInPix = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);

        mShadowHeight =a.getDimensionPixelSize(R.styleable.StickyScrollView_stuckShadowHeight,
                defaultShadowHeightInPix);

        int shadowDrawableRes = a.getResourceId(R.styleable.StickyScrollView_stuckShadowDrawable, -1);

        if (shadowDrawableRes != -1) {
            mShadowDrawable =context.getResources().getDrawable(shadowDrawableRes);
        }

        a.recycle();

    }

    /*** Sets the height of the shadow drawable in pixels.
     *
     * @paramheight
     */
    public void setShadowHeight(intheight) {
        mShadowHeight =height;
    }

    public voidsetup() {
        stickyViews = new ArrayList<View>();
    }

    private intgetLeftForViewRelativeOnlyChild(View v) {
        int left =v.getLeft();
        while (v.getParent() != getChildAt(0)) {
            v =(View) v.getParent();
            left +=v.getLeft();
        }
        returnleft;
    }

    private intgetTopForViewRelativeOnlyChild(View v) {
        int top =v.getTop();
        while (v.getParent() != getChildAt(0)) {
            v =(View) v.getParent();
            top +=v.getTop();
        }
        returntop;
    }

    private intgetRightForViewRelativeOnlyChild(View v) {
        int right =v.getRight();
        while (v.getParent() != getChildAt(0)) {
            v =(View) v.getParent();
            right +=v.getRight();
        }
        returnright;
    }

    private intgetBottomForViewRelativeOnlyChild(View v) {
        int bottom =v.getBottom();
        while (v.getParent() != getChildAt(0)) {
            v =(View) v.getParent();
            bottom +=v.getBottom();
        }
        returnbottom;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, intb) {
        super.onLayout(changed, l, t, r, b);
        if (!clipToPaddingHasBeenSet) {
            clippingToPadding = true;
        }
        notifyHierarchyChanged();
    }

    @Override
    public void setClipToPadding(booleanclipToPadding) {
        super.setClipToPadding(clipToPadding);
        clippingToPadding =clipToPadding;
        clipToPaddingHasBeenSet = true;
    }

    @Override
    public voidaddView(View child) {
        super.addView(child);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, intindex) {
        super.addView(child, index);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, intindex, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, int width, intheight) {
        super.addView(child, width, height);
        findStickyViews(child);
    }

    @Override
    public voidaddView(View child, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, params);
        findStickyViews(child);
    }

    @Override
    protected voiddispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (currentlyStickingView != null) {
            canvas.save();
            canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() +stickyViewTopOffset
                    + (clippingToPadding ? getPaddingTop() : 0));

            canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth() -stickyViewLeftOffset,
                    currentlyStickingView.getHeight() + mShadowHeight + 1);

            if (mShadowDrawable != null) {
                int left = 0;
                int right =currentlyStickingView.getWidth();
                int top =currentlyStickingView.getHeight();
                int bottom = currentlyStickingView.getHeight() +mShadowHeight;
                mShadowDrawable.setBounds(left, top, right, bottom);
                mShadowDrawable.draw(canvas);
            }

            canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(),
                    currentlyStickingView.getHeight());
            if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
                showView(currentlyStickingView);
                currentlyStickingView.draw(canvas);
                hideView(currentlyStickingView);
            } else{
                currentlyStickingView.draw(canvas);
            }
            canvas.restore();
        }
    }

    @Override
    public booleandispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() ==MotionEvent.ACTION_DOWN) {
            redirectTouchesToStickyView = true;
        }

        if(redirectTouchesToStickyView) {
            redirectTouchesToStickyView = currentlyStickingView != null;
            if(redirectTouchesToStickyView) {
                redirectTouchesToStickyView = ev.getY() <= (currentlyStickingView.getHeight() +stickyViewTopOffset)
                        && ev.getX() >=getLeftForViewRelativeOnlyChild(currentlyStickingView)
                        && ev.getX() <=getRightForViewRelativeOnlyChild(currentlyStickingView);
            }
        } else if (currentlyStickingView == null) {
            redirectTouchesToStickyView = false;
        }
        if(redirectTouchesToStickyView) {
            ev.offsetLocation(0, -1
                    * ((getScrollY() + stickyViewTopOffset) -getTopForViewRelativeOnlyChild(currentlyStickingView)));

            //XKJ add TODO: remove this
currentlyStickingView.invalidate();
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean hasNotDoneActionDown = true;

    @Override
    public booleanonTouchEvent(MotionEvent ev) {
        if(redirectTouchesToStickyView) {
            ev.offsetLocation(0,
                    ((getScrollY() + stickyViewTopOffset) -getTopForViewRelativeOnlyChild(currentlyStickingView)));
        }

        if (ev.getAction() ==MotionEvent.ACTION_DOWN) {
            hasNotDoneActionDown = false;
        }

        if(hasNotDoneActionDown) {
            MotionEvent down =MotionEvent.obtain(ev);
            down.setAction(MotionEvent.ACTION_DOWN);
            super.onTouchEvent(down);
            hasNotDoneActionDown = false;
        }

        if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() ==MotionEvent.ACTION_CANCEL) {
            hasNotDoneActionDown = true;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, intoldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        doTheStickyThing();
        if (mOnScrollHandler != null) {
            mOnScrollHandler.onScrollChanged(l, t, oldl, oldt);
        }
        int maxScroll = getChildAt(0).getHeight() -getHeight();
        if (getChildCount() > 0 && t ==maxScroll) {
            if (mOnScrollToEnd != null) {
                mOnScrollToEnd.onScrollToEnd();
            }
        }
    }

    public voidsetOnScrollListener(OnScrollChangedListener handler) {
        mOnScrollHandler =handler;
    }

    public interfaceOnScrollChangedListener {
        public void onScrollChanged(int l, int t, int oldl, intoldt);
    }

    public interfaceIOnScrollToEnd {
        public voidonScrollToEnd();
    }

    public voidsetOnScrollToEndListener(IOnScrollToEnd handler) {
        mOnScrollToEnd =handler;
    }

    private voiddoTheStickyThing() {
        View viewThatShouldStick = null;
        View approachingView = null;
        for(View v : stickyViews) {
            int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0: getPaddingTop())
                    - MIN_STICK_TOP;//add 50dp

            if (viewTop <= 0) {
                if (viewThatShouldStick == null
                        || viewTop > (getTopForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + (clippingToPadding ? 0: getPaddingTop()))) {
                    viewThatShouldStick =v;
                }
            } else{
                if (approachingView == null
                        || viewTop < (getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0: getPaddingTop()))) {
                    approachingView =v;
                }
            }
        }
        if (viewThatShouldStick != null) {
            stickyViewTopOffset = approachingView == null ?MIN_STICK_TOP : Math.min(MIN_STICK_TOP,
                    getTopForViewRelativeOnlyChild(approachingView) -getScrollY()
                            + (clippingToPadding ? 0 : getPaddingTop()) -viewThatShouldStick.getHeight());
            if (viewThatShouldStick !=currentlyStickingView) {
                if (currentlyStickingView != null) {
                    stopStickingCurrentlyStickingView();
                }
                //only compute the left offset when we start sticking.
                stickyViewLeftOffset =getLeftForViewRelativeOnlyChild(viewThatShouldStick);
                startStickingView(viewThatShouldStick);
            }
        } else if (currentlyStickingView != null) {
            stopStickingCurrentlyStickingView();
        }
    }

    private voidstartStickingView(View viewThatShouldStick) {
        currentlyStickingView =viewThatShouldStick;
        if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
            hideView(currentlyStickingView);
        }
        if(((String) currentlyStickingView.getTag()).contains(FLAG_NONCONSTANT)) {
            post(invalidateRunnable);
        }
    }

    private voidstopStickingCurrentlyStickingView() {
        if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
            showView(currentlyStickingView);
        }
        currentlyStickingView = null;
        removeCallbacks(invalidateRunnable);
    }

    /*** Notify that the sticky attribute has been added or removed from one or
     * more views in the View hierarchy
     */
    public voidnotifyStickyAttributeChanged() {
        notifyHierarchyChanged();
    }

    private voidnotifyHierarchyChanged() {
        if (currentlyStickingView != null) {
            stopStickingCurrentlyStickingView();
        }
        stickyViews.clear();
        findStickyViews(getChildAt(0));
        doTheStickyThing();
        invalidate();
    }

    private voidfindStickyViews(View v) {
        if (v instanceofViewGroup) {
            ViewGroup vg =(ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                String tag =getStringTagForView(vg.getChildAt(i));
                if (tag != null &&tag.contains(STICKY_TAG)) {
                    stickyViews.add(vg.getChildAt(i));
                } else if (vg.getChildAt(i) instanceofViewGroup) {
                    findStickyViews(vg.getChildAt(i));
                }
            }
        } else{
            String tag =(String) v.getTag();
            if (tag != null &&tag.contains(STICKY_TAG)) {
                stickyViews.add(v);
            }
        }
    }

    privateString getStringTagForView(View v) {
        Object tagObject =v.getTag();
        returnString.valueOf(tagObject);
    }

    private voidhideView(View v) {
        if (Build.VERSION.SDK_INT >= 11) {
            v.setAlpha(0);
        } else{
            AlphaAnimation anim = new AlphaAnimation(1, 0);
            anim.setDuration(0);
            anim.setFillAfter(true);
            v.startAnimation(anim);
        }
    }

    private voidshowView(View v) {
        if (Build.VERSION.SDK_INT >= 11) {
            v.setAlpha(1);
        } else{
            AlphaAnimation anim = new AlphaAnimation(0, 1);
            anim.setDuration(0);
            anim.setFillAfter(true);
            v.startAnimation(anim);
        }
    }

    /*** 设置悬浮高度
     * @paramheight
     */
    public void setStickTop(intheight) {
        MIN_STICK_TOP =height;
    }

    /*** 解决vviewpager在scrollview滑动冲突的问题
     */
    //滑动距离及坐标
    private floatxDistance, yDistance, xLast, yLast;

    @Override
    public booleanonInterceptTouchEvent(MotionEvent ev) {
        switch(ev.getAction()) {
            caseMotionEvent.ACTION_DOWN:
                xDistance = yDistance =0f;
                xLast =ev.getX();
                yLast =ev.getY();
                break;
            caseMotionEvent.ACTION_MOVE:
                final float curX =ev.getX();
                final float curY =ev.getY();

                xDistance += Math.abs(curX -xLast);
                yDistance += Math.abs(curY -yLast);
//com.ihaveu.utils.Log.i("test", "curx:"+curX+",cury:"+curY+",xlast:"+xLast+",ylast:"+yLast);
//xLast = curX;
//yLast = curY;

                if (xDistance >yDistance) {
                    return false;
                }

        }
        return super.onInterceptTouchEvent(ev);
    }
}

接下来是调用自定义控件了,用到两个关键的方法。StatusBarUtil.setTranslucentForImageView(MainActivity.this, 0, title)和llTitle.setBackgroundColor(Color.argb((int) alpha, 227, 29, 26))分别设置状态栏和标题栏的颜色。

packagecom.xiaoyuan;

importandroid.graphics.Color;
importandroid.os.Bundle;
importandroid.support.v7.app.AppCompatActivity;
importandroid.view.View;
importandroid.view.ViewTreeObserver;
importandroid.widget.FrameLayout;
importandroid.widget.LinearLayout;
importandroid.widget.RelativeLayout;
importandroid.widget.TextView;

importcom.jaeger.library.StatusBarUtil;

public class MainActivity extends AppCompatActivity implementsView.OnClickListener, StickyScrollView.OnScrollChangedListener {

    TextView oneTextView, twoTextView;
    privateStickyScrollView stickyScrollView;
    private intheight;
    privateLinearLayout llContent;
    privateRelativeLayout llTitle;
    privateFrameLayout frameLayout;
    privateTextView title;

    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListeners();
    }

    /*** 初始化View
     */
    private voidinitView() {
        stickyScrollView =(StickyScrollView) findViewById(R.id.scrollView);
        frameLayout =(FrameLayout) findViewById(R.id.tabMainContainer);
        title =(TextView) findViewById(R.id.title);
        oneTextView =(TextView) findViewById(R.id.infoText);
        llContent =(LinearLayout) findViewById(R.id.ll_content);
        llTitle =(RelativeLayout) findViewById(R.id.ll_good_detail);
        oneTextView.setOnClickListener(this);
        twoTextView =(TextView) findViewById(R.id.secondText);
        twoTextView.setOnClickListener(this);

        stickyScrollView.setOnScrollListener(this);
        StatusBarUtil.setTranslucentForImageView(MainActivity.this, 0, title);
        FrameLayout.LayoutParams params =(FrameLayout.LayoutParams) llTitle.getLayoutParams();
        params.setMargins(0, getStatusHeight(), 0, 0);
        llTitle.setLayoutParams(params);

        //默认设置一个Frg
getSupportFragmentManager().beginTransaction().replace(R.id.tabMainContainer, Fragment.newInstance()).commit();
    }

    /*** 获取状态栏高度
     *
     * @return
     */
    private intgetStatusHeight() {
        int resourceId = MainActivity.this.getResources().getIdentifier("status_bar_height", "dimen", "android");
        returngetResources().getDimensionPixelSize(resourceId);

    }

    @Override
    public voidonClick(View v) {
        if (v.getId() ==R.id.infoText) {
            getSupportFragmentManager().beginTransaction().replace(R.id.tabMainContainer, Fragment.newInstance()).commit();
        } else if (v.getId() ==R.id.secondText) {
            getSupportFragmentManager().beginTransaction().replace(R.id.tabMainContainer, Fragment1.newInstance()).commit();

        }
    }


    private voidinitListeners() {
        //获取内容总高度
        final ViewTreeObserver vto =llContent.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public voidonGlobalLayout() {
                height =llContent.getHeight();
                //注意要移除
llContent.getViewTreeObserver()
                        .removeGlobalOnLayoutListener(this);

            }
        });

        //获取Fragment高度
        ViewTreeObserver viewTreeObserver =frameLayout.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public voidonGlobalLayout() {
                height = height -frameLayout.getHeight();
                //注意要移除
frameLayout.getViewTreeObserver()
                        .removeGlobalOnLayoutListener(this);
            }
        });

        //获取title高度
        ViewTreeObserver viewTreeObserver1 =llTitle.getViewTreeObserver();
        viewTreeObserver1.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public voidonGlobalLayout() {
                height = height - llTitle.getHeight() - getStatusHeight();//计算滑动的总距离
                stickyScrollView.setStickTop(llTitle.getHeight() + getStatusHeight());//设置距离多少悬浮
                //注意要移除
llTitle.getViewTreeObserver()
                        .removeGlobalOnLayoutListener(this);
            }
        });


    }

    @Override
    public void onScrollChanged(int l, int t, int oldl, intoldt) {
        if (t <= 0) {
            llTitle.setBackgroundColor(Color.argb((int) 0, 255, 255, 255));

        } else if (t > 0 && t <=height) {
            float scale = (float) t /height;
            int alpha = (int) (255 *scale);
            llTitle.setBackgroundColor(Color.argb((int) alpha, 227, 29, 26));//设置标题栏的透明度及颜色
            StatusBarUtil.setTranslucentForImageView(MainActivity.this, alpha, title);//设置状态栏的透明度
        } else { StatusBarUtil.setTranslucentForImageView(MainActivity.this, 0, title);
            llTitle.setBackgroundColor(Color.argb((int) 255, 227, 29, 26));
            StatusBarUtil.setTranslucentForImageView(MainActivity.this, 255, title);
        }
    }
}

最后,尊重一下上述代码的原作者,具体代码可到github下载,https://github.com/xiaoyuanandroid/ProductPage。

免责声明:文章转载自《Android中的沉浸式状态栏效果》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇sql server 碎片整理——DBCC SHOWCONTIG使用JavaScript开发Acrobat应用程序01下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

10个经典的Android开源项目(附源码包)

      最近在抽空学习Android系统开发,对Android学习也比较感兴趣,刚开始学就试着在网上找几个项目源码研究看下,以下就将找到的Android项目源码列出,希望对正在或准备学习Android系统开发开发的能有些帮助!       1、Android团队提供的示例项目  如果不是从学习Android SDK中提供的那些样例代码开始,可能没有更好...

Android studio初见及结构分析

经过千辛万苦之后,终于安装上了Android studio1.5,下面就来看一下AS的界面,了解一下工程结构,为以后的App开发做准备。 下图即为用于测试的App结构: 如上图所见,App结构包括两个子目录,包括app和Gradle Scripts两个子目录,首先对这两个子目录分别进行介绍: app目录中又包含三个子目录,其中 1、mainfests包含...

点击状态栏回到顶部两种实现

1.局部设置 scrollView有个属性scrollsToTop,默认值为YES. 所以默认情况下点击状态栏就可以回到顶部。但当一个控制器中有多个scrollView或其子类时,因为默认值都是YES,所以系统不知道要让哪个scrollView回到顶部。所以要让需要回到顶部的scrollView.scrollsToTop = YES,而其他的scrollV...

Android Native C 之 Helloworld的四种编译方式_转载

一.编写helloworld.c Android.mk     [root@fontlose jni]# cat hello.c  [cpp] view plaincopyprint?  #include <stdio.h>   int main()   {       printf("Hello World!\n");       ...

android体系结构介绍

   1)应用程序层          Android平台不仅仅是操作系统,也包含了许多应用程序,诸如SMS短信客户端程序、电话拨号程序、图片浏览器、Web浏览器等应用程序。这些应用程序都是       用Java语言编写的,并且这些应用程序都是可以被开发人员开发的其他应用程序所替换,这点不同于其他手机操作系统固化在系统内部的系统软件,更加灵活和个    ...

android在windows下面coco2dx平台搭建以及一些常见问题的解决

  最近因为参加比赛一些coco2dx的游戏,并且跨平台移植 ,废了好几天的时间,终于搞定了coco2dx的环境配置以及移植的全过程,在这片文章里面先说明一下我的coco2dx在windows下开发配置 闲话不说,直接上正文吧 1.首先,配置android开发环境(JAVA环境,eclipse+adt), 这个应该不用多说了吧   不明白的朋友们可以去参考...