Flutter小部件之AndroidView

AndroidView

Flutter 1.26.0-1.0.pre ,Dart 2.12.0 (build 2.12.0-141.0.dev)

在Flutter小部件上嵌入一個Android的View,與UiKitView對應(yīng),UiKitView是在Flutter小部件上嵌入一個ios的View.
源碼

屬性 釋義
viewType → String 這個小部件要嵌入的Android視圖類型的唯一標(biāo)識符。
clipBehavior → Clip 內(nèi)容被剪輯的方式,默認(rèn)是Clip.hardEdge,在曲線或非軸向直線會呈現(xiàn)鋸齒狀,可以使用Clip.antiAlias
creationParams → dynamic 在PlatformViewFactory調(diào)用create時,作為參數(shù)傳遞
creationParamsCodec → MessageCodec? 對其進(jìn)行編碼的編解碼器
gestureRecognizers → Set<Factory<OneSequenceGestureRecognizer>>? 哪些手勢應(yīng)該轉(zhuǎn)發(fā)到Android視圖。
hitTestBehavior → PlatformViewHitTestBehavior 這個小部件在沖擊測試期間應(yīng)該如何表現(xiàn)。
layoutDirection → TextDirection? android端view的文字方向
onPlatformViewCreated → PlatformViewCreatedCallback? 當(dāng)PlatformView創(chuàng)建時的回調(diào)

示例1 :在Flutter頁面的一個小部件嵌入一個原生的Android視圖。

要實現(xiàn)在Flutter頁面的一個小部件嵌入一個原生的Android視圖,會分為Flutter端和Android端兩端的工作。
我們這里實現(xiàn)在Flutter頁面的一個小部件嵌入一個原生的Android視圖,并可以兩端進(jìn)行通信。Flutter視圖顯示Android端
按鈕被點(diǎn)擊的次數(shù),而Android視圖顯示Flutter端按鈕被點(diǎn)擊的次數(shù),每一次點(diǎn)擊都會立即更新視圖。


android_view.gif

Flutter端需要做的:

  • 1.在Flutter的一個小部件中聲明一個AndroidView小部件,并指定AndroidView的viewType.
  • 2.在Flutter中聲明通道對象,并設(shè)置監(jiān)聽,當(dāng)Android端調(diào)用通道約定的函數(shù)時,獲取Android端傳來的Android按鈕點(diǎn)擊次數(shù),
    并更新Flutter的視圖。
  • 3.點(diǎn)擊Flutter按鈕時,通過通道函數(shù)將Flutter按鈕被點(diǎn)擊次數(shù)傳遞給Android端。

Flutter端第一步:在Android端需要注冊PlatformView的工程對象,與Flutter端產(chǎn)生映射關(guān)系,Map<String, PlatformViewFactory> viewFactories,
viewFactories來存儲它們的關(guān)系。

AndroidView(
            //與 Android 原生交互時唯一標(biāo)識符,與Android端有對應(yīng)關(guān)系
            viewType: 'plugins.flutter.io/android_view',
          ),

Flutter端第二步:

 //創(chuàng)建通道對象,與android端創(chuàng)建的通道對象名稱一致
  MethodChannel _channel = MethodChannel("plugins.flutter.io/channel_name_1");
  //安卓端的按鈕被點(diǎn)擊的次數(shù)
  String _androidButtonClickedNumber = '0';
  //當(dāng)前Flutter端按鈕被點(diǎn)擊的次數(shù)
  int _flutterButtonClickedNumber = 0;


 @override
  void initState() {
    super.initState();
    //設(shè)置此通道上的監(jiān)聽
    _channel.setMethodCallHandler(_handlerMethodCall);
  }

  Future<dynamic> _handlerMethodCall(MethodCall call) async{
    //獲取通道監(jiān)聽中調(diào)用的函數(shù)名稱
    String method = call.method;
    if(method == 'addAndroidButtonAndNoticeFlutter'){
       String androidButtonClickedNumber = call.arguments['AndroidButtonClickedNumber'];
       _androidButtonClickedNumber = androidButtonClickedNumber;
       setState(() {});
    }
  }

Flutter端第三步:

ElevatedButton(
    onPressed: () {
      _flutterButtonClickedNumber = _flutterButtonClickedNumber + 1;
      setState(() {});
      Map<String,String> map = {'FlutterButtonClickedNumber':_flutterButtonClickedNumber.toString()};
      //在Flutter端調(diào)用執(zhí)行函數(shù),將Flutter端按鈕的點(diǎn)擊次數(shù)傳遞到安卓端
      _channel.invokeMethod("addFlutterButtonAndNoticeAndroid",map);
    },
    child: Text("+1", style:
    TextStyle(fontSize: 18, color: Colors.white),
    ),
),

