手机接PC显示器界面适配(PC模式)

前段时间,华为推出了PC模式,暂时只支持Mate10和P20系列,插上华为的Type C扩展坞就可以连接USB设备和外接显示器。说到这个,中兴也在忙着新手机的准备,相信看到这里的同学都想知道这是个啥玩意了吧。根据我的理解,你就把撞上显示器的这台手机当成电脑主机就可以了,通过Type C扩展外接鼠标键盘你就可以使用经过适配的APP了。

问题1

如何知道当前应用使用的是PC显示器打开还是手机原始打开?方法如下:
通过getDisplayId获取值来判断!值为0则表示当前为手机模式,否则当作PC模式。
目前支持电脑模式的手机版本基本在8.0以上,8.0以下手机还没听说有这种操作,所以需要做个版本判断

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    // textview可为界面中已经初始化完成的任意view
    Display display = textview.getDisplay();  
    // 当前显示设备为手机 
    if (display != null && display.getDisplayId() == 0){
    }else{//  当前显示器为非手机
    }
}else{
}

此时我们知道了当前使用的是PC模式还是手机模式以后做适配就方便了。
这里我们还需要知道屏幕的密度,因为不同的显示屏幕(包括PC显示器)的密度是不一样的,和况手机密度也分好多种。

DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
if (dm != null) {
    float screenDensity = dm.density;// 密度
}
问题2

首先适配要适配啥呢?(我这里所讲的适配仅针对屏幕上的一些动态添加的组件及Canvas画bitmap的适配)一般情况下,如果界面布局通过XML写死位置以后在两者屏幕上显示是不需要做适配的,位置基本上不会因为屏幕密度发生改变。非一般的情况则是我们有时候需要往一个容器中添加一个或多个组件,这个时候我们需要计算要添加在容器中的什么位置的时候有可能就会被影响到了。(比方说界面中xml只有一个LinewrLayout,需要手动地在里面添加各种不同的组件,比如天气组件,搜索框,列表等等...),这时我们需要注意,通常我们在适配手机的时候往往一些设置控件的dpi值或px值都是按照2倍图也就是密度为2的大小设置的,在PC显示器中,有大部分显示器密度可能为1,但应该也存在更小或偏大的密度,此时,设置在手机上的值重新设置在PC显示器中,将影响整个组件的形变。比如下:

// 从资源文件中获取PX值,getDimension获取的值是将dp转换为px以后的值
int mBottomBarHeight = mContext.getResources().getDimension(R.dimen.bottombar_height);
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mCompositorView.getLayoutParams();
// layoutParams.bottomMargin = mBottomBarHeight;// 此时,这样设置在手机端是没任何问题的,但在PC端显示的距离就大了去了,位置是不正确的。需要除以密度才能设置为正确的位置
layoutParams.bottomMargin = (int)(mBottomBarHeight/screenDensity);// 正确设置在PC显示器上,所以这里要做区分到底设置在手机上还是PC显示器上,用上面提供的方法

一般设置距离位置等遇到问题基本上都是因为不同显示器密度不同,需要除以密度实现正确的位置。(以上是我在密度为1的PC显示器上总结的观点)

其次需要适配的还有Canvas中drawBitmap()的问题。在画布上画一张bitmap在手机上也是无任何问题,但PC显示器上依然不正确。(只显示了整张图的一部分)

整张图为
整图

但只显示一部分如:
部分显示
解决办法如下:

加上这么一句话bitmap.density= resources.displayMetrics.densityDpi,修改bitmap的density为运行设备上的density就可以了

var bitmap=BitmapFactory.decodeResource(resources,R.drawable.ic_launcher,opt).copy(Bitmap.Config.ARGB_8888,true);
bitmap.density= resources.displayMetrics.densityDpi;// 加上这句代码
canvas= Canvas(bitmap)
canvas.drawBitmap(bitmap, 0f, 0f, null)
问题3

在使用PC模式下,动态添加进入界面的view(如写一个通用Dialog,需要往中间添加不同的view),显示时,字体变大。

解决办法

将字体设置的sp转换成px重新设置一遍。

    /**
     * 根据手机分辨率从 sp 的单位 转成为  px
     */
    public static int sp2px(Context context, float spValue) {
        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * scale + 0.5f);
    }
// 重新设置字体,并使用px单位
textview.setTextSize(TypedValue.COMPLEX_UNIT_PX,DensityUtils.sp2px(activity,13));