对于混合开发的应用而言,通常我们只会将应用的部分模块修改成 Flutter 开发,其他模块继续保留原生开发,因此应用内除了 Flutter 的页面之外,还会有原生 Android、iOS 的页面。在这种情况下,Flutter 页面有可能会需要跳转到原生页面,而原生页面也可能会需要跳转到 Flutter 页面。这就涉及到了一个新的问题:如何统一管理原生页面和 Flutter 页面跳转交互的混合导航栈。
示例 从原生跳转Flutter在跳回原生
Flutter 代码
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
void main() => runApp(
_widgetForRoute(window.defaultRouteName)
);
const platform = MethodChannel('samples.chenhang/navigation');
Widget _widgetForRoute(String route) {
switch (route) {
default:
return MaterialApp(
theme: ThemeData(
pageTransitionsTheme: PageTransitionsTheme(builders: {
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
})),
home:DefaultPage(showBack: true),
);
}
}
class PageA extends StatelessWidget {
bool showBack;
PageA({ Key key, this.showBack=false }) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.greenAccent,
appBar: AppBar(title: Text("Flutter Page A")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Page A',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
),
),
RaisedButton(
child: Text("Go Native Page"),
onPressed: ()=>platform.invokeMethod('openNativePage')
)
],
),
)
);
}
}
class DefaultPage extends StatelessWidget {
bool showBack;
DefaultPage({Key key, this.showBack=false }) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.redAccent,
appBar: AppBar(
title: Text("Flutter Default Page"),
leading: !showBack?
null:IconButton(
icon:Icon(Icons.arrow_back),
onPressed:() => platform.invokeMethod('closeFlutterPage')
)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Default Page',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
),
),
RaisedButton(
child: Text("Go Page A"),
onPressed: ()=>Navigator.push(
context, MaterialPageRoute(
builder: (context) => PageA())),
)
],
),
)
);
}
}
iOS端代码
FlutterHomeViewController *vc = [[FlutterHomeViewController alloc]init];
[vc setInitialRoute:@"defaultPage"];
[self.navigationController pushViewController:vc animated:YES];
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface FlutterHomeViewController : FlutterViewController
@end
NS_ASSUME_NONNULL_END
#import "FlutterHomeViewController.h"
#import "SomeOtherNativeViewController.h"
@interface FlutterHomeViewController ()
@end
@implementation FlutterHomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"samples.chenhang/navigation" binaryMessenger:self];
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// Note: this method is invoked on the UI thread.
if([call.method isEqualToString:@"openNativePage"]) {
SomeOtherNativeViewController *vc = [[SomeOtherNativeViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
result(@0);
}
else if([call.method isEqualToString:@"closeFlutterPage"]) {
[self.navigationController popViewControllerAnimated:YES];
result(@0);
}
else {
result(FlutterMethodNotImplemented);
}
}];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self navigationController] setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[self navigationController] setNavigationBarHidden:NO animated:animated];
}
@end
#import "SomeOtherNativeViewController.h"
#import "FlutterHomeViewController.h"
@interface SomeOtherNativeViewController ()
@end
@implementation SomeOtherNativeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor greenColor];
self.title = @"Other Native Page";
[self.view addSubview:({
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, self.view.frame.size.width, 30)];
label.text = @"Some Native ViewController";
label.textAlignment = NSTextAlignmentCenter;
label;
})];
[self.view addSubview:({
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(50, 250, 120, 30);
button.adjustsImageWhenHighlighted = NO;
button.adjustsImageWhenDisabled = NO;
button.showsTouchWhenHighlighted = YES;
[button setTitle:@"Open Flutter" forState:UIControlStateNormal];
[button addTarget:self action:@selector(openFlutterVC) forControlEvents:UIControlEventTouchUpInside];
button;
})];
// Do any additional setup after loading the view.
}
- (void)openFlutterVC {
FlutterHomeViewController *vc = [[FlutterHomeViewController alloc]init];
[vc setInitialRoute:@"defaultPage"];
[self.navigationController pushViewController:vc animated:YES];
}
@end
Android 端代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
Intent intent = new Intent(MainActivity.this, FlutterPageActivity.class);
startActivity(intent);
}
});
}
}
public class FlutterPageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
FlutterView flutterView = Flutter.createView(this,getLifecycle(),"defaultRoute");
//注册方法通道
new MethodChannel(flutterView, "samples.chenhang/navigation").setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
//如果方法名为打开新页面
if(call.method.equals("openNativePage")) {
//新建Intent,打开原生页面
Intent intent = new Intent(FlutterPageActivity.this, SomeNativePageActivity.class);
startActivity(intent);
result.success(0);
}
//如果方法名为关闭Flutter页面
else if(call.method.equals("closeFlutterPage")) {
//销毁自身(Flutter容器)
finish();
result.success(0);
}
else {
//方法未实现
result.notImplemented();
}
}
});
setContentView(flutterView);
}
}
public class SomeNativePageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_some_native);
android.support.v7.app.ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
Button btn = findViewById(R.id.buttonx);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
Intent intent = new Intent(SomeNativePageActivity.this, FlutterPageActivity.class);
startActivity(intent);
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
this.finish(); // back button
return true;
}
return super.onOptionsItemSelected(item);
}
}
网友评论