适配完结篇2-谷歌小弟的 Android 多分辨率适配框架

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.TextView;

// 版权声明:https://blog.csdn.net/lfdfhl/article/details/52735103
public class SupportMultipleScreensUtil {
public static final int BASE_SCREEN_WIDTH = 1080;
public static float scale = 1.0F;

private SupportMultipleScreensUtil() {

}

public static void init(Context context) {
Resources resources = context.getResources();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
scale = (float) widthPixels / BASE_SCREEN_WIDTH;
}

public static void scale(View view) {
if (null != view) {
if (view instanceof ViewGroup) {
scaleViewGroup((ViewGroup) view);
} else {
scaleView(view);
}
}
}

public static void scaleViewGroup(ViewGroup viewGroup) {
for (int i = 0; i < viewGroup.getChildCount(); ++i) {
View view = viewGroup.getChildAt(i);
if (view instanceof ViewGroup) {
scaleViewGroup((ViewGroup) view);
}
scaleView(view);
}
}

public static void scaleView(View view) {
Object isScale = view.getTag(R.id.is_scale_size_tag);
if (!(isScale instanceof Boolean) || !((Boolean) isScale).booleanValue()) {
if (view instanceof TextView) {
scaleTextView((TextView) view);
} else {
scaleViewSize(view);
}
view.setTag(R.id.is_scale_size_tag, Boolean.valueOf(true));
}
}

// 对于TextView,不但要缩放其尺寸,还需要对其字体进行缩放:
private static void scaleTextView(TextView textView) {
if (null != textView) {
scaleViewSize(textView);

Object isScale = textView.getTag(R.id.is_scale_font_tag);
if (!(isScale instanceof Boolean) || !((Boolean) isScale).booleanValue()) {
float size = textView.getTextSize();
size *= scale;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}

Drawable[] drawables = textView.getCompoundDrawables();
Drawable leftDrawable = drawables[0];
Drawable topDrawable = drawables[1];
Drawable rightDrawable = drawables[2];
Drawable bottomDrawable = drawables[3];
setTextViewCompoundDrawables(textView, leftDrawable, topDrawable, rightDrawable, bottomDrawable);
int compoundDrawablePadding = getScaleValue(textView.getCompoundDrawablePadding());

textView.setCompoundDrawablePadding(compoundDrawablePadding);
}
}

/**
* 等比例缩放: 对每个View的宽高,padding,margin值都按比例缩 放,并且在缩放后重新设置其布局参数。 博客地址:
*/
private static void scaleViewSize(View view) {
if (null != view) {
int paddingLeft = getScaleValue(view.getPaddingLeft());
int paddingTop = getScaleValue(view.getPaddingTop());
int paddingRight = getScaleValue(view.getPaddingRight());
int paddingBottom = getScaleValue(view.getPaddingBottom());
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);

LayoutParams layoutParams = view.getLayoutParams();
if (null != layoutParams) {
if (layoutParams.width > 0) {
layoutParams.width = getScaleValue(layoutParams.width);
}

if (layoutParams.height > 0) {
layoutParams.height = getScaleValue(layoutParams.height);
}

if (layoutParams instanceof MarginLayoutParams) {
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams;
int topMargin = getScaleValue(marginLayoutParams.topMargin);
int leftMargin = getScaleValue(marginLayoutParams.leftMargin);
int bottomMargin = getScaleValue(marginLayoutParams.bottomMargin);
int rightMargin = getScaleValue(marginLayoutParams.rightMargin);
marginLayoutParams.topMargin = topMargin;
marginLayoutParams.leftMargin = leftMargin;
marginLayoutParams.bottomMargin = bottomMargin;
marginLayoutParams.rightMargin = rightMargin;
}
}
view.setLayoutParams(layoutParams);
}
}

private static void setTextViewCompoundDrawables(TextView textView, Drawable leftDrawable, Drawable topDrawable,
Drawable rightDrawable, Drawable bottomDrawable) {
if (null != leftDrawable) {
scaleDrawableBounds(leftDrawable);
}

if (null != rightDrawable) {
scaleDrawableBounds(rightDrawable);
}

if (null != topDrawable) {
scaleDrawableBounds(topDrawable);
}

if (null != bottomDrawable) {
scaleDrawableBounds(bottomDrawable);
}
textView.setCompoundDrawables(leftDrawable, topDrawable, rightDrawable, bottomDrawable);
}

// 考虑到对TextView的CompoundDrawable进行缩放
private static Drawable scaleDrawableBounds(Drawable drawable) {
int right = getScaleValue(drawable.getIntrinsicWidth());
int bottom = getScaleValue(drawable.getIntrinsicHeight());
drawable.setBounds(0, 0, right, bottom);
return drawable;
}

private static int getScaleValue(int value) {
return value <= 4 ? value : (int) Math.ceil((double) (scale * (float) value));
}

}

图简便, 直接贴了代码, R.id.is_scale_size_tagR.id.is_scale_size_tag报错只需要在\res\values下创建ids.xml文件下定义即可

1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<item type="id" name="test"/>
</resources>

用法

1
2
3
4
5
6
7
8
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View rootView=findViewById(android.R.id.content);
SupportMultipleScreensUtil.init(getApplication());
SupportMultipleScreensUtil.scale(rootView);
}

总结

  • 切图存放于drawable-nodpi
  • 抛开系统的dpi并且摒弃dp和sp,统一使用px作为尺寸单位
  • 按照给定高分辨率(如1920*1080)切图和布局, 其实只有1080px有参考价值
  • 根据需要, 等比例缩放每个View

目前,xxhdpi分辨率的手机占了主流,所以在该框架中采用了drawable-xxhdpi的切图。倘若以后xxxhdpi分辨率的手机占了主导地位,那么就请UI设计师按照该分辨率切图,我们将其放在drawable-nohdpi中,再修改BASE_SCREEN_WIDTH即可。

文章来源(References)

Android多分辨率适配框架(1)— 核心基础 - CSDN博客