Flutter 颤振中的多向涡旋
我来自web开发背景,并且习惯于能够创建一个x和y溢出的元素(允许向任何方向滚动)。我正在努力用flifter实现同样的功能 通过查看文档,我发现了SingleChildScrollView,但它只允许Axis.horizontal或Axis.vertical,不能同时允许两者 因此,我尝试了以下方法:Flutter 颤振中的多向涡旋,flutter,flutter-layout,Flutter,Flutter Layout,我来自web开发背景,并且习惯于能够创建一个x和y溢出的元素(允许向任何方向滚动)。我正在努力用flifter实现同样的功能 通过查看文档,我发现了SingleChildScrollView,但它只允许Axis.horizontal或Axis.vertical,不能同时允许两者 因此,我尝试了以下方法: return SingleChildScrollView( // horizontal scroll widget scrollDirection: Axis.horizontal,
return SingleChildScrollView( // horizontal scroll widget
scrollDirection: Axis.horizontal,
child: SingleChildScrollView( // vertical scroll widget
scrollDirection: Axis.vertical,
child: ...content of the container etc...
)
);
这适用于x和y,但不允许对角滚动
有没有一种方法可以实现对角滚动,或者有没有更好的材质小部件我完全没有
谢谢我已经找到了一个解决方案,尽管它并不完美: 我创建了一个带有
Offset\u scrollOffset
的StatefulWidget,它使用一个ClipRect和一个类型为Transform的子级。变换矩阵(Matrix4.identity()…translate(\u offset.dx,\u offset.dy)
)应用于变换
gesturedector
有一个onPanUpdate回调,用于更新滚动位置<代码>\u scrollOffset+=e.delta。如果滚动位置太低或太高,只需设置滚动位置即可将其限制在小部件的边界上
动画和动画控制器用于设置投掷速度。onPanEnd提供了最后一次平移的速度,因此只需根据该速度执行一次二人之间的投掷
动画会在捕捉时停止,以便用户可以停止滚动速度
这方面的主要问题是它不能完美地模拟Android或iOS的滚动速度,尽管我正在努力使用Flatter提供的ScrollSimulation类使其工作得更好。import'package:flatter/signatures.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class FreeScrollView extends StatefulWidget {
final Widget child;
final ScrollPhysics physics;
const FreeScrollView({Key? key, this.physics = const ClampingScrollPhysics(), required this.child}) : super(key: key);
@override
State<FreeScrollView> createState() => _FreeScrollViewState();
}
class _FreeScrollViewState extends State<FreeScrollView> {
final ScrollController _verticalController = ScrollController();
final ScrollController _horizontalController = ScrollController();
final Map<Type, GestureRecognizerFactory> _gestureRecognizers = <Type, GestureRecognizerFactory>{};
@override
void initState() {
super.initState();
_gestureRecognizers[PanGestureRecognizer] = GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
() => PanGestureRecognizer(),
(instance) => instance
..onDown = _handleDragDown
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd
..onCancel = _handleDragCancel
..minFlingDistance = widget.physics.minFlingDistance
..minFlingVelocity = widget.physics.minFlingVelocity
..maxFlingVelocity = widget.physics.maxFlingVelocity
..velocityTrackerBuilder = ScrollConfiguration.of(context).velocityTrackerBuilder(context)
..dragStartBehavior = DragStartBehavior.start);
}
@override
Widget build(BuildContext context) => Stack(children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalController,
physics: widget.physics,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, // ignore: avoid_redundant_argument_values
controller: _verticalController,
physics: widget.physics,
child: widget.child)),
Positioned.fill(
child: RawGestureDetector(
gestures: _gestureRecognizers,
behavior: HitTestBehavior.opaque,
excludeFromSemantics: true,
)),
]);
Drag? _horizontalDrag;
Drag? _verticalDrag;
ScrollHoldController? _horizontalHold;
ScrollHoldController? _verticalHold;
void _handleDragDown(DragDownDetails details) {
_horizontalHold = _horizontalController.position.hold(() => _horizontalHold = null);
_verticalHold = _verticalController.position.hold(() => _verticalHold = null);
}
void _handleDragStart(DragStartDetails details) {
_horizontalDrag = _horizontalController.position.drag(details, () => _horizontalDrag = null);
_verticalDrag = _verticalController.position.drag(details, () => _verticalDrag = null);
}
void _handleDragUpdate(DragUpdateDetails details) {
_horizontalDrag?.update(DragUpdateDetails(
sourceTimeStamp: details.sourceTimeStamp,
delta: Offset(details.delta.dx, 0),
primaryDelta: details.delta.dx,
globalPosition: details.globalPosition));
_verticalDrag?.update(DragUpdateDetails(
sourceTimeStamp: details.sourceTimeStamp,
delta: Offset(0, details.delta.dy),
primaryDelta: details.delta.dy,
globalPosition: details.globalPosition));
}
void _handleDragEnd(DragEndDetails details) {
_horizontalDrag
?.end(DragEndDetails(velocity: details.velocity, primaryVelocity: details.velocity.pixelsPerSecond.dx));
_verticalDrag
?.end(DragEndDetails(velocity: details.velocity, primaryVelocity: details.velocity.pixelsPerSecond.dy));
}
void _handleDragCancel() {
_horizontalHold?.cancel();
_horizontalDrag?.cancel();
_verticalHold?.cancel();
_verticalDrag?.cancel();
}
}
进口“包装:颤振/材料.省道”;
类FreeScrollView扩展StatefulWidget{
最后一个孩子;
期末物理;
const FreeScrollView({Key?Key,this.physics=const ClampingScrollPhysics(),需要this.child}):super(Key:Key);
@凌驾
State createState()=>\u FreeScrollViewState();
}
类_FreeScrollViewState扩展状态{
最终ScrollController_verticalController=ScrollController();
最终ScrollController_horizontalController=ScrollController();
最终地图_-gesturecognizers={};
@凌驾
void initState(){
super.initState();
_手势识别器[PanGestureRecognizer]=手势识别器工厂WithHandlers(
()=>PangestureRecognitor(),
(实例)=>实例
…onDown=_handleDragDown
…onStart=\u handleDragStart
..onUpdate=\u handleDragUpdate
…onEnd=_handleDragEnd
…onCancel=\u handledrag取消
..minFlingDistance=widget.physics.minFlingDistance
…minFlingVelocity=widget.physics.minFlingVelocity
…maxFlingVelocity=widget.physics.maxFlingVelocity
..velocityTrackerBuilder=ScrollConfiguration.of(上下文)。velocityTrackerBuilder(上下文)
..dragStartBehavior=dragStartBehavior.start);
}
@凌驾
小部件构建(BuildContext上下文)=>堆栈(子项:[
SingleChildScrollView(
滚动方向:轴水平,
控制器:_水平控制器,
物理学:widget.physics,
子:SingleChildScrollView(
scrollDirection:Axis.vertical,//忽略:避免冗余参数值
控制器:_垂直控制器,
物理学:widget.physics,
child:widget.child),
定位填充(
孩子:RawGestureDetector(
手势:\手势识别器,
行为:HitTestBehavior.不透明,
excludeFromSemantics:true,
)),
]);
拖动?_水平拖动;
阻力?\垂直阻力;
ScrollHoldController?\u水平保持;
ScrollHoldController?\u垂直保持;
void_handleDragDown(拖拽下细节){
_horizontalHold=_horizontalController.position.hold(()=>_horizontalHold=null);
_verticalHold=\u verticalController.position.hold(()=>\u verticalHold=null);
}
void_handleDragStart(dragstart详细信息){
_horizontalDrag=\u horizontalController.position.drag(详细信息,()=>\u horizontalDrag=null);
_verticalDrag=\u verticalController.position.drag(详细信息,()=>\u verticalDrag=null);
}
void\u handleDragUpdate(DragUpdate详细信息){
_水平拖动?更新(拖动更新详细信息(
sourceTimeStamp:details.sourceTimeStamp,
增量:偏移量(details.delta.dx,0),
primaryDelta:details.delta.dx,
globalPosition:details.globalPosition);
_垂直拖动?更新(拖动更新详细信息(
sourceTimeStamp:details.sourceTimeStamp,
增量:偏移量(0,细节增量dy),
primaryDelta:details.delta.dy,
globalPosition:details.globalPosition);
}
void_handleDragEnd(图纸详图){
_水平阻力
?结束(DragEndDetails(速度:details.velocity,primaryVelocity:details.velocity.pixelsPerSecond.dx));
_垂直阻力
?.end(DragEndDetails(速度:details.velocity,primaryVelocity:details.velocity.pixelsPerSecond.dy));
}
void_handleDragCancel(){
_水平保持?.cancel();
_水平拖动?.cancel();
_垂直保持?.cancel();
_垂直拖动?.cancel();
}
}
InteractiveViewer是另一种选择,它支持对角拖动(而不是滚动)手势。