屏幕适配的一种解决方案
程序员文章站
2022-03-11 09:01:22
...
android屏幕适配
屏幕适配的一种解决方案
众所周知,安卓屏幕适配一直以来是一个头疼闹热的问题,市面上的解决方案也层出不群,比如:google的百分比适配,还有像素目录适配等,这里要说的是另外的一种方式,而且这种方式几乎能够适配所有的屏幕
方法说明
其实很简单,大致需要两个步骤:
- 根据ui切图的尺寸与当前屏幕的尺寸计算出尺寸比例
- 继承需要适配的控件对需要的属性进行一个缩放就行了
实现代码
首先通过工具类得到尺寸比例
package com.example.screenadaptiondemo
import android.content.Context
import android.util.DisplayMetrics
import android.view.WindowManager
import java.lang.Exception
class UiUtils {
companion object{
private const val DIME_CLASS = "com.android.internal.R\$dimen"
/**这两个值一般是ui设计给出的标准的尺寸*/
private const val UI_HEIGHT = 1920f
private const val UI_WIDTH = 1080f
/**当前屏幕除了状态栏的宽度*/
private var disPlayMetricsWidth = -1f
/**当前屏幕除了状态栏的高度*/
private var disPlayMetricsHeight = -1f
private var mUiUtils: UiUtils? = null
fun getInstance(context: Context): UiUtils{
if(mUiUtils == null){
mUiUtils = UiUtils(context)
}
return mUiUtils!!
}
}
private var mContext: Context
private constructor(context: Context){
mContext = context
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val disPlayMetrics = DisplayMetrics()
if(disPlayMetricsHeight == -1f || disPlayMetricsWidth == -1f){
windowManager.defaultDisplay.getMetrics(disPlayMetrics)
val statusBarHeight = getStatusHeight(context)
//判断横屏还是竖屏
if(disPlayMetrics.widthPixels > disPlayMetrics.heightPixels){
//横屏
disPlayMetricsWidth = disPlayMetrics.heightPixels.toFloat()
disPlayMetricsHeight = (disPlayMetrics.widthPixels - statusBarHeight).toFloat()
}else {
disPlayMetricsWidth = disPlayMetrics.widthPixels.toFloat()
disPlayMetricsHeight = (disPlayMetrics.heightPixels - statusBarHeight).toFloat()
}
}
}
/**
* 得到宽度的比例值
*/
fun getWidthScaleValue(): Float = (disPlayMetricsWidth/ UI_WIDTH)
/**
* 得到高度上的比例值
*/
fun getHeightScaleValue(): Float = (disPlayMetricsHeight / (UI_HEIGHT - getStatusHeight(mContext)))
/**
* 获取状态栏的高度
*/
private fun getStatusHeight(context: Context): Int {
return getValue(context, DIME_CLASS, "system_bar_height", 48)
}
private fun getValue(context: Context, dimeClass: String, sysbarHeight: String, defValue: Int): Int {
try {
val clazz = Class.forName(dimeClass)
val obj = clazz.newInstance()
val filedObj = clazz.getField(sysbarHeight)
val statusHeight = filedObj.get(obj).toString().toInt()
return context.resources.getDimensionPixelSize(statusHeight)
}catch (e: Exception){
return defValue
}
return defValue
}
}
然后继承需要适配的布局控件,进行相关属性值的计算
package com.example.screenadaptiondemo;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class MyRelativeLayout extends RelativeLayout {
private static final String TAG = "MyRelativeLayout";
/**需要这个标志来控制自己在onMeasure里面写的方法只走一次*/
private boolean isFlag = false;
public MyRelativeLayout(Context context) {
super(context);
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(!isFlag){
//拿到宽度与高度的比例值
float scaleX = UiUtils.Companion.getInstance(getContext()).getWidthScaleValue();
float scaleY = UiUtils.Companion.getInstance(getContext()).getHeightScaleValue();
for (int i = 0; i < getChildCount(); i++) {
LayoutParams layoutParams = (LayoutParams) getChildAt(i).getLayoutParams();
//宽度乘以比例值得到的就是适配之后的控件的宽度
layoutParams.width = (int) (layoutParams.width * scaleX);
layoutParams.height = (int) (layoutParams.height * scaleY);
layoutParams.leftMargin = (int) (layoutParams.leftMargin * scaleX);
layoutParams.rightMargin = (int) (layoutParams.rightMargin * scaleX);
layoutParams.topMargin = (int) (layoutParams.topMargin * scaleY);
layoutParams.bottomMargin = (int) (layoutParams.bottomMargin * scaleY);
}
isFlag = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}