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