[Flutter]Tạo Widget với Android Native bằng Platform Views

Một ví dụ về tạo 2 widget được triển khai dưới Android Native

Dưới Native

Đầu tiên, chúng ta sẽ tạo 2 class FirstWidget.kt và SecondWidget.kt:

  • FirstWidget.kt : Sử dụng file .xml

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import io.flutter.plugin.platform.PlatformView

internal class FirstWidget(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
    private val view: View

    override fun getView(): View {
        return view
    }

    init {
        view = LayoutInflater.from(context).inflate(R.layout.first_widget, null)
    }

    override fun dispose() {
    }
}
  • first_widget.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/first_widget">

    <TextView
        android:id="@+id/first_widget_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="FirstWidget from Android!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • SecondWidget.kt: 1 cách khác để tạo view
import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView

internal class SecondWidget(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
    private val textView = TextView(context)

    override fun getView(): View {
        return textView
    }

    override fun dispose() {}

    init {
        textView.textSize = 20f
        textView.setBackgroundColor(Color.rgb(255, 255, 255))
        textView.text = "Rendered on a native Android view (id: $id)"
    }
}

Tạo 2 class FirstWidgetFactory.kt và SecondWidgetFactory.kt:

  • FirstWidgetFactory.kt
import android.content.Context
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class FirstWidgetFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        val creationParams = args as Map<String?, Any?>?
        return FirstWidget(context, viewId, creationParams)
    }
}
  • SecondWidgetFactory.kt
import android.content.Context
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class SecondWidgetFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        val creationParams = args as Map<String?, Any?>?
        return SecondWidget(context, viewId, creationParams)
    }
}

Tại MainActivity.kt:

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)
        flutterEngine
                .platformViewsController
                .registry
                .registerViewFactory("com.example.flutter_app_demo1.FirstWidgetPlugin", FirstWidgetFactory())
        flutterEngine
                .platformViewsController
                .registry
                .registerViewFactory("com.example.flutter_app_demo1.SecondWidgetPlugin", SecondWidgetFactory())
    }

}

Về phần Dart

Tạo 2 file first_widget.dart và second_widget.dart:

  • first_widget.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';


class FirstWidget extends StatefulWidget {
  const FirstWidget({
    Key? key,
  }) : super(key: key);


  @override
  State<StatefulWidget> createState() => _FirstWidgetState();
}

class _FirstWidgetState extends State<FirstWidget> {
   String viewType = 'com.example.flutter_app_demo1.FirstWidgetPlugin';
   Map<String, dynamic> creationParams = <String, dynamic>{};
  @override
  Widget build(BuildContext context) {
    if (defaultTargetPlatform == TargetPlatform.android) {
      return SizedBox(
        width: 200,
        child: PlatformViewLink(
          viewType: viewType,
          surfaceFactory:
              (BuildContext context, PlatformViewController controller) {
            return AndroidViewSurface(
              controller: controller as AndroidViewController,
              gestureRecognizers:  const <Factory<OneSequenceGestureRecognizer>>{},
              hitTestBehavior: PlatformViewHitTestBehavior.opaque,
            );
          },
          onCreatePlatformView: (PlatformViewCreationParams params) {
            return PlatformViewsService.initSurfaceAndroidView(
              id: params.id,
              viewType: viewType,
              layoutDirection: TextDirection.ltr,
              creationParams: creationParams,
              creationParamsCodec: const StandardMessageCodec(),
              onFocus: () {
                params.onFocusChanged(true);
              },
            )
              ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
              ..create();
          },
        ),
      );
    }
    return const Text('iOS platform version is not implemented yet.');
  }

}
  • second_widget.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';

class SecondWidget extends StatefulWidget {
  const SecondWidget({
    Key? key,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => _SecondWidgetState();
}

class _SecondWidgetState extends State<SecondWidget> {
  String viewType = "com.example.flutter_app_demo1.SecondWidgetPlugin";
  Map<String, dynamic> creationParams = <String, dynamic>{};
  @override
  Widget build(BuildContext context) {
    if (defaultTargetPlatform == TargetPlatform.android) {
      return PlatformViewLink(
        viewType: viewType,
        surfaceFactory:
            (BuildContext context, PlatformViewController controller) {
          return AndroidViewSurface(
            controller: controller as AndroidViewController,
            gestureRecognizers:  const <Factory<OneSequenceGestureRecognizer>>{},
            hitTestBehavior: PlatformViewHitTestBehavior.opaque,
          );
        },
        onCreatePlatformView: (PlatformViewCreationParams params) {
          return PlatformViewsService.initSurfaceAndroidView(
            id: params.id,
            viewType: viewType,
            layoutDirection: TextDirection.ltr,
            creationParams: creationParams,
            creationParamsCodec: const StandardMessageCodec(),
            onFocus: () {
              params.onFocusChanged(true);
            },
          )
            ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
            ..create();
        },
      );
    }
    return const Text('iOS platform version is not implemented yet.');
  }

}

Sau đó gọi lại 2 Widget vừa rồi tại main.dart

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter PlatformView Example'),
      ),
      body: Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: const <Widget>[
          Card(
            child: SizedBox(
              height: 200,
              child: FirstWidget(),
            ),
          ),
          Card(
            child: SizedBox(
              height: 200,
              child: SecondWidget(),
            ),
          ),
        ],
      ),
    );
  }

PlatformView

PlatformView là một tính năng Flutter cần thực hiện để hiển thị Native-UIs toàn diện trên Android View / UIKitView.

Nếu bạn muốn biết thêm thông tin về PlatformView, hãy xem tài liệu chính thức:


Posted

in

by

Tags:

Comments

One response to “[Flutter]Tạo Widget với Android Native bằng Platform Views”

  1. Your code of destiny Avatar

    I’m really impressed along with your writing abilities and also with the format on your blog. Is this a paid subject matter or did you modify it your self? Anyway keep up the nice quality writing, it is uncommon to look a great blog like this one these days!

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: