在Flutter中替换像碎片一样的小部件

时间:2018-06-01 09:24:31

标签: android dart flutter

我是Flutter的新手。

我有一个带有2个子小部件的应用程序(Android中有2个片段),当我点击WidgetA中的下一个按钮时,我想将该小部件替换(或推送)到WidgetChildA中,就像在Android中推送(或替换)片段一样。但不是那样,我在Flutter中得到了一个像普通屏幕一样的全屏小部件。

这是我的代码:

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")],
    )));
  }
}

截图:

Home page
enter image description here

After clicked
enter image description here

4 个答案:

答案 0 :(得分:2)

好吧,我将使用谷歌在底部导航栏上执行此操作的方式进行此操作,但我认为这不是最有效的方法,但是它可以正常工作

  class MainFabContainer extends StatefulWidget {

    MainFabContainer({
      Key key,
    }) : super(key: key);

    @override
    State<StatefulWidget> createState() {
      return MainFabContainerState();
    }

  }

  class MainFabContainerState extends State<MainFabContainer> {
    String title = "Title";
    int _currentIndex = 0;
    final List<int> _backstack = [0];

    @override
    Widget build(BuildContext context) {
      //each fragment is just a widget which we pass the navigate function
      List<Widget> _fragments =[Fragment1(navigate: navigateTo),Fragment2(navigate: navigateTo,),Fragment3(navigate: navigateTo,)];
      //will pop scope catches the back button presses
      return WillPopScope(
        onWillPop: () {
          customPop(context);
        },
        child: Scaffold(
          drawer: drawer(),
          appBar: AppBar(
            title: Text(title),
          ),
          body: Column(
            children: <Widget>[
              Expanded(
                child: _fragments[_currentIndex],
              ),
            ],
          ),
        ),
      );
    }


    void navigateTo(int index) {
      _backstack.add(index);
      setState(() {
        _currentIndex = index;
      });
    }

    void navigateBack(int index) {
      setState(() {
        _currentIndex = index;
      });
    }

    customPop(BuildContext context) {
      if (_backstack.length - 1  > 0) {
        navigateBack(_backstack[_backstack.length - 1]);
      } else {
        _backstack.removeAt(_backstack.length - 1);
        Navigator.pop(context);
      }
    }
    //this method could be called by the navigate and navigate back methods
    _setTitle(String appBarTitle) {
      setState(() {
        title = appBarTitle;
      });
    }
  }

答案 1 :(得分:1)

我不确定你是否可以使用路由器来替换视图的一部分;但您可以有条件地更改在构建方法中呈现的窗口小部件,如下所示:

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

然后您只需要在有状态小部件中使用someCondition设置setState

setState(() => someCondition = true);

如果你想从FragmentA内部执行此操作,可以允许它将函数传递给它的构造函数:

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

但是,最好将所有这些逻辑封装在一个小部件中,这样这个逻辑就不会在父级中徘徊。您可以为FragementA创建一个StatefulWidget,它会跟踪您所处的阶段,然后在其构建方法中呈现正确的子窗口小部件,如:

build() {
  switch(stage) {
    Stages.Stage1:
      return new Stage1(
        onNext: () => setState(() => stage = Stages.Stage2);
      );
    Stages.Stage2:
      return new Stage1(
        onPrevious: () => setState(() => stage = Stages.Stage1);
      );
  }
}

答案 2 :(得分:0)

您可以简单地将MaterialApp小部件与CupertinoPageTransitionsBuilder一起用作pageTransitionTheme,例如

MaterialApp(
   theme: ThemeData(
   pageTransitionsTheme: PageTransitionsTheme(builders: {
   TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
   TargetPlatform.android: SlideRightPageTransitionsBuilder(),
   }),
   initialRoute: "fragment1",
   routes: <String, WidgetBuilder>{
      "fragment1": (BuildContext context) => Fragment1(),
      "fragment2": (BuildContext context) => Fragment2(),
   }
...
),

然后在片段1中,您只需使用以下内容即可通过幻灯片动画导航到另一个片段

Navigator.of(context).pushReplacementNamed("fragment2");

答案 3 :(得分:-1)

简单地使用SingleStatefull小部件,然后在创建状态中进行一些布尔运算,以调用不同的状态小部件来充当fragment。 例如

if(showUpload)
{
  return new _Upload(responseUpload: response); // Fragment 1
}else
{
  return  EditState(mapSaved: map,);     // Fragment 2
}