安卓屏幕适配——pt适配,将pt作为宽度百分比单位


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 单位的配置进行安卓的适配,存在缺陷,并没什么鸟用。

猜你喜欢

转载自blog.csdn.net/Mingyueyixi/article/details/81741554
今日推荐