Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace widgets like fragments in Flutter

I'm new to Flutter.

I have an app with 2 sub widgets (2 fragments in Android), and when i clicked next button in WidgetA, I want to replace (or push) that widget into WidgetChildA, like push (or replace) fragments in Android. But instead of that, I got a fullscreen widget like a normal screen in Flutter.

Here is my code:

import 'package:flutter/material.dart';

class DemoFragment extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new DemoFragmentState();
  }
}

class DemoFragmentState extends State<DemoFragment> {
  @override
  Widget build(BuildContext context) {
    print(context.toString() + context.hashCode.toString());
    return new Scaffold(
      appBar: new AppBar(title: new Text("Demo fragment")),
      body: new Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          new FragmentA(),
          new FragmentB()
        ],
      ),
    );
  }
}

class FragmentA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print(context.toString() + context.hashCode.toString());
    return new Center(
      child: new Column(
        children: <Widget>[
          new Text("Fragment A"),
          new RaisedButton(
              child: new Text("next"),
              onPressed: () {
                print(context.toString() + context.hashCode.toString());
                Navigator.of(context).push(new PageRouteBuilder(
                    opaque: true,
                    transitionDuration: const Duration(milliseconds: 0),
                    pageBuilder: (BuildContext context, _, __) {
                      return new FragmentChildA();
                    }));

                /*showDialog(
                    context: context,
                    builder: (_) => new AlertDialog(
                          title: new Text("Hello world"),
                          content: new Text("this is my content"),
                        ));*/
              })
        ],
      ),
    );
  }
}

class FragmentB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print(context.toString() + context.hashCode.toString());
    return new Center(
        child: new Column(
      children: <Widget>[
        new Text("Fragment B"),
        new RaisedButton(
            child: new Text("next"),
            onPressed: () {
              print(context.toString() + context.hashCode.toString());
              Navigator.of(context).push(new PageRouteBuilder(
                  opaque: true,
                  transitionDuration: const Duration(milliseconds: 0),
                  pageBuilder: (BuildContext context, _, __) {
                    return new FragmentChildB();
                  }));
            })
      ],
    ));
  }
}

class FragmentChildA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
            child: new Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[new Text("Fragment Child A")],
    )));
  }
}

class FragmentChildB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
            child: new Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[new Text("Fragment Child B")],
    )));
  }
}

Screenshots:

Home page
enter image description here

After clicked
enter image description here

like image 616
Châu Minh Phúc Avatar asked Jun 01 '18 09:06

Châu Minh Phúc


2 Answers

Well, I found out the way to handle this case for a few months, but I just forgot to answer this question.

The solution is wrapping your Widget with a new Navigator.

You can see the video example here

And the simple demo for it here

The downside of this solution is sometimes, the keyboard is not showing as my intention.

like image 200
Châu Minh Phúc Avatar answered Sep 21 '22 07:09

Châu Minh Phúc


I'm not sure if you can use the router to replace just the part of a view; but you could conditionally change which Widget you render in the build method, like this:

children: <Widget>[
    someCondition ? new FragmentA() : new FragmentChildA(),
    new FragmentB()
],

Then you just need to set someCondition by using setState in the stateful widget:

setState(() => someCondition = true);

If you want to do this from inside FragmentA you could allow it to have the function passed into its constructor:

new FragmentA(
  onPress: setState(() => someCondition = true)
)

However, it might be better to encapsulate all of this logic inside a single widget so this logic isn't all hanging around in the parent. You could make a single StatefulWidget for FragementA which keeps track of which stage you're on, and then in its build method renders the correct child widget, something like:

build() {
  switch(stage) {
    Stages.Stage1:
      return new Stage1(
        onNext: () => setState(() => stage = Stages.Stage2);
      );
    Stages.Stage2:
      return new Stage1(
        onPrevious: () => setState(() => stage = Stages.Stage1);
      );
  }
}
like image 31
Danny Tuppeny Avatar answered Sep 17 '22 07:09

Danny Tuppeny