Search code examples
flutterlayoutflutter-layoutmaster-detail

How to Navigate in Same the Page Master Detail page Flutter


I am building a master detail based app and I want to show in splitview. Trying to understand how to push data to another page in same view but couldn't. Want to cover details data in second page. How to push data?

It could be either responsive or not. But I don't want to resolve but only using set state and fill the blank in details page

image

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          widget.title,
          style: TextStyle(color: Colors.black),
        ),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: VerticalSplitView(

          left: ListView.builder( itemCount: 12,
    itemBuilder: (context, index) {
      return Card(
        child: InkWell(
          splashColor: Colors.blue.withAlpha(30),
          onTap: () {
            //Navigator.push(context, MaterialPageRoute(builder: (context) => new yapiekle()) );
          },
          child: Container(
            child: Padding(
              padding: EdgeInsets.all(12.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                //Center Column contents vertically,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[

                  Expanded(

                    child: ListTile(
                      leading: Image.network("https://picsum.photos/200/300"),

                        title: Text("Title"),
                        subtitle: Text("Subtitle")),

                  ),
                  //Spacer(),

                ],
              ),
            ),
          ),
        ),
      );

    }
    ),

          right: Container(
            decoration: BoxDecoration(
              border: Border.all(color: Colors.black),
            ),
            child: Center(
                child: FlutterLogo(
                  size: 256,
                )),
          ),
        ),
      ),
    );
  }
}

class VerticalSplitView extends StatefulWidget {
  final Widget left;
  final Widget right;
  final double ratio;

  const VerticalSplitView(
      {Key key, @required this.left, @required this.right, this.ratio = 0.5})
      : assert(left != null),
        assert(right != null),
        assert(ratio >= 0),
        assert(ratio <= 1),
        super(key: key);

  @override
  _VerticalSplitViewState createState() => _VerticalSplitViewState();
}

class _VerticalSplitViewState extends State<VerticalSplitView> {
  final _dividerWidth = 16.0;

  //from 0-1
  double _ratio;
  double _maxWidth;

  get _width1 => _ratio * _maxWidth;

  get _width2 => (1 - _ratio) * _maxWidth;

  @override
  void initState() {
    super.initState();
    _ratio = widget.ratio;
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, BoxConstraints constraints) {
      assert(_ratio <= 1);
      assert(_ratio >= 0);
      if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
      if (_maxWidth != constraints.maxWidth) {
        _maxWidth = constraints.maxWidth - _dividerWidth;
      }

      return SizedBox(
        width: constraints.maxWidth,
        child: Row(
          children: <Widget>[
            SizedBox(
              width: _width1,
              child: widget.left,
            ),
            GestureDetector(
              behavior: HitTestBehavior.translucent,
              child: SizedBox(
                width: _dividerWidth,
                height: constraints.maxHeight,
                child: RotationTransition(
                  child: Icon(Icons.drag_handle),
                  turns: AlwaysStoppedAnimation(0.25),
                ),
              ),
              onPanUpdate: (DragUpdateDetails details) {
                setState(() {
                  _ratio += details.delta.dx / _maxWidth;
                  if (_ratio > 1)
                    _ratio = 1;
                  else if (_ratio < 0.0) _ratio = 0.0;
                });
              },
            ),
            SizedBox(
              width: _width2,
              child: widget.right,
            ),
          ],
        ),
      );
    });
  }
}

Solution

  • I assumed that you want to change the the right page by clicking on the left card widgets. I have been developed something like this. I am using IndexedStack for render on the right side of VerticalSplitView then use provider and consumer for controlling the page to display.

    First of all you need to import provider dependency in pubspec.ymal You can replace this code below for entire of main.dart.

    In main.dart you can try to replace this code. The idea is we are going to create IndexedStack that contain the Widget (Page as you prefer). Then we are going to change the index of IndexedStack by using Provider and Consumer.

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:test_indexed_stack/page_data.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) {
              var pageData = PageData();
              return pageData;
            }),
          ],
          child: MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: MyHomePage(title: 'Flutter Demo Home Page'),
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      // Set required page same as list length in left of VerticalSplitView
      List<Widget> pages = [Text('Page1'), Text('Page2'), Text('Page3'),
        Text('Page4'), Text('Page5'), Text('Page6'), Text('Page7'),
        Text('Page8'), Text('Page9'), Text('Page10'), Text('Page11'),
        Text('Page12'), ];
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(
              widget.title,
              style: TextStyle(color: Colors.black),
            ),
            backgroundColor: Colors.transparent,
            elevation: 0,
          ),
          body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: VerticalSplitView(
    
              left: ListView.builder( itemCount: 12,
                  itemBuilder: (context, index) {
                    return Card(
                      child: InkWell(
                        splashColor: Colors.blue.withAlpha(30),
                        onTap: () {
                          // Set the current page for change page on the right side.
                          Provider.of<PageData>(context, listen: false).setCurrentTab(index);
                        },
                        child: Container(
                          child: Padding(
                            padding: EdgeInsets.all(12.0),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              //Center Column contents vertically,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: <Widget>[
    
                                Expanded(
    
                                  child: ListTile(
                                      leading: Image.network("https://picsum.photos/200/300"),
    
                                      title: Text("Title"),
                                      subtitle: Text("Subtitle")),
    
                                ),
                                //Spacer(),
    
                              ],
                            ),
                          ),
                        ),
                      ),
                    );
    
                  }
              ),
    
              right: Consumer<PageData>(
                builder: (context, pageData, child) {
                  return Container(
                      decoration: BoxDecoration(
                        border: Border.all(color: Colors.black),
                      ),
                      child: IndexedStack(
                        children: pages,
                        index: pageData.currentPage,
                      )
                  );
                },
              ),
            ),
          ),
        );
      }
    }
    
    class VerticalSplitView extends StatefulWidget {
      final Widget left;
      final Widget right;
      final double ratio;
    
      const VerticalSplitView(
          {Key key, @required this.left, @required this.right, this.ratio = 0.5})
          : assert(left != null),
            assert(right != null),
            assert(ratio >= 0),
            assert(ratio <= 1),
            super(key: key);
    
      @override
      _VerticalSplitViewState createState() => _VerticalSplitViewState();
    }
    
    class _VerticalSplitViewState extends State<VerticalSplitView> {
      final _dividerWidth = 16.0;
    
      //from 0-1
      double _ratio;
      double _maxWidth;
    
      get _width1 => _ratio * _maxWidth;
    
      get _width2 => (1 - _ratio) * _maxWidth;
    
      @override
      void initState() {
        super.initState();
        _ratio = widget.ratio;
      }
    
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(builder: (context, BoxConstraints constraints) {
          assert(_ratio <= 1);
          assert(_ratio >= 0);
          if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
          if (_maxWidth != constraints.maxWidth) {
            _maxWidth = constraints.maxWidth - _dividerWidth;
          }
    
          return SizedBox(
            width: constraints.maxWidth,
            child: Row(
              children: <Widget>[
                SizedBox(
                  width: _width1,
                  child: widget.left,
                ),
                GestureDetector(
                  behavior: HitTestBehavior.translucent,
                  child: SizedBox(
                    width: _dividerWidth,
                    height: constraints.maxHeight,
                    child: RotationTransition(
                      child: Icon(Icons.drag_handle),
                      turns: AlwaysStoppedAnimation(0.25),
                    ),
                  ),
                  onPanUpdate: (DragUpdateDetails details) {
                    setState(() {
                      _ratio += details.delta.dx / _maxWidth;
                      if (_ratio > 1)
                        _ratio = 1;
                      else if (_ratio < 0.0) _ratio = 0.0;
                    });
                  },
                ),
                SizedBox(
                  width: _width2,
                  child: widget.right,
                ),
              ],
            ),
          );
        });
      }
    }
     
    

    You need to create file for Provider and replce the code below.

    import 'package:flutter/cupertino.dart';

    class PageData extends ChangeNotifier{
      PageData();
    
      int _currentPage = 0;
    
      void setCurrentTab(int index){
        this._currentPage = index;
        notifyListeners();
      }
    
      int get currentPage {
        return this._currentPage;
      }
    }
    

    Happy coding :)