一种低成本的Flutter屏幕适配方案

5,311 阅读3分钟

背景

老生常谈,屏幕适配,UI切图,视觉还原.

解决方案

从Android中来,到Android中去

Android的适配方案现在相对比较优秀的是头条这个

今日头条屏幕适配方案终极版正式发布!

骚年你的屏幕适配方式该升级了!-今日头条适配方案

我理解他的原理就是通过修改系统设置项,把DP值转化成以宽度或者高度为基准的度量单位,即宽度或者高度的百分比,然后RD可以快速把设计稿转化成UI视图.

怎么把这套方案搬到Flutter上

OK,知道原理后,怎么把这套方案搬到Flutter上面,也就是怎么修改Flutter的相对像素单位值?

修改如下:

// main函数
void main() => InnerWidgetsFlutterBinding.ensureInitialized()
  ..attachRootWidget(new MyApp())
  ..scheduleWarmUpFrame();
  

// 具体实现
const double SCREEN_WIDTH = 1242;

double getAdapterRatio() {
  return ui.window.physicalSize.width / SCREEN_WIDTH;
}

Size getScreenAdapterSize() {
  return Size(SCREEN_WIDTH, ui.window.physicalSize.height / getAdapterRatio());
}



class InnerWidgetsFlutterBinding extends WidgetsFlutterBinding {
  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null) InnerWidgetsFlutterBinding();
    return WidgetsBinding.instance;
  }

  @override
  ViewConfiguration createViewConfiguration() {
    return ViewConfiguration(
      size: getScreenAdapterSize(),
      devicePixelRatio: getAdapterRatio(),
    );
  }
}

这里的1242是和UE沟通的标准尺寸. 使用的标准尺寸手机是iPhone 6Plus.

扩展方法方案

上面的方法,有个问题是修改了Flutter系统的默认相对像素单位,我这边使用没有问题,但是会导致项目内其他RD开发的时候出现问题. 而我的目的仅仅是想用一个低成本的方案,快速把页面画出来.

extension Adapt on Diagnosticable {
  static MediaQueryData mediaQuery = MediaQueryData.fromWindow(window);
  static double _width = mediaQuery.size.width;
  static var _ratio;

  init(int number) {
    int uiwidth = number is int ? number : 1242;
    _ratio = _width / uiwidth;
  }

  px(number) {
    if (!(_ratio is double || _ratio is int)) {
      init(1242);
    }
    return number * _ratio;
  }
}

这里使用扩展函数,扩展到Diagnosticable上,因为还没找到dart里面怎么写顶层函数,先这样写.

  1. 为什么要用扩展函数

和Kotlin一样,为了不写工具类

  1. 为什么要扩展到Diagnosticable

因为布局类里面的实例,就是Diagnosticable的子类,扩展到这上面不用依赖外部类实例.

看个例子就明白了,上面的代码用法如下:

                  Positioned(
                    top: 0,
                    child: Image.asset(
                      'assets/images/bg/pay_head.png',
                      width: px(1037),
                    ),
                  ),
                  Positioned(
                    bottom: px(310),
                    child: Container(
                      height: px(796),
                      width: px(1072),
                      child: ...
                    ),
                  ),

如果使用扩展的写法,这里直接传入一个px()函数就行了,里面的参数是直接从UE的切图里面拿出来用的,也不会修改系统默认单位,其他RD也感知不到.

具体的效果如下:

这样写起来就会很快,也能满足适配要求.

问题

这里的视觉还没还原,我这里先大概评估下方案.

第三部(iphone8)手机高度设置有些问题

因为这里使用的是宽度为基础值,但是有些切图参数是标注的高度,这个时候要么转换成相对宽度值, 要么RD自己估算下.

人物背景圆角都有问题

这里圆角是切图画上去的,外面又有一个自己画的圆角,两个圆角不同源肯定有问题. 要么直接全部让UE画下,这样开发起来可以快点. 要么全部让RD自己画,UE只给人偶单图.

第二手机怎么有删格出现

我也想知道,Android手机怎么了,按理说这个Google Pixel3配置不差啊.

总结

Android碎片化严重,所以Android屏幕适配方案很早就有成熟的东西出来了,对比下这两个东西的应用场景其实没什么大的差别, 那么人们为什么会对Flutter适配感到苦恼呢?

正所谓知易而行难,知道了一个知识点只能解决眼前的问题或者更多的只是充当一些谈资, 善用知识归纳,内化,运用才能真正帮到自己吧.