I have used your code to reproduce the issue. If I understood your needs right, here is the fix:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: SafeArea(
child: ScrollSizingWidget(),
),
),
),
);
}
class ScrollSizingWidget extends StatefulWidget {
const ScrollSizingWidget({Key? key}) : super(key: key);
@override
State<ScrollSizingWidget> createState() => _ScrollSizingWidgetState();
}
class _ScrollSizingWidgetState extends State<ScrollSizingWidget> {
late final ScrollController _horizontal;
late final ScrollController _vertical;
@override
void initState() {
super.initState();
_horizontal = ScrollController();
_vertical = ScrollController();
}
@override
void dispose() {
_horizontal.dispose();
_vertical.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scrollbar(
controller: _horizontal,
scrollbarOrientation: ScrollbarOrientation.bottom,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.zero,
child: SizedBox(
height: 500,
width: 1000,
child: Scrollbar(
controller: _vertical,
scrollbarOrientation: ScrollbarOrientation.right,
child: SingleChildScrollView(
controller: _vertical,
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
height: 200,
width: 1000,
color: Colors.red,
),
Container(
height: 1000,
width: 1000,
color: Colors.orange,
),
],
),
),
),
),
),
);
}
Firstly, you say that your main SingleChildScrollView
scrolls horizontally, but your widget tree starts with a Scrollbar
which uses a vertical ScrollController
. So you should create your widgets step by step, as you explained.
Also, since you want to see the vertical Scrollbar
through your main SingleChildScrollView
, I wrapped both(red and orange Containers) with Scrollbar
and SingleChildScrollView
to have the effect you want. Furthermore, I connected these Scrollbar
and SingleChildScrollView
with the same horizontal ScrollController
. So now, not only the orange Container
, but both are scrollable and stick together, not independent.
If you don't want the red Container
being scrolled along with the orange Container
, check this:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: SafeArea(
child: ScrollSizingWidget(),
),
),
),
);
}
class ScrollSizingWidget extends StatefulWidget {
const ScrollSizingWidget({Key? key}) : super(key: key);
@override
State<ScrollSizingWidget> createState() => _ScrollSizingWidgetState();
}
class _ScrollSizingWidgetState extends State<ScrollSizingWidget> {
late final ScrollController _horizontal;
late final ScrollController _vertical;
@override
void initState() {
super.initState();
_horizontal = ScrollController();
_vertical = ScrollController();
}
@override
void dispose() {
_horizontal.dispose();
_vertical.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scrollbar(
controller: _horizontal,
scrollbarOrientation: ScrollbarOrientation.bottom,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.zero,
child: SizedBox(
height: 500,
width: 1000,
child: Column(
children: [
Container(
height: 200,
width: 1000,
color: Colors.red,
),
Expanded(
child: Scrollbar(
controller: _vertical,
scrollbarOrientation: ScrollbarOrientation.right,
child: SingleChildScrollView(
controller: _vertical,
scrollDirection: Axis.vertical,
child: Container(
height: 700,
width: 1000,
color: Colors.orange,
),
),
),
),
],
),
),
),
);
}
Lastly, Scrollbar
's position in iOS is a bit buggy because of the notch, etc. So I wrapped your ScrollSizingWidget
with SafeArea
to fix the issue in iOS.
If these answers are not what you expect, please don't hesitate to write.
Edit: After your explanations in the comments below, I have created another fix. I believe CustomScrollView
and Sliver
widgets are fits here perfectly. The red Container
, which you want to stay in its position, should be wrapped with the SliverAppBar
. Lastly, the orange Container
, which you want to be able to scroll vertically, could be wrapped with SliverFixedExtentList
. Please check the code below:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: SafeArea(
child: ScrollSizingWidget(),
),
),
),
);
}
class ScrollSizingWidget extends StatefulWidget {
const ScrollSizingWidget({Key? key}) : super(key: key);
@override
State<ScrollSizingWidget> createState() => _ScrollSizingWidgetState();
}
class _ScrollSizingWidgetState extends State<ScrollSizingWidget> {
late final ScrollController _horizontal;
late final ScrollController _vertical;
@override
void initState() {
super.initState();
_horizontal = ScrollController();
_vertical = ScrollController();
}
@override
void dispose() {
_horizontal.dispose();
_vertical.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scrollbar(
controller: _horizontal,
scrollbarOrientation: ScrollbarOrientation.bottom,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.zero,
child: SizedBox(
height: 500,
width: 1000,
child: Scrollbar(
controller: _vertical,
scrollbarOrientation: ScrollbarOrientation.right,
child: CustomScrollView(
controller: _vertical,
scrollDirection: Axis.vertical,
slivers: [
SliverAppBar(
toolbarHeight: 200.0,
collapsedHeight: 200.0,
pinned: true,
stretch: true,
elevation: 0.0,
backgroundColor: Colors.transparent,
title: Container(
height: 200.0,
color: Colors.red,
),
titleSpacing: 0,
),
SliverFixedExtentList(
itemExtent: 1200.0,
delegate: SliverChildBuilderDelegate(
(_, __) => Container(
color: Colors.orange,
),
childCount: 1,
),
),
],
),
),
),
),
);
}