如何在Flutter中嵌套Android布局

效果

本文具体demo效果如下

开发

1.首先创建flutter项目,在项目中定义好flutter需要展示布局:

@override

Widget build(BuildContext context) {

return Scaffold(

body: Column(

crossAxisAlignment: CrossAxisAlignment.start,

children: <Widget>[

Expanded(

child: Center(

child: Text(

'Android按钮点击了 $_counter 次',

style: const TextStyle(fontSize: 17.0)),

),

),

Container(

padding: const EdgeInsets.only(bottom: 15.0, left: 5.0),

child: Row(

children: <Widget>[

Image.asset('assets/flutter-mark-square-64.png', scale: 1.5),

const Text('Flutter', style: TextStyle(fontSize: 30.0)),

],

),

),

],

),

floatingActionButton: FloatingActionButton(

onPressed: _sendFlutterIncrement,

child: const Icon(Icons.add),

),

);

}

上述代码所呈现的布局就是效果图中Flutter那一部分(上半部分),设置FloatingActionButton是为了呈现Flutter与Android的交互过程, "Android按钮点击了 $_counter 次"呈现的是交互结果,Image.asset()则显示的是Flutter的logo(标记这是flutter中的布局)。之所以这样做是因为Flutter与Android页面相互嵌套通产伴随着数据交互。

2.创建Android中的布局:

<io.flutter.embedding.android.FlutterView

android:id="@+id/flutter_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_weight="1"

/>

<androidx.coordinatorlayout.widget.CoordinatorLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_weight="1"

android:background="@color/grey"

>

<LinearLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

>

<TextView

android:id="@+id/button_tap"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:text="@string/button_tap"

...

/>

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/android"

...

/>

</LinearLayout>

<com.google.android.material.floatingactionbutton.FloatingActionButton

android:id="@+id/button"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

...

/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

io.flutter.embedding.android.FlutterView就是需要展示的flutter布局也就是第一步中编写的布局,剩下的部分和第一步的逻辑是一样的,有用来展示交互结果的TextView(@+id/button_tap),标记Android页面的TextView(@string/android),用来交互的按钮FloatingActionButton。

3.定义通信渠道

Flutter:

static const String _channel = 'increment';

static const String _pong = 'pong';

static const String _emptyMessage = '';

static const BasicMessageChannel<String> platform =

BasicMessageChannel<String>(_channel, StringCodec());

int _counter = 0;

@override

void initState() {

super.initState();

platform.setMessageHandler(_handlePlatformIncrement);

}

Future<String> _handlePlatformIncrement(String message) async {

setState(() {

_counter++;

});

return _emptyMessage;

}

void _sendFlutterIncrement() {

platform.send(_pong);

}

代码中通信渠道使用的是BasicMessageChannel,没有用MethodChannel和EventChannel是因为BasicMessageChannel可以随时随地进行任何通信,而另外两种则各自有各自的局限性,这里就不做解释了,稍后会有文章专门介绍这三种通信渠道。_channel 是通信渠道的名称,这个是唯一且固定的,一旦定义好,Android端也要使用相同的名称,否则两者无法对接,导致通信失败。_pong是Flutter向Android传递的消息内容,Android每次接收的内容为"pong",相应的Flutter按钮点击次数就+1,消息内容和类型用户都可以自定义,只要定义好BasicMessageChannel的泛型和消息编码机制(文中使用的是StringCodec)即可。如果消息的内容比较多,开发者可以使用Json进行消息传递。_counter是flutter接收Android按钮的点击次数,Android按钮每点击一次_counter就+1。相关变量或常量定义完后,开发者需要在initState()中进行消息接收处理,因为BasicMessageChannel是双向通信,platform.setMessageHandler(_handlePlatformIncrement)就是对接收到的消息进行处理,_handlePlatformIncrement方法说明了消息的类型是String,消息是异步,_counter+1后调用setState()刷新布局后相应展示的Android按钮点击次数就+1了。platform.send(_pong)就是Flutter按钮点击完后调用这个方法,然后BasicMessageChannel将消息发送到Android。

Android:

private static FlutterEngine flutterEngine;

private FlutterView flutterView;

private int counter;

private static final String CHANNEL = "increment";

private static final String EMPTY_MESSAGE = "";

private static final String PING = "ping";

private BasicMessageChannel<String> messageChannel;

...

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if (flutterEngine == null) {

flutterEngine = new FlutterEngine(this, args);

flutterEngine.getDartExecutor().executeDartEntrypoint(

DartEntrypoint.createDefault()

);

}

...

flutterView = findViewById(R.id.flutter_view);

flutterView.attachToFlutterEngine(flutterEngine);

messageChannel = new BasicMessageChannel<>(flutterEngine.getDartExecutor(), CHANNEL, StringCodec.INSTANCE);

messageChannel.

setMessageHandler(new MessageHandler<String>() {

@Override

public void onMessage(String s, Reply<String> reply) {

onFlutterIncrement();

reply.reply(EMPTY_MESSAGE);

}

});

FloatingActionButton fab = findViewById(R.id.button);

fab.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

sendAndroidIncrement();

}

});

...

CHANNEL 是通信渠道的名称也是渠道的标识符,一定要和flutter统一,否则无法通信。BasicMessageChannel是通信渠道,如果使用了和flutter端不一样的,也是无法通信的。EMPTY_MESSAGE是Android端收到Flutter消息后给Flutter的回复,表示让Flutter知道Android收到消息了。Android端收到消息后在setMessageHandler中进行消息处理:将flutter点击按钮次数+1( onFlutterIncrement()),同时回复确认收到的消息(reply.reply(EMPTY_MESSAGE))。FloatingActionButton发生点击事件后调用sendAndroidIncrement方法就会向Flutter发送消息说自己点击了一次按钮:

private void sendAndroidIncrement() {

messageChannel.send(PING);

}

PING就是Android向Flutter发送的消息内容,Flutter收到消息后就对Android点击按钮次数+1。如果传递的消息比较多,还需要对具体的消息进行判断来确认需要做哪些处理,本文中只传递一种内容的消息,所以对消息的参数和方法没有做判断。代码中flutterView即是需要展示的Flutter布局,flutterEngine则是flutter引擎(说法不统一), flutterView.attachToFlutterEngine(flutterEngine)则是为flutterView注入生命和能量,否则flutterView就是空空没有生命和内容的控件。flutterEngine和AppCompatActivity的生命周期是绑定在一起:

@Override

protected void onResume() {

super.onResume();

flutterEngine.getLifecycleChannel().appIsResumed();

}

@Override

protected void onPause() {

super.onPause();

flutterEngine.getLifecycleChannel().appIsInactive();

}

@Override

protected void onStop() {

super.onStop();

flutterEngine.getLifecycleChannel().appIsPaused();

}

@Override

protected void onDestroy() {

flutterView.detachFromFlutterEngine();

super.onDestroy();

}

Android中一旦出现了对生命周期的绑定,就是说只要按要求来,就不会出现乱七八糟的问题,即使有问题也不是它的问题。

总结

  • Flutter与Android的交互在不断迭代中已经变得比较完善,最新Flutter版本中已经比Flutter早期的版中简单很多。
  • 如果能避免Flutter与Android的相互嵌套就尽量避免,因为两者的嵌套很耗能,可能出现卡顿、死机、高耗电等问题。

说明

有些代码展示不全,详情请查看demo。

以上就是如何在Flutter中嵌套Android布局的详细内容,更多关于Flutter中嵌套Android布局的资料请关注其它相关文章!

以上是 如何在Flutter中嵌套Android布局 的全部内容, 来源链接: utcz.com/p/243621.html

回到顶部