核心思路:利用ui设计稿的尺寸和手机自身尺寸得出缩放比,再将控件宽高处理后设置到控件上。性能方面会多渲染一次控件
ui设计稿高和宽这边假设是1920*1080,具体根据实际设计稿来设置
//ui图上的宽高
private static final int BASE_WIDTH = 1080;
private static final int BASE_HEIGHT = 1920; // ui给的图不包含状态栏,后面要减去状态栏的高度
定义一些变量
//设备的真实宽高
private static int displayWidth;
private static int displayHeight; // 后面要减去状态栏的高度
//状态栏高度
private int statusBarHeight;
//屏幕信息
private DisplayMetrics displayMetrics;
首先使用WindowManager获取本机屏幕长宽,存放在displayMetrics.widthPixels 和 displayMetrics.heightPixels中
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
而实际屏幕大小要减去状态栏高度,这边需要获取下状态栏高度
//使用运行过程中的资源文件
private int getStatusBarHeight(Context context) {
int statusBarHeight = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (statusBarHeight > 0) {
return statusBarHeight;
}
//上面方法获取不到的话,使用反射资源获取
return getStatusBarHeightByAndroid(context, "com.android.internal.R$dimen", "system_bar_height", 48);
}
private int getStatusBarHeightByAndroid(Context context, String className, String fieldName, int defValue) {
try {
//获取class
Class aClass = Class.forName(className);
//获取实例
Object o = aClass.newInstance();
Field field = aClass.getField(fieldName);
int id = Integer.parseInt(field.get(o).toString());
return context.getResources().getDimensionPixelOffset(id);
} catch (Exception e) {
return defValue;
}
}
根据是否横竖屏设置真实高度
/**
* 设置真实长宽
*/
public void refreshDisplayMetrics() {
//判断横竖屏
if (displayMetrics.widthPixels > displayMetrics.heightPixels) {//横屏
displayWidth = displayMetrics.heightPixels;
displayHeight = displayMetrics.widthPixels;
} else { //竖屏
displayWidth = displayMetrics.widthPixels;
displayHeight = displayMetrics.heightPixels;
}
}
至此初始化函数代码为下:
//初始化真实宽高
public void init(Context context) {
//使用WindowManager获取
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
//获取状态栏高度
statusBarHeight = getStatusBarHeight(context);
//根据状态栏高度初始化真实宽高
refreshDisplayMetrics();
}
再写两个获取处理后的宽和高的方法,高度计算时需减去状态栏高度
public float getWidth(float width) {
return width * displayWidth / BASE_WIDTH;
}
public float getHeight(float height) {
return height * (displayHeight - statusBarHeight) / (BASE_HEIGHT - statusBarHeight);
}
主要核心代码已完成,再将对控件的逻辑处理完成
/**
* view设置长宽等属性的逻辑处理
* 需使用px
*/
public class ViewCalculateUtil {
/**
* 设置layoutparams
*
* @param view
* @param width
* @param height
* @param topMargin
* @param bottomMargin
* @param leftMargin
* @param rightMargin
*/
public static void setLayoutParams(View view, int width, int height, int topMargin, int bottomMargin, int leftMargin, int rightMargin) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (layoutParams != null) {
if (width != LinearLayout.LayoutParams.MATCH_PARENT &&
width != LinearLayout.LayoutParams.WRAP_CONTENT) {
layoutParams.width = (int) UIUtils.getInstance().getWidth(width);
} else {
layoutParams.width = width;
}
if (height != LinearLayout.LayoutParams.MATCH_PARENT && height != LinearLayout.LayoutParams.WRAP_CONTENT) {
layoutParams.height = (int) UIUtils.getInstance().getHeight(height);
} else {
layoutParams.height = height;
}
layoutParams.topMargin = (int) UIUtils.getInstance().getHeight(topMargin);
layoutParams.bottomMargin = (int) UIUtils.getInstance().getHeight(bottomMargin);
layoutParams.leftMargin = (int) UIUtils.getInstance().getWidth(leftMargin);
layoutParams.rightMargin = (int) UIUtils.getInstance().getWidth(rightMargin);
view.setLayoutParams(layoutParams);
}
}
/**
* 设置字号
*
* @param view
* @param size
*/
public static void setTextSize(TextView view, int size) {
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, UIUtils.getInstance().getHeight(size));
}
/**
* 设置view的内边距
*
* @param view
* @param topPadding
* @param bottomPadding
* @param leftpadding
* @param rightPadding
*/
public static void setViewPadding(View view, int topPadding, int bottomPadding, int leftpadding, int rightPadding) {
view.setPadding((int) UIUtils.getInstance().getWidth(leftpadding),
(int) UIUtils.getInstance().getHeight(topPadding),
(int) UIUtils.getInstance().getWidth(rightPadding),
(int) UIUtils.getInstance().getHeight(bottomPadding));
}
}
可以使用上面工具类中的方法对单个控件进行适配,但我们不希望每个控件都要写一行代码,再进行封装得出下面的类:
/**
* 逐层处理viewgroup
*/
public class ViewsParseUtil {
/**
* 对activity中的所有控件进行适配
* @param activity
*/
protected static void parseAcitvity(Activity activity) {
//获取DecorView中id为content的布局
final ViewGroup context = (ViewGroup) activity.findViewById(android.R.id.content);
context.post(new Runnable() {
@Override
public void run() {
catchViewGroup(context);
}
});
}
/**
* 对组件进行适配
* @param viewGroup
*/
protected static void catchViewGroup(ViewGroup viewGroup) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View view = viewGroup.getChildAt(i);
catchChildView(view);
}
}
/**
* 对控件进行适配
* @param view
*/
private static void catchChildView(View view) {
if (view instanceof ViewGroup) {
catchViewGroup((ViewGroup) view);
} else {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
//设置LayoutParams
ViewCalculateUtil.setLayoutParams(view, layoutParams.width, layoutParams.height, layoutParams.topMargin, layoutParams.bottomMargin,
layoutParams.leftMargin, layoutParams.rightMargin);
if (view instanceof TextView) {//如果是textview,设配字体大小
TextView textView = (TextView) view;
ViewCalculateUtil.setTextSize(textView, (int) textView.getTextSize());
}
//设置padding
ViewCalculateUtil.setViewPadding(view, view.getPaddingTop(), view.getPaddingBottom(), view.getPaddingLeft(), view.getPaddingRight());
}
}
}
最后使用方法,在合适的地方初始化框架
UIUtils.getInstance().init(getApplicationContext());
在activity中调用
UIUtils.getInstance().registerActivity(this);
项目地址https://gitee.com/aruba/ScreenAdapter.git