Adroid端需要做的:

  • 1.聲明一個類MyPlatformView實現(xiàn)PlatformView接口,必須實現(xiàn)getView()函數(shù),這里定義了要顯示的Android視圖。
  • 2.聲明一個類MyPlatformViewFactory繼承PlatformViewFactory類,重寫create函數(shù),這里返回上面我們聲明的MyPlatformView。
  • 3.聲明一個類MyPlatformViewPlugin實現(xiàn)FlutterPlugin和MethodChannel.MethodCallHandler接口,F(xiàn)lutterPlugin會在
    FlutterEngine綁定和解綁的時候產(chǎn)生回調(diào),我們可以在這兩個時機(jī)分別進(jìn)行注冊和注銷的工作。在MyPlatformViewPlugin
    中創(chuàng)建通道對象,并監(jiān)聽來自Flutter端的函數(shù)調(diào)用,并進(jìn)行之后的刷新Android視圖。
  • 4.將MyPlatformViewPlugin注冊到FlutterEngine

Android端第一步:

public class MyPlatformView implements PlatformView {

    private View mNativeView;
    private TextView mTvCount;
    private Button mBtnAdd;
    private int mAndroidButtonClickedNumber = 0;
    private MethodChannel mChannel;

    public MyPlatformView(Context context, MethodChannel channel) {
        mChannel = channel;
        mNativeView = LayoutInflater.from(context).inflate(R.layout.view_my_flutter,null,false);
        mTvCount = mNativeView.findViewById(R.id.tv_count);
        mBtnAdd = mNativeView.findViewById(R.id.btn_add);

        mTvCount.setText("Flutter的按鈕被點(diǎn)擊數(shù)量:0");

        //點(diǎn)擊安卓按鈕并將安卓按鈕點(diǎn)擊數(shù)量通知Flutter端
        mBtnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mAndroidButtonClickedNumber = mAndroidButtonClickedNumber + 1;
                Map<String,String> map = new HashMap<>();
                map.put("AndroidButtonClickedNumber",mAndroidButtonClickedNumber+"");
                mChannel.invokeMethod("addAndroidButtonAndNoticeFlutter",map);
            }
        });
    }

    /**
     * 返回嵌入到Flutter頁面中的安卓原生view
     * @return
     */
    @Override
    public View getView() {
        return mNativeView;
    }

    /**
     * Flutter的按鈕被點(diǎn)擊數(shù)量+1
     * 安卓原生會顯示Flutter的按鈕被點(diǎn)擊的數(shù)量
     */
    public void showFlutterButtonClickedNumber(String number){
        mTvCount.setText("Flutter的按鈕被點(diǎn)擊數(shù)量:"+number);
    }
    @Override
    public void onFlutterViewAttached(@NonNull View flutterView) { }
    @Override
    public void onFlutterViewDetached() { }
    @Override
    public void dispose() { }


}

Android端第二步:


public class MyPlatformViewFactory extends PlatformViewFactory {

    private MethodChannel mChannel;
    public MyPlatformView mMyPlatformView;

    public MyPlatformViewFactory(MessageCodec<Object> createArgsCodec, MethodChannel channel) {
        super(createArgsCodec);
        mChannel = channel;
    }

    /**
     *
     * @param context
     * @param viewId 在Flutter端AndroidView的唯一識別id
     * @param args Flutter端AndroidView傳遞過來的參數(shù)
     * @return
     */
    @Override
    public PlatformView create(Context context, int viewId, Object args) {
        mMyPlatformView = new MyPlatformView(context,mChannel);
        return mMyPlatformView;
    }

}

Android端第三步:


public class MyPlatformViewPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler {

    private MethodChannel mChannel;
    private MyPlatformViewFactory mMyPlatformViewFactory;


    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
        //創(chuàng)建通道對象,通道名稱與Flutter端通道的名稱一致
        mChannel = new  MethodChannel(binding.getBinaryMessenger(),"plugins.flutter.io/channel_name_1");
        //注冊此通道的監(jiān)聽
        mChannel.setMethodCallHandler(this);
        //創(chuàng)建PlatformView的工廠對象
        mMyPlatformViewFactory = new MyPlatformViewFactory(StandardMessageCodec.INSTANCE,mChannel);
        //在Flutter引擎上注冊PlatformView的工廠對象
        binding.getPlatformViewRegistry()
                .registerViewFactory("plugins.flutter.io/android_view",mMyPlatformViewFactory);
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        //注銷通道的監(jiān)聽
        mChannel.setMethodCallHandler(null);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        //獲取監(jiān)聽到的函數(shù)名稱
        String methodName = call.method;
        if (methodName.equals("addFlutterButtonAndNoticeAndroid")){
            String flutterButtonClickedNumber = call.argument("FlutterButtonClickedNumber");
            mMyPlatformViewFactory.mMyPlatformView.showFlutterButtonClickedNumber(flutterButtonClickedNumber);
        }
    }
}

Android端第四步:

public class MainActivity extends FlutterActivity {
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        //注冊插件
        flutterEngine.getPlugins().add(new MyPlatformViewPlugin());
    }
}

注:此例子是在純Flutter項目中實現(xiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容