package com.example.administrator.searchpicturetool.widght.fitsystemwindowlayout; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.widget.RelativeLayout; import com.example.administrator.searchpicturetool.R; /** * Created by zhuchenxi on 15/11/7. */ public class FitSystemWindowsRelativeLayout extends RelativeLayout{ public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; private static int STATUSBAR_HEIGHT; private static int NAVIGATIONBAR_HEIGHT; private int mScreenOrientation = VERTICAL; private boolean isInputMethod = false; private int mInputMethodHeight = 0; private boolean mPaddingStatusBar; private boolean mPaddingNavigationBar; private int mStatusBarColor = 0; private int mStatusBarHeight = 0; private int mNavigationBarHeight = 0; private Paint mStatusBarPaint; public FitSystemWindowsRelativeLayout(Context context) { super(context); init(); } public FitSystemWindowsRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); initAttrs(attrs); init(); } public FitSystemWindowsRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAttrs(attrs); init(); } protected void initAttrs(AttributeSet attrs) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.fit_system_windows); try { int colorAttr; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { colorAttr = android.R.attr.colorPrimaryDark; } else { colorAttr = getContext().getResources().getIdentifier("colorPrimaryDark", "attr", getContext().getPackageName()); } TypedValue outValue = new TypedValue(); getContext().getTheme().resolveAttribute(colorAttr, outValue, true); if (outValue.resourceId!=0)mStatusBarColor = getResources().getColor(outValue.resourceId); mStatusBarColor = a.getColor(R.styleable.fit_system_windows_status_color,mStatusBarColor); mPaddingStatusBar = a.getBoolean(R.styleable.fit_system_windows_padding_status, true); mPaddingNavigationBar = a.getBoolean(R.styleable.fit_system_windows_padding_navigation, false); Utils.log("initAttrs"+" mStatusBarColor"+mStatusBarColor+" mPaddingStatusBar:"+mPaddingStatusBar+" mPaddingStatusBar:"+mPaddingStatusBar); } finally { a.recycle(); } } private void init(){ int statusBarHeight = 0; int navigationBarHeight = 0; setWillNotDraw(false); setFitsSystemWindows(false);//不然4.4就会绘制默认的statusBar遮罩 mScreenOrientation = (getResources().getConfiguration().orientation== Configuration.ORIENTATION_PORTRAIT)?VERTICAL:HORIZONTAL; STATUSBAR_HEIGHT = Utils.getStatusBarHeight(getContext()); NAVIGATIONBAR_HEIGHT = Utils.getNavigationBarHeight(getContext()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ){ statusBarHeight = STATUSBAR_HEIGHT; if (Utils.hasSoftKeys(getContext())) navigationBarHeight = NAVIGATIONBAR_HEIGHT; } mStatusBarHeight = statusBarHeight; mNavigationBarHeight = navigationBarHeight; mStatusBarPaint = new Paint(); mStatusBarPaint.setColor(mStatusBarColor); Utils.log("init"+" mStatusBarHeight:"+mStatusBarHeight+" mNavigationBarHeight:"+mNavigationBarHeight); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mPaddingStatusBar){ canvas.drawRect(0,0,getRight(),mStatusBarHeight,mStatusBarPaint); } } public void setStatusBarColor(int color){ mStatusBarColor = color; mStatusBarPaint.setColor(mStatusBarColor); invalidate(); } @Override protected boolean fitSystemWindows(Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Utils.log("fitSystemWindows" +" Left:"+insets.left +" Top:"+insets.top +" Right:"+insets.right +" Bottom:"+insets.bottom); if(insets.bottom > NAVIGATIONBAR_HEIGHT){ mInputMethodHeight = insets.bottom; isInputMethod = true; }else { mInputMethodHeight = 0; isInputMethod = false; } applyPadding(); insets.set(0,0,0,0); } return super.fitSystemWindows(insets); } @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Utils.log("onApplyWindowInsets" +" Left:"+insets.getSystemWindowInsetLeft() +" Top:"+insets.getSystemWindowInsetTop() +" Right:"+insets.getSystemWindowInsetRight() +" Bottom:"+insets.getSystemWindowInsetBottom()); if(insets.getSystemWindowInsetBottom() > NAVIGATIONBAR_HEIGHT){ mInputMethodHeight = insets.getSystemWindowInsetBottom(); isInputMethod = true; }else { mInputMethodHeight = 0; isInputMethod = false; } applyPadding(); insets.replaceSystemWindowInsets(0,0,0,0);//使默认的padding效果失效,因为我完全自己处理了。 return insets;//我重写了自己的Padding规则,所以我可以无视对insets的处理。 } else { return insets; } } public void applyPadding(){ for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); //可滑动View内Padding if (mScreenOrientation == VERTICAL&&lp.isPaddingNavigation()) Utils.paddingToNavigationBar(child); if (!lp.hasSetMarginStatus()&&!lp.isForceLayout()){ lp.setMarginStatus(mPaddingStatusBar); } if (!lp.hasSetMarginNavigation()&&!lp.isForceLayout()){ lp.setMarginNavigation(mPaddingNavigationBar); } //合适的marginStatus与marginNavigation lp.topMargin = getStatusValue(lp); lp.bottomMargin = getNavigationVerticalValue(lp); lp.rightMargin = getNavigationHorizontalValue(lp); Utils.log(""+child.getClass().getSimpleName()+" "+lp.leftMargin+" - "+lp.topMargin+" - "+lp.rightMargin+" - "+lp.bottomMargin); } } //返回底部应有padding private int getNavigationVerticalValue(LayoutParams lp){ if (isInputMethod)return mInputMethodHeight; return (mScreenOrientation == VERTICAL)?(lp.mMarginNavigation?mNavigationBarHeight:0):0; } //返回右边应有padding private int getNavigationHorizontalValue(LayoutParams lp){ return (mScreenOrientation == HORIZONTAL)?(lp.mMarginNavigation?mNavigationBarHeight:0):0; } //返回顶部应有padding private int getStatusValue(LayoutParams lp){ return (lp.mMarginStatus?mStatusBarHeight:0); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { if (p instanceof LayoutParams) { return new LayoutParams((LayoutParams) p); } else if (p instanceof MarginLayoutParams) { return new LayoutParams((MarginLayoutParams) p); } return new LayoutParams(p); } @Override protected RelativeLayout.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } public static class LayoutParams extends RelativeLayout.LayoutParams { private boolean mPaddingNavigation = false; private boolean mMarginStatus = false; private boolean mHasSetMarginStatus = false; private boolean mMarginNavigation = false; private boolean mHasSetMarginNavigation = false; private boolean mForceLayout = false; public LayoutParams(Context context, AttributeSet attrs) { super(context, attrs); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.fit_system_windows); this.mPaddingNavigation = a.getBoolean( R.styleable.fit_system_windows_padding_navigation, false); mHasSetMarginStatus = a.hasValue(R.styleable.fit_system_windows_margin_status); mHasSetMarginNavigation = a.hasValue(R.styleable.fit_system_windows_margin_navigation); this.mMarginStatus = a.getBoolean( R.styleable.fit_system_windows_margin_status, false); this.mMarginNavigation = a.getBoolean( R.styleable.fit_system_windows_margin_navigation, false); this.mPaddingNavigation = a.getBoolean( R.styleable.fit_system_windows_padding_navigation, false); out:for (int i : getRules()) { switch (i){ case ABOVE: case BELOW: case ALIGN_BASELINE: case ALIGN_BOTTOM: case ALIGN_TOP: case CENTER_IN_PARENT: case CENTER_VERTICAL: mForceLayout = true; break out; } } a.recycle(); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(ViewGroup.LayoutParams p) { super(p); } public LayoutParams(MarginLayoutParams source) { super(source); } public boolean isForceLayout() { return mForceLayout; } public void setForceLayout(boolean mForceLayout) { this.mForceLayout = mForceLayout; } public boolean isPaddingNavigation() { return mPaddingNavigation; } public void setPaddingNavigation(boolean mPaddingNavigation) { this.mPaddingNavigation = mPaddingNavigation; } public boolean isMarginStatus() { return mMarginStatus; } public void setMarginStatus(boolean mMarginStatus) { mHasSetMarginStatus = true; this.mMarginStatus = mMarginStatus; } public boolean hasSetMarginStatus() { return mHasSetMarginStatus; } public boolean isMarginNavigation() { return mMarginNavigation; } public void setMarginNavigation(boolean mMarginNavigation) { mHasSetMarginNavigation = true; this.mMarginNavigation = mMarginNavigation; } public boolean hasSetMarginNavigation() { return mHasSetMarginNavigation; } } }