мультискролл flutter
Как сделать чтобы было видно сразу 2 скрола?

Scrollbar(
isAlwaysShown: true,
controller: controller,
child: SingleChildScrollView(
controller: controller,
scrollDirection: Axis.horizontal,
child: Column(
children: [
Container(
width: 3000,
height: 56,
color: Colors.red,
child: Text("wewe"),
),
Expanded(
child: Scrollbar(
controller: controller1,
isAlwaysShown: true,
child: SingleChildScrollView(
controller: controller1,
scrollDirection: Axis.vertical,
child: Container(
width: 3000,
height: 2000,
color: Colors.blue,
child: Text("1edds"),
),
),
),
)
Ответы (1 шт):
Со скроллом в Flutter много проблем и issues по Scrollbar. К примеру:
https://github.com/flutter/flutter/issues/36474
https://github.com/flutter/flutter/issues/73697
и другие.
Если переключиться на flutter channel dev, то некоторые из проблем уже решены. По Вашему примеру, только увеличен размер для наглядности:
Сами элементы не пропадают, но уезжают. Все же хотелось бы, чтобы оба было видно и при скролле. А если глянуть, там ещё пачка issue касательно скроллбаров.
Так что легче написать свой костыль. Пример по Вашему коду:
Код:
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
@override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
ScrollController _horizontalController = ScrollController();
ScrollController _verticalController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
SingleChildScrollView(
controller: _horizontalController,
scrollDirection: Axis.horizontal,
child: Column(
children: [
Container(
width: 3000,
height: 56,
color: Colors.red,
child: Text(
List<String>.generate(10, (index) => 'Header example')
.toString()),
),
Expanded(
child: SingleChildScrollView(
controller: _verticalController,
scrollDirection: Axis.vertical,
child: Container(
width: 3000,
height: 2000,
color: Colors.blue,
// MARK: - Для наглядности примера добавил
child: Text(List<String>.generate(
100,
(index) =>
'${List<String>.generate(10, (index) => 'Header example').toString()}\n')
.toString()),
),
),
),
],
),
),
Positioned(
top: 56,
right: 0,
bottom: 0,
child: OurCustomScrollbar(
axis: Axis.vertical,
controller: _verticalController,
),
)
],
),
),
);
}
}
class OurCustomScrollbar extends StatefulWidget {
// MARK: - Зачатки конфигурации направления, нужно дописать
final Axis axis;
final ScrollController controller;
OurCustomScrollbar({
@required this.axis,
@required this.controller,
});
@override
_OurCustomScrollbarState createState() => new _OurCustomScrollbarState();
}
class _OurCustomScrollbarState extends State<OurCustomScrollbar> {
double _barOffset;
bool _isDragInProcess;
// MARK: - Размеры хардкод для примера, для красоты лучше высчитывать из размеров вьюшки и контента.
double _barHeight = 50;
double _barWidth = 20;
@override
void initState() {
super.initState();
widget.controller.addListener(() {
// MARK: - Я слежу за тобой, controller ;)
_onChangePosition(widget.controller);
});
_barOffset = 0;
_isDragInProcess = false;
}
double get barMaxScrollExtent => context.size.height - _barHeight;
double get barMinScrollExtent => 0;
double get controllerMaxScrollExtent =>
widget.controller.position.maxScrollExtent;
double get controllerMinScrollExtent =>
widget.controller.position.minScrollExtent;
void _onVerticalDragUpdate(DragUpdateDetails details) {
setState(() {
_barOffset += details.delta.dy;
if (_barOffset < barMinScrollExtent) {
_barOffset = barMinScrollExtent;
}
if (_barOffset > barMaxScrollExtent) {
_barOffset = barMaxScrollExtent;
}
double translatedControllerDelta =
details.delta.dy * controllerMaxScrollExtent / barMaxScrollExtent;
double controllerOffset =
widget.controller.position.pixels + translatedControllerDelta;
if (controllerOffset < widget.controller.position.minScrollExtent) {
controllerOffset = widget.controller.position.minScrollExtent;
}
if (controllerOffset > controllerMaxScrollExtent) {
controllerOffset = controllerMaxScrollExtent;
}
widget.controller.jumpTo(controllerOffset);
});
}
_onChangePosition(ScrollController controller) {
if (_isDragInProcess) {
return;
}
setState(() {
_barOffset =
controller.offset * barMaxScrollExtent / controllerMaxScrollExtent;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onVerticalDragStart: (e) {
_isDragInProcess = true;
},
onVerticalDragUpdate: _onVerticalDragUpdate,
onVerticalDragEnd: (e) {
_isDragInProcess = false;
},
child: Container(
alignment: Alignment.topRight,
margin: EdgeInsets.only(top: _barOffset),
child: Container(
height: _barHeight,
width: _barWidth,
color: Colors.black,
),
),
);
}
}
Ну и странно, что не сделают стандартный "независимый" скроллбар, который легко можно было бы прилепить куда угодно.

