Flutter/Native混合工程頁面跳轉

這篇文章介紹Flutter頁面的入棧出棧方式拔恰、Flutter頁面和Native頁面互相跳轉的方法,以及混合頁面棧的管理方案思考。

1. Flutter頁面之間的跳轉

在不同的頁面之間跳轉,在Android里對應的是Activity(Fragment)跳轉,iOS里對應的是ViewController的跳轉眶诈,在Flutter里,每個頁面都是Widget瓜饥,跳轉的過程就是Widget的入棧和出棧過程逝撬。跳轉用到的類是Navigator

例子:

  1. 在一個頁面(比如StatelessWidget)中跳轉到SecondScreen
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondScreen()),
  );

push的第二個參數是Route乓土,可以自己實現宪潮,也可以直接用已經幫你實現了兩個平臺的跳轉動畫的MaterialPageRoute

  1. SecondScreen中回到原來的頁面趣苏,用Navigator.pop出棧:
// Within the SecondScreen Widget
onPressed: () {
  Navigator.pop(context);
}

觀察pop的方法簽名狡相,第二個參數可以攜帶參數返回上一個頁面。

Navigator.pop(context,"攜帶參數");

前一個頁面通過push方法的返回值來接收參數食磕,返回值是一個Future<T>尽棕。類似Android的startActivityForResult

Navigator的其他push/pop方法:

  1. pop 普通的退棧
  2. popAndPushNamed 退棧然后入棧一個指定name的頁面
  3. popUntil 重復調用pop直到predicate返回true
  4. push 普通的疊加棧
  5. pushAndRemoveUntil 跳轉彬伦,然后清棧(相當于Android的)
  6. pushNamed 跳轉到指定的routeName的widget

對于6滔悉,可以在MaterialApp里配置路由

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
      routes: {
        "route1": (BuildContext context) => new SecondPage(),
      },
    );
  }
}

2. Flutter頁面跳轉Native頁面

Flutter跳Native頁面利用的是MethodChannell。也就是先發(fā)一個「信號」給Native客戶端单绑,客戶端收到信號后打開Native的頁面氧敢。

method channe

a. 跳轉到一個新的頁面

  1. MethodCallHandler回調函數中打開新的Native Activity,這樣的Activity是全屏的询张,跳轉方式遵循原生的頁面跳轉:
public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "samples.flutter.io/battery";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        FlutterMain.startInitialization(this);

        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);

        new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
                new MethodChannel.MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
                        //打開新的Activity
                        startActivity(new Intent(MainActivity.this, FloatingActivity.class));
                    }
                });
    }

iOS的實現也類似,通過MethodChannel(flutterView, CHANNEL).setMethodCallHandler來回調Native的方法浙炼,可以參考:
https://flutter.io/platform-channels/

b. 疊加到現有的View

對于安卓來說份氧,可以attach到現有的VIew:

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "samples.flutter.io/battery";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        FlutterMain.startInitialization(this);

        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);

        new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
                new MethodChannel.MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
                        //add到現有的view
                        FrameLayout v = findViewById(android.R.id.content);
                        View linearLayout = new LinearLayout(MainActivity.this);
                        linearLayout.setBackgroundColor(0xff0000ff);
                        ViewGroup.MarginLayoutParams marginLayoutParams = new ViewGroup.MarginLayoutParams(400, 400);
                        marginLayoutParams.setMargins(400, 400, 0, 0);
                        linearLayout.setLayoutParams(marginLayoutParams);
                        v.addView(linearLayout);
                    }
                });
    }

疊加了藍色塊

原理是這樣的,通過findViewById(android.R.id.content)獲取到framelayout弯屈,圖中綠色的那一層蜗帜。
其實,Flutter的View是一個SurfaceView资厉,也是那個綠色的View的child厅缺。
View的層級

注意,在已有App中繼承FlutterActivity的時候,要先在super.onCreate()之前調用下面的代碼來初始化Flutter湘捎。

        FlutterMain.startInitialization(this);

3. Native頁面跳Flutter頁面

這一部分可以參考官方文檔诀豁。
創(chuàng)建一個FlutterView,然后利用addContentView添加到當前頁面的layout中窥妇。

fab.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    View flutterView = Flutter.createView(
      MainActivity.this,
      getLifecycle(),
      "route1"
    );
    FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(600, 800);
    layout.leftMargin = 100;
    layout.topMargin = 200;
    addContentView(flutterView, layout);
  }
});

