非常有趣的问题。浏览完文档后,我找不到适合这种情况的小部件。因此,我决定在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(),
);
}
}