Flutter:如何创建在左侧和底部具有固定部分的双向滚动ListView

问题描述 投票:0回答:1

如何在Flutter中制作滚动视图,在其中固定屏幕的左下部和底部(轴),然后可以将屏幕的其余部分水平向右滚动或垂直向上滚动。 (想象一下用两个轴滚动图形..参见图片)

2D Graph

flutter graph scroll drawing bidirectional
1个回答
0
投票

非常有趣的问题。浏览完文档后,我找不到适合这种情况的小部件。因此,我决定在pub.dev上搜索一些可以实现此目标的插件。

找到它:https://pub.dev/packages/bidirectional_scroll_view

该插件在两个轴上都可以很好地滚动内容,但是要获得所需的内容(“左侧和底部的固定部分”),您必须相应地构建页面。我决定使用Stack和Align小部件,如下所示:

See the full code on a working DartPad: https://dartpad.dev/10573c0e9bfa7f1f8212326b795d8628

或者看看下面的代码(不要忘记在项目中包含bidirectional_scroll_view):

void main() {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  BidirectionalScrollViewPlugin _plugin;
  double fixedAxisSpace = 100.0;
  double biDirectContentWidth = 4096.0;
  double biDirectContentHeight = 4096.0;

  @override
  void initState() {
    super.initState();
      _plugin = new BidirectionalScrollViewPlugin(
      child: _buildWidgets(),
      velocityFactor: 0.0, 
    );
  }

  void _snapToZeroZero(BuildContext context){
    double yOffset = biDirectContentHeight + fixedAxisSpace - context.size.height;
    _plugin.offset = new Offset(0, yOffset);
  }

  @override
  Widget build(BuildContext context) { 
    final btnSnapToZeroZero = Padding(
      padding: EdgeInsets.all(10.0),
        child:FlatButton(
          color: Colors.black,
          shape: RoundedRectangleBorder(
            borderRadius: new BorderRadius.circular(12.0),
          ),
          onPressed: () { _snapToZeroZero(context); },
          child: Text(
            "Snap to 0.0",
            textAlign: TextAlign.center,
            style: TextStyle(color: Colors.white),
            ),
       )
      );

    return new MaterialApp(
      debugShowCheckedModeBanner: false,
      home: new Scaffold(
        body: Stack(
          children: <Widget>[
             _plugin, // BidirectionalScrollViewPlugin, goes 1st because we want it to sit on the bottom layer
             Align( // Y Axis goes over _plugin, it is aligned to topLeft
              alignment: Alignment.topLeft,
              child: Column(
                children: <Widget> [
                  Expanded( 
                    child: Container(
                      width: fixedAxisSpace,
                      decoration: BoxDecoration(
                        color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
                        border: Border(
                          right: BorderSide(width: 1.0, color: Colors.black),
                        ),
                      ),
                      child: Center(child: VerticalTextWidget("FIXED _ Y AXIS", 22))
                    ),
                  ),
                  SizedBox(height: fixedAxisSpace),
                ]
              ),
             ),
             Align( // X Axis goes over _plugin and Y Axis, it is aligned to bottomLeft
              alignment: Alignment.bottomLeft,
              child: Row(
                children: <Widget> [
                  SizedBox(width: fixedAxisSpace),
                  Expanded( 
                    child: Container(
                      height: fixedAxisSpace,
                      decoration: BoxDecoration(
                        color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
                        border: Border(
                          top: BorderSide(width: 1.0, color: Colors.black),
                        ),
                      ),
                      child: Center(child: Text("FIXED | X AXIS", style: TextStyle(fontSize: 22)))
                    ),
                  ),
                ]
              ),
             ),

             Align( // this little square is optional, I use it to put a handy little button over everything else at the bottom left corner.
              alignment: Alignment.bottomLeft,
                child: Container(
                  color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
                  height: fixedAxisSpace,
                  width: fixedAxisSpace,
                  child: btnSnapToZeroZero
              ),
             ),

          ],
        )
     )
    );
  }

  // put your large bidirectional content here
  Widget _buildWidgets() {
    return new Padding(
      padding: EdgeInsets.fromLTRB(100, 0, 0, 100),
      child: SizedBox(
        width: biDirectContentWidth,
        height: biDirectContentHeight,
        child: Image.network(
          'https://i.stack.imgur.com/j1ItQ.png?s=328&g=1',
          repeat: ImageRepeat.repeat,
          alignment: Alignment.bottomLeft
        ),
      )
    );
  }
}

VerticalTextWidget:

class VerticalTextWidget extends StatelessWidget {
  final String text;
  final double size;

  const VerticalTextWidget(this.text, this.size);

  @override
  Widget build(BuildContext context) {
    return Wrap(
      direction: Axis.vertical,
      alignment: WrapAlignment.center,
      children: text.split("").map((string) => Text(string, style: TextStyle(fontSize: size))).toList(),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.