Flutter的副屏显示

最近一直在做Flutter项目,用来开发具有两块屏幕的收银机应用。在找遍了全网Flutter资料后发现,Flutter居然没有提供这样子的API,看来只能自己手工实现了。

POS收银机外型
POS收银机外型

由于副屏无需触屏幕交互,所以我打算利用 Android Presentation API 在副屏幕上显示个WebView,通过Flutter -> Native接口 -> 切换Web的Hash来发送副屏切换命令。

Android端代码

副屏代码

/**
 * 副屏
 */
public class AdPresentation extends Presentation {


    Activity context;

    XWebView mainWebView;

    /**
     * 全局变量
     */
    public static AdPresentation globalInstance;


    public AdPresentation(Context outerContext, Display display) {
        super(outerContext, display);
        if(outerContext instanceof Activity){
            context = (Activity) outerContext;
        }
        globalInstance = this;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ad);
        mainWebView = findViewById(R.id.MainWebView);
    }

    private void loadUrl(String hash){
        context.runOnUiThread(()->{
            String originUserAgent = mainWebView.getSettings().getUserAgentString();
            mainWebView.getSettings().setUserAgentString(originUserAgent);
            mainWebView.loadUrl(BuildConfig.PRESENTATION_URL+"#"+hash);
        });

    }

    /**
     * 切换页面
     */
    public void switchHash(String hash){
        loadUrl(hash);
    }

}

Flutter控制副屏的插件代码

/**
 * 副屏插件
 */
public class PresentationPlugin implements MethodChannel.MethodCallHandler {

    private Context mContext;

    //副屏幕
    DisplayManager mDisplayManager;//屏幕管理类
    Display mDisplay[];//屏幕数组
    Presentation lastDisplayPresentation;//用于记录上次展示的副屏的界面
    AdPresentation mPresentation;

    private PresentationPlugin(Context context) {
        mContext = context;
        showPresentation();
    }

    public void showPresentation() {
        mDisplayManager = (DisplayManager) MainActivity.globalInstance .getSystemService(Context.DISPLAY_SERVICE);
        mDisplay = mDisplayManager.getDisplays();
        if (mDisplay.length < 2) {
            return;
        }
        new Handler().postDelayed(() -> {
            mPresentation = new AdPresentation(MainActivity.globalInstance, mDisplay[1]);
            mPresentation.show();
            //延时取消,否则会闪动
            new Handler().postDelayed(() -> {
                if (lastDisplayPresentation != null) {
                    lastDisplayPresentation.dismiss();
                    lastDisplayPresentation = null;
                }
                lastDisplayPresentation = mPresentation;
            }, 100);
        }, 100);
    }

    public static void registerWith(PluginRegistry.Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "app/presentation");
        channel.setMethodCallHandler(new PresentationPlugin(registrar.context()));
    }

    @Override
    public void onMethodCall(MethodCall call, final MethodChannel.Result result) {
        switch (call.method) {
            case "switchHash":
                String hash = call.argument("hash").toString();
                if(mDisplay.length >= 2){
                    AdPresentation.globalInstance.switchHash(hash);
                    result.success("OK");
                }else{
                    result.error("FAIL", "NO_PRESENTATION", null);
                }
                break;
            default:
                result.notImplemented();
                break;
        }
    }
}

Flutter端

import 'dart:async';
import 'package:flutter/services.dart';

class PresentationPlugin {
  static const MethodChannel _channel = const MethodChannel('app/presentation');

  static Future<Null> switchHash({
    String hash,
    Function(String) callback,
  }) async {
    print('PresentationPlugin.swichHash:'+hash);
    try {
      final String resp = await _channel.invokeMethod('switchHash', {'hash': hash}); //切换副屏幕

      if (callback != null) {
        callback(resp);
      }

    } catch (e) {
      print(e);
    }    
  }
}

//调用切换
PresentationPlugin.switchHash(
    hash:"/pages/Payment?payway=wx",
);

总结

如果不需要交互,WebView真的是非常不错的渲染载体。