The Flutter hybrid development family includes the following:

  • Embed native View-Android
  • Embed native View-ios
  • Communicate with native -MethodChannel
  • Communicate with native -BasicMessageChannel
  • Communicate with native -EventChannel
  • Add Flutter to Android Activity
  • Add Flutter to Android Fragment
  • Add Flutter to iOS

Share one article every weekday, welcome to follow, like and forward.

Create a FlutterFragment with a new engine

Adding a Flutter to a Fragment is basically the same as adding an Activity. If adding a Flutter to an Activity meets your requirements, it is recommended to use an Activity because it is more flexible and easy to use.

Add to Fragment code:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val fragment = FlutterFragment.createDefault()
        supportFragmentManager
            .beginTransaction()
            .add(R.id.fragment_container, fragment)
            .commit()
    }
}
Copy the code

The activity_main layout file is modified as follows:

<? The 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" tools:context=".MainActivity"> <FrameLayout android:id="@+id/fragment_container" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toTopOf="@+id/button"/> <Button Android :id="@+id/button" Android :layout_width="wrap_content" Android :layout_height="wrap_content" Android :text=" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>Copy the code

The red area is the FlutterFragment section, which is mostly Android native knowledge.

The UI is already loaded, but there are no interactions or behaviors. In general, the Activity lifecycle needs to be passed transparently to the FlutterFragment:

class MainActivity : AppCompatActivity() {
  override fun onPostResume(a) {
    super.onPostResume() flutterFragment!! .onPostResume() }override fun onNewIntent(@NonNull intent: Intent){ flutterFragment!! .onNewIntent(intent) }override fun onBackPressed(a){ flutterFragment!! .onBackPressed() }override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String? >, grantResults:IntArray
  ){ flutterFragment!! .onRequestPermissionsResult( requestCode, permissions, grantResults ) }override fun onUserLeaveHint(a){ flutterFragment!! .onUserLeaveHint() }override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level) flutterFragment!! .onTrimMemory(level) } }Copy the code

Initialize the new engine route

Specify engine routing:

val fragment = FlutterFragment
    .withNewEngine()
    .initialRoute("one_page")
    .build<FlutterFragment>()

supportFragmentManager
    .beginTransaction()
    .add(R.id.fragment_container, fragment)
    .commit()
Copy the code

Create a FlutterFragment using a cache engine

Each FlutterFragment creates a FlutterEngine (a Flutter engine). FlutterFragment also supports a cache engine. Start the engine in MyApplication:

class MyApplication : Application() {
    lateinit var flutterEngine: FlutterEngine

    override fun onCreate(a) {
        super.onCreate()
        flutterEngine = FlutterEngine(this)
        flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache
            .getInstance()
            .put("engine_id", flutterEngine)


    }
}
Copy the code

Use:

val fragment = FlutterFragment
    .withCachedEngine("engine_id")
    .build<FlutterFragment>()

supportFragmentManager
    .beginTransaction()
    .add(R.id.fragment_container, fragment)
    .commit()
Copy the code

Initialize the cache engine route

Initialize the route for the cache engine:

flutterEngine = FlutterEngine(this)

flutterEngine.navigationChannel.setInitialRoute("one_page")

flutterEngine.dartExecutor.executeDartEntrypoint(
    DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
    .getInstance()
    .put("engine_id", flutterEngine)
Copy the code

Changing entry points

By default, the entryPoint of FlutterFragment is the main() function, and we can modify its entryPoint,

val fragment = FlutterFragment
    .withNewEngine()
    .dartEntrypoint("newMain")
    .build<FlutterFragment>()
Copy the code

Dart add entryPoint to main.dart file:

void main() => runApp(MyApp());

void newMain()=> runApp(NewApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      routes: {
        'one_page':(context){
          return OnePage();
        },
        'two_page':(context){
          return TwoPage();
        }
      },
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}class NewApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: TwoPage() ); }}Copy the code

NewMain is the new EntryPoint.

Change the rendering mode of FlutterFragment

There are two rendering modes for FlutterFragment: SurfaceView and TextureView, SurfaceView by default, SurfaceView performs better than TextureView, but it has to be at the top or bottom of the hierarchy, and on Android versions prior to Android N, There is no way to animate surfaceViews because their layout and rendering are out of sync with other View hierarchies, so choose a proper render mode and set it as follows:

val fragment = FlutterFragment
    .withNewEngine()
    .renderMode(RenderMode.texture)
    .build<FlutterFragment>()
Copy the code

Set FlutterFragment transparency

By default, FlutterFragment uses the SurfaceView to render opaque backgrounds. For any pixels not drawn by the Flutter, the background is black. For performance reasons, rendering with an opaque background is preferred. Transparent Flutter rendering on Android can negatively impact performance. However, sometimes Flutter needs to be transparent to display the UNDERLYING UI. Therefore, Flutter supports transparent Settings in FlutterFragment.

val fragment = FlutterFragment
    .withNewEngine()
    .transparencyMode(TransparencyMode.transparent)
    .build<FlutterFragment>()
Copy the code

Put the press under the FlutterFragment,

<? The 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" tools:context=".MainActivity"> <Button Android :id="@+id/button" Android :layout_width="wrap_content" Android :layout_height="wrap_content" Android :text=" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <FrameLayout android:id="@+id/fragment_container" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>Copy the code

The background of the FlutterFragment was already transparent, but it was not transparent when it was run. The buttons were not displayed because the Flutter itself was not transparent.

@override
Widget build(BuildContext context) {
  returnScaffold( appBar: AppBar( title: Text(widget.title), ), backgroundColor: Colors.transparent, ... ) ; }Copy the code

communication

Lao Meng Flutter blog (330 controls usage + practical primer series) : laomengit.com