PS:这个方案存在缺陷,其实并没什么鸟用。不过其中涉及的物理尺寸和像素的转换,这个知识还是有点应用的,比如可以用来制作直尺,将手机屏幕当直尺用,测量其他物体的尺寸。
1、物理尺寸和像素单位的转换方法
安卓支持的单位有dp、px、pt(英寸/72)、mm(毫米)、in(英寸),很明显 pt(英寸/72)、mm(毫米)、in(英寸)是物理单位,是实际尺寸。
∵ 打印分辨率=每英寸像素个数
,即
dpi = px/in
,
安卓中,屏幕的dpi和屏幕像素是可以求出的,于是可以计算出屏幕的物理尺寸。
in = px/dpi
又 1英寸 = 2.54厘米
所以,可以将像素尺寸转换为实际的物理尺寸:
public static float covertXPx2Cm(Context context, float px) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
return px / dm.xdpi * 2.54f;
}
public static float covertYPx2Cm(Context context, float px) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
return px / dm.ydpi * 2.54f;
}
说明,由于横纵轴上的像素密度(实际上是ppi,但很多时候等于dpi,实际打印到纸张上才有区别)是不同的,所以对横纵像素,分别转换。
2、尝试将pt作为百分比单位
若屏幕宽高皆为100pt,那么pt自然就变成了百分比单位。
——理想很美好,现实很谷歌,这是不成功方案
∵ dpi = px/in
,
又 ∵ in = pt/72
∴ dpi = px*72/pt
依据上述推导出的公式 dpi = px*72/pt
,我们只要令px为屏幕像素尺寸, pt 固定为100,改变安卓原有的dpi大小,即可使pt变成百分比单位。
所以在Application继承类App中有以下代码:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
changeAppConfig();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
changeAppConfig();
}
private void changeAppConfig() {
// 改变pt定义(pt:一英寸/72),将屏幕宽度设置750pt。
// px = pt*dpi/72;
// dpi = px*72/pt;//固定pt为750
DisplayMetrics dm = getResources().getDisplayMetrics();
getResources().getDisplayMetrics().xdpi = dm.widthPixels * 72f / 100f;
getResources().getDisplayMetrics().ydpi = dm.heightPixels * 72f / 100f;
}
}
然后在AndroidManifest.xml的Application标签中指定App:
android:name=".App"
添加布局文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvRedMain"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:background="@color/colorAccent"
android:textColor="#ffffff" />
<TextView
android:id="@+id/tvBlueMain"
android:layout_width="50pt"
android:layout_height="100pt"
android:background="@color/colorPrimaryDark"
android:textColor="#ffffff" />
</android.support.v7.widget.LinearLayoutCompat>
在Activity中测量屏幕并测试一下这个View的宽高是否符合预期:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvRedMain = findViewById(R.id.tvRedMain);
DisplayMetrics dm = getResources().getDisplayMetrics();
tvRedMain.setText(
"屏幕\n dpi:" + dm.densityDpi
+ " density:" + dm.density
+ " sDensity" + dm.scaledDensity
+ " wpx" + dm.widthPixels
+ " hpx" + dm.heightPixels
+ " xdpi" + dm.xdpi
+ " ydpi" + dm.ydpi
);
// 屏幕物理宽度:cm
float screenWidthCm = dm.widthPixels / dm.xdpi * 2.54f;
// 屏幕物理高度:cm
float screenHeightCm = dm.heightPixels / dm.ydpi * 2.54f;
tvRedMain.append(" width:" + screenWidthCm + "cm");
tvRedMain.append(" height:" + screenHeightCm + "cm");
tvBlueMain = findViewById(R.id.tvBlueMain);
tvBlueMain.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
tvBlueMain.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
tvBlueMain.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
DisplayMetrics dm = getResources().getDisplayMetrics();
tvBlueMain.append("当前View\n w:50pt h:100pt");
tvBlueMain.append(" w:" + tvBlueMain.getMeasuredWidth());
tvBlueMain.append(" h:" + tvBlueMain.getMeasuredHeight());
tvBlueMain.append(" w:" + tvBlueMain.getMeasuredWidth() / dm.xdpi * 2.54 + "cm");
tvBlueMain.append(" h:" + tvBlueMain.getMeasuredHeight() / dm.ydpi * 2.54 + "cm");
}
});
}
运行结果:
结果发现宽度设置100pt的确是50%填充,但是高度并没有。高度的百分比是无效的,它以宽度为标准进行计算。100%的高度实际等于屏幕的宽度。
这个发现,让计划功败垂成。
另外,由于我们对pt重新定义,还导致了物理宽高的计算出现了偏差。因为此时的1pt已经并非72分之一英寸,而且,设置宽高均为100pt,还导致了计算出的物理宽高是相等的。因为pt就是物理尺寸啊。
显然我用代码改变了手机屏幕大小,产品经理正在欢呼胜利。
这么弄可能会造成一些测量上的失误,所以并不成功。
而假如,我按照原来的比例设置pt,dpi,由于pt的改变,按 一英寸 = 2.54cm 自然是算不准物理高度的:
private void changeAppConfig() {
// 改变pt定义(pt:一英寸/72),将屏幕宽度设置750pt。
// px = pt*dpi/72;
// dpi = px*72/pt;//固定pt为750
DisplayMetrics dm = getResources().getDisplayMetrics();
float xdpi = dm.widthPixels * 72f / 100f;
float ydpi = xdpi*dm.ydpi/dm.xdpi;
getResources().getDisplayMetrics().xdpi = xdpi;
getResources().getDisplayMetrics().ydpi = ydpi;
}
但还保留着宽高比例:
注释掉changConfig方法,得到正确的物理尺寸计算结果:
3、结论
结论就是通过改变 pt 单位的配置进行安卓的适配,存在缺陷,并没什么鸟用。