一般写Dialog的时候,都会设置宽度为屏幕的宽度1
2
3
Window window = getDialog().getWindow(); WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.BOTTOM;
params.width = WindowManager.LayoutParams.MATCH_PARENT; window.setAttributes(params);
但是有时候会出现一些奇怪的问题
layout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="utf-8"?> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"> <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@+id/menu1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:padding="15dp"
android:text="重新登录"
android:textColor="#fa0000"
android:background="@drawable/seletcor_top_bg"
/>
<View android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#f5f4f4"/>
<TextView android:id="@+id/menu2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:padding="15dp"
android:text="退出"
android:textColor="#2763b6"
android:background="@drawable/seletcor_bottom_bg"
/>
</LinearLayout> <Button android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="15dp"
android:background="@drawable/seletcor_round_bg"
android:text="取消"
/> </LinearLayout>
效果展示 按照上面的代码写的时候,效果是这样的。
这不是我们想要的效果。
当我们多设置一步 A window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
它会去除所有的padding
效果是这样的。
这个也不是我们想要的效果
当我们多设置一步 B window.getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
效果是这样的。
看起来符合我们的要求,但是这个边距实际上是系统提供的,我们不能自己设置。
代码分析
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
为什么会去除padding
?
1
public abstract void setBackgroundDrawable (Drawable drawable) ;
这个方法是个抽象方法,它的唯一实现是PhoneWindow
。1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public final void setBackgroundDrawable (Drawable drawable) {
if (drawable != mBackgroundDrawable || mBackgroundResource != 0 ) {
mBackgroundResource = 0 ;
mBackgroundDrawable = drawable;
if (mDecor != null ) {
mDecor.setWindowBackground(drawable);
}
if (mBackgroundFallbackResource != 0 ) {
mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
}
}
}
这里主要看mDecor.setWindowBackground(drawable);
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void setWindowBackground (Drawable drawable) {
if (getBackground() != drawable) {
setBackgroundDrawable(drawable);
if (drawable != null ) {
mResizingBackgroundDrawable = enforceNonTranslucentBackground(drawable,
mWindow.isTranslucent() || mWindow.isShowingWallpaper());
} else {
mResizingBackgroundDrawable = getResizingBackgroundDrawable(
getContext(), 0 , mWindow.mBackgroundFallbackResource,
mWindow.isTranslucent() || mWindow.isShowingWallpaper());
}
if (mResizingBackgroundDrawable != null ) {
mResizingBackgroundDrawable.getPadding(mBackgroundPadding);
} else {
mBackgroundPadding.setEmpty();
}
drawableChanged();
}
}
setBackgroundDrawable(drawable);
方法会进入View
的setBackgroundDrawable
方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if (background != null ) {
Rect padding = sThreadLocal.get();
if (padding == null ) {
padding = new Rect();
sThreadLocal.set(padding);
}
resetResolvedDrawablesInternal();
background.setLayoutDirection(getLayoutDirection());
if (background.getPadding(padding)) {
resetResolvedPaddingInternal();
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
mUserPaddingLeftInitial = padding.right;
mUserPaddingRightInitial = padding.left;
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
break ; case LAYOUT_DIRECTION_LTR:
default :
mUserPaddingLeftInitial = padding.left;
mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
mLeftPaddingDefined = false ;
mRightPaddingDefined = false ;
}
}
其中background.getPadding(padding)
这句话很有意思。
1
2
3
4
5
6
public boolean getPadding (@NonNull Rect padding) {
padding.set(0 , 0 , 0 , 0 );
return false ; }
当它的参数有值的时候,返回的是true,当它返回false的时候,padding都会被设置为0。
因为我们传入的是ColorDrawable
,它没有重写这个方法,所以它返回的永远是false。方法里面不执行。 回到DecorView
的setWindowBackground
方法。1
2
3
4
5
if (mResizingBackgroundDrawable != null ) {
这句话会重置mBackgroundPadding为0 0 0 0
mResizingBackgroundDrawable.getPadding(mBackgroundPadding); } else {
mBackgroundPadding.setEmpty(); }
drawableChanged();
而drawableChanged
会重新设置padding
,所以window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
会将默认的padding清0。
1
2
3
4
5
6
7
8
9
10
11
12
private void drawableChanged () {
if (mChanging) {
return ;
}
setPadding(mFramePadding.left + mBackgroundPadding.left,
mFramePadding.top + mBackgroundPadding.top,
mFramePadding.right + mBackgroundPadding.right,
mFramePadding.bottom + mBackgroundPadding.bottom);
requestLayout();
invalidate();
}
为什么window.getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
会保留padding
?
也很好理解了。因为它实际上直接调用了View
的setBackgroundDrawable
方法。根据之前的逻辑,到了if (background.getPadding(padding))
这一步它是不会重新设置padding
的。
总结 当同时设置View
的padding
和背景
的时候。调用顺序很重要。