前提
平时xml中view的宽高单位都是dp居多,我们的设计师一般会选择一款机型的屏幕尺寸作为设计的目标尺寸。
那么,如何根据目标尺寸的屏幕密度,适配我们种类繁多的机型?
实现目标
将以dp作为单位,以目标尺寸标注的宽高,和当前机型的比例,动态进行屏幕适配。
例如:设计尺寸为360dp宽,我们的view设置180dp宽。那么,该view在任何屏幕尺寸下,都将占用屏幕一半的尺寸;
了解参数
在上代码前,先了解下待会用到的参数含义:
- density
当前机型的屏幕密度,标准屏幕密度是每平方英寸有160个像素,如果当前机型每平方英寸有320个像素,即density = (320 / 160)= 2; - scaleDensity
代表的是字体的屏幕密度,默认情况下:scaleDensity = density; - densityDpi
表示的就是每平方英寸显示的像素点个数。
如:160个像素点 即densityDpi=160;
上代码
代码其实非常简单,直接从DisplayMetrics中获取。
private final static float WIDTH = 360;//适配机型的宽为360dp,屏幕宽/屏幕密度=360dp
private static float appDensity;
private static float appScaleDensity;
public static void setDensity(Application application, Activity activity) {
//获取当前app的屏幕显示信息
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
appDensity = displayMetrics.density;
appScaleDensity = displayMetrics.scaledDensity;
//计算等比缩放后的density和scaleDensity
//WIDTH相对于所有屏幕宽度都是相等的,它是用dp作为单位,所以 屏幕宽度/屏幕密度=WIDTH
//targetDensity = targetWidht/WIDTH
float targetDensity = displayMetrics.widthPixels / WIDTH;
//appScaleDensity/appDensity=targetScaleDensity/targetDensity;
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//替换activity的density,appdensity,densityDpi
DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
aDisplayMertics.density = targetDensity;
aDisplayMertics.scaledDensity = targetScaleDensity;
aDisplayMertics.densityDpi = targetDensityDpi;
}
}
思路讲解,计算
首先我们需要获取当前机型的屏幕密度信息:appDensity,appScaleDensity
我们的设计尺寸会根据默认机型计算出一个固定的以dp为单位的宽度:WIDTH
比如:默认机型的宽高为1080*1920,该设备的屏幕密度为3
那么WIDTH = 1080/3 = 360dp;因此所有适配机型的宽也就等于360dp。
根据 屏幕宽度 / 屏幕密度=WIDTH公式,现在知道屏幕宽度和WIDTH,也就能求出:屏幕密度=屏幕宽度 / WIDHT;
现在屏幕宽度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。
接下来,就需要求出适配机型的scaleDensity
appScaleDensity / appDensity = targetScaleDensity / targetDensity ;
targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;
densityDpi = density * 160 ;
最后,把获取到的数据,设置到activity的displayMetrics中。
计算出来后,我们需要在绘制view之前先设置好
在onCreate中的setContentView之前添加
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//在绘制前设置density
DensityUtils.setDensity(this.application, this)
setContentView(R.layout.activity_screen_adapter2)
}
现在,我们的设计尺寸宽度为360dp,我们设置view的宽度为180dp,应该是占用屏幕一半尺寸。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.screenAdapter2.ScreenAdapter2Activity”>
<TextView
android:id=“@+id/tv1”
android:layout_width=“180dp”
android:layout_height=“180dp”
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#f00" />
<TextView
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_below="@id/tv1"
android:layout_toRightOf="@id/tv1"
android:background="#0f0" />
</RelativeLayout>
显示效果:
device-2019-10-21-102743.png
字体的缩放监听
以上代码在字体发生改变时,不会根据字体设置相应的发生改变
我们需要监听字体改变事件,再重新计算scaleDensity;
//完整代码
public static void setDensity(final Application application, Activity activity) {
//获取当前app的屏幕显示信息
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
appDensity = displayMetrics.density;
appScaleDensity = displayMetrics.scaledDensity;
//监听字体改变,重新获取scaleDensity
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
//计算等比缩放后的density和scaleDensity
//WIDTH相对于所有屏幕宽度都是相等的,它是用dp作为单位,所以 屏幕宽度/屏幕密度=WIDTH
//targetDensity = targetWidht/WIDTH
float targetDensity = displayMetrics.widthPixels / WIDTH;
//appScaleDensity/appDensity=targetScaleDensity/targetDensity;
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//替换activity的density,appdensity,densityDpi
DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
aDisplayMertics.density = targetDensity;
aDisplayMertics.scaledDensity = targetScaleDensity;
aDisplayMertics.densityDpi = targetDensityDpi;
}
![QQ20191012-122912.png](https://img.haomeiwen.com/i1982159/bccbae9c9d2e1fd8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
网友评论