屏幕适配的方式
-
限定符适配
App会根据当前的分辨率自动选择对应分辨率的资源
限定符适配有以下优势
- 使用简单,无需开发者手动指定
- Google推荐使用方式,有系统自己判断
- 适配通过不同的xml布局完成,无需在代码中额外再写
缺点
需要很多xml资源
增大了包体积
-
百分比适配
- google 有一个库
- 只能使用第三方的百分比的父布局所以可扩展性较差
-
动态代码适配
这个就是手动在java层来做处理有三方式
-
第一个跟百分比布局一样自己手写ViewGroup
public class UIRelativeLayout extends RelativeLayout {
private boolean flag = false;
public UIRelativeLayout(Context context) {
super(context);
}
public UIRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UIRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(flag) {
//获取水平方向的缩放比
float scaleX = UIUtils.getInstance(getContext()).getHorizontalScaleValue();
//获取垂直方向的缩放比
float scaleY = UIUtils.getInstance(getContext()).getVerticalScaleValue();
int count = getChildCount();
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
LayoutParams params = (LayoutParams) view.getLayoutParams();
params.width *= scaleX;
params.height *= params.height * scaleY;
params.bottomMargin *= scaleY;
params.leftMargin *=scaleX;
//可以设置padding margin等值
}
flag = true;
}
}
}
上述方式需要跟百分比布局一样,需要使用自己手写的ViewGroup,子控件就可以跟平常一样了,而且不能预览
-
第二种方式将ViewGroup的操作,抽象成一个工具类中的方法,自己手动触发
public void updateSize(View view){
//获取水平方向的缩放比
float scaleX = UIUtils.getInstance(view.getContext()).getHorizontalScaleValue();
//获取垂直方向的缩放比
float scaleY = UIUtils.getInstance(view.getContext()).getVerticalScaleValue();
Layoutparams params = view.getLayoutParams();
if(params.width>0){
params.width*=scaleX;
}
if(params.height>0){
params.height*=scaleY;
}
}
这种方式最为麻烦,因为每个View都需要自己手动修改
-
第三种方式自己手动改activity的density属性
public class Density {
//UI图尺寸
private static final float WIDTH = 720;
private static float appDensity;
private static float appScaleDensity;
public static void setDensity(Application application, Activity activity) {
DisplayMetrics metrics = application.getResources().getDisplayMetrics();
if (appDensity == 0) {
appDensity = metrics.density;
appScaleDensity = metrics.scaledDensity;
//注册的监听器主要是监听系统设置改变字体大小的。
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale != 0) {
appScaleDensity = newConfig.fontScale;
}
}
@Override
public void onLowMemory() {
}
});
}
//根据当前屏幕宽度和UI设计图的宽相除获得density
float targetDensity = metrics.widthPixels / WIDTH;
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//将自己的desity给activity
DisplayMetrics dm = activity.getResources().getDisplayMetrics();
dm.density = targetDensity;
dm.scaledDensity = targetScaleDensity;
dm.densityDpi = targetDensityDpi;
}
}
然后再需要的Activity的setContentView()之前调用即可,这种方式非常简单,而且高效,推荐使用。
缺点暂未发现
顺便附上UIUtils的源码
public class UIUtils {
public static final float STANDARD_WIDTH = 1080f;
public static final float STANDARD_HEIGHT = 1980f;
private static UIUtils instance;
private float displayMetricsHeight ;
private float displayMetricsWidth ;
private float systemBarHeight;
//为了防止内存泄漏,请使用application
public static UIUtils getInstance(Context context) {
if (instance == null) {
instance = new UIUtils(context);
}
return instance;
}
public static UIUtils getInstance() {
if (instance != null) {
return instance;
}
return null;
}
private UIUtils(Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
systemBarHeight = getSystemBarHeight(context);
if(metrics.widthPixels>metrics.heightPixels){
displayMetricsHeight = metrics.widthPixels- systemBarHeight;
displayMetricsWidth = metrics.heightPixels;
}else {
displayMetricsHeight = metrics.heightPixels-systemBarHeight;
displayMetricsWidth = metrics.widthPixels;
}
}
//获取宽度缩放比
public float getHorizontalScaleValue(){
return displayMetricsWidth/STANDARD_WIDTH;
}
public float getVerticalScaleValue(){
return displayMetricsHeight/STANDARD_HEIGHT;
}
private int getSystemBarHeight(Context context){
return getValue(context,"com.android.internal.R$dimen","system_bar_height",48);
}
private int getValue(Context context,String dimeClass,String system_bar_height ,int defaultVaule){
try {
Class<?> clz = Class.forName(dimeClass);
Object object = clz.newInstance();
Field field = clz.getField(system_bar_height);
int id = Integer.parseInt(field.get(object).toString());
return context.getResources().getDimensionPixelSize(id);
}catch (Exception e){
e.printStackTrace();
}
return 0;
}