或者舷胜,使用FlutterFragment,在指定的container中啟動Flutter頁面活翩。

iOS在FlutterViewController中添加一個native的UIButton作為subView:

- (void)viewDidLoad {
  [super viewDidLoad];
  UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
  [button addTarget:self
             action:@selector(handleButtonAction)
   forControlEvents:UIControlEventTouchUpInside];
  [button setTitle:@"Press me" forState:UIControlStateNormal];
  [button setBackgroundColor:[UIColor blueColor]];
  button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
  [self.view addSubview:button];
}

- (void)handleButtonAction {
  FlutterViewController* flutterViewController = [[FlutterViewController alloc] init];
  [self presentViewController:flutterViewController animated:false completion:nil];
}

TODO 在Flutter/Native混合App里管理UI棧

后續(xù)要做的事是寫出一個混合App里管理UI棧的框架烹骨。
初步的思考是,在MaterialApp中定義的route可以作為路由材泄,同時通過獲取并保存Flutter頁面history的方式(參考List<Route<dynamic>> navHistory = navState.history;)維護Flutter頁面棧沮焕。打開原生頁面使用MethodChannel(Plugin),Android拉宗,iOS兩端各自維護峦树;
如果需要再次跳轉Flutter頁面,通過獲取GlobalKey中保存的history的方式恢復Flutter頁面棧簿废。


延伸閱讀:
https://zhuanlan.zhihu.com/p/42273996
https://www.aliyun.com/jiaocheng/21966.html
http://www.reibang.com/p/e9ce78a01a93?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
https://flutter.io/cookbook/navigation/navigation-basics/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末空入,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子族檬,更是在濱河造成了極大的恐慌歪赢,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件单料,死亡現場離奇詭異埋凯,居然都是意外死亡,警方通過查閱死者的電腦和手機扫尖,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門白对,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人换怖,你說我怎么就攤上這事甩恼。” “怎么了沉颂?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵条摸,是天一觀的道長。 經常有香客問我铸屉,道長吃嘿,這世上最難降的妖魔是什么眉菱? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任够挂,我火速辦了婚禮荐虐,結果婚禮上踏枣,老公的妹妹穿的比我還像新娘。我一直安慰自己钙蒙,他們只是感情好茵瀑,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仪搔,像睡著了一般瘾婿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烤咧,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天偏陪,我揣著相機與錄音,去河邊找鬼煮嫌。 笑死笛谦,一個胖子當著我的面吹牛,可吹牛的內容都是我干的昌阿。 我是一名探鬼主播饥脑,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼懦冰!你這毒婦竟也來了灶轰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤刷钢,失蹤者是張志新(化名)和其女友劉穎笋颤,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體内地,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡伴澄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了阱缓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片非凌。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荆针,靈堂內的尸體忽然破棺而出敞嗡,到底是詐尸還是另有隱情,我是刑警寧澤航背,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布秸妥,位于F島的核電站,受9級特大地震影響沃粗,放射性物質發(fā)生泄漏。R本人自食惡果不足惜键畴,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一最盅、第九天 我趴在偏房一處隱蔽的房頂上張望突雪。 院中可真熱鬧,春花似錦涡贱、人聲如沸咏删。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽督函。三九已至,卻和暖如春激挪,著一層夾襖步出監(jiān)牢的瞬間辰狡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工垄分, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宛篇,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓薄湿,卻偏偏與公主長得像叫倍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子豺瘤,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容

  • 用兩張圖告訴你吆倦,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,749評論 2 59
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,310評論 25 707
  • 原文:ReactNative頁面跳轉Navigator ReactNative頁面跳轉Navigator Navi...
    難卻卻閱讀 2,833評論 0 1
  • 你也想要一個唐晶那樣的閨蜜嗎? 最近瞻赶,《我的前半生》大熱赛糟,隨著劇情的推進,里面的每個角色都或多或少的被罵了砸逊。當然璧南,...
    Una月亮閱讀 252評論 0 0
  • 1. 我家的廚房里司倚,最不經常用的鍋就是電壓力鍋了,已然成了一個“雞肋”篓像,棄之可惜动知、用之無用。開始買的時候员辩,是想著可...
    梁涵閱讀 541評論 0 1