在 Flutter 中添加大小的 PageView 的正确方法是什么?
What is the right way to add a sized PageView in Flutter?
我尝试添加一个 PageView
,它没有填满整个屏幕。
为此,我将 PageView 放在 Column
:
中
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Column(
children: <Widget>[
new SizedBox(height: 100.0, child: new Center(child: new Text("sticky header"))),
new Expanded(
child: new PageView(
children: <Widget>[
new Container(
color: Colors.red,
child: new Padding(
padding: const EdgeInsets.all(50.0),
child: new _Painter(),
),
),
new Container(
color: Colors.green,
child: new Padding(
padding: const EdgeInsets.all(50.0),
child: new _Painter(),
),
),
],
),
),
],
),
);
}
}
到目前为止这有效。
每个 PageView
都有一个 _Painter
which has a RenderBox
可以画东西。
我的问题来了:我使用 handleEvent
方法检测拖动事件,但 y
位置错误。可以看到画出来的线不是我触摸屏幕的地方(透明气泡)。
我该如何解决这个问题?我必须自己计算正确的 y
位置吗?
您可以找到 full source here.
更新
globalToLocal
中途修复了问题,但我仍然必须在计算中包括填充。有没有办法获取小部件的填充?
void _handleDragUpdate(DragUpdateDetails details) {
final pos = globalToLocal(details.globalPosition);
_currentPath?.lineTo(pos.dx + 50.0, pos.dy + 50.0);
markNeedsPaint();
}
奖励积分
当我左右拖动 PageView
时,我的 _PainterRenderBox
忘记了绘制的线条。记住这些台词的最佳位置在哪里?将它们存储在 _Painter
或 _MyHomePageState
?
中
您缺少的是将 globalPosition
相对于 RenderBox
转换为 localPosition
。你可以这样实现
// onDragUpdate with the Painting Context
RenderBox referenceBox = context.findRenderObject();
Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
// then use the localPosition to draw
您的用例的用法示例,如 here:
class _PainterRenderBox extends RenderBox {
final _lines = new List<Path>();
PanGestureRecognizer _drag;
Path _currentPath;
// variable to store padding
Offset padding;
_PainterRenderBox() {
final GestureArenaTeam team = new GestureArenaTeam();
_drag = new PanGestureRecognizer()
..team = team
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd;
}
@override
bool get sizedByParent => true;
@override
bool hitTestSelf(Offset position) => true;
@override
handleEvent(PointerEvent event, BoxHitTestEntry entry) {
assert(debugHandleEvent(event, entry));
if (event is PointerDownEvent) {
_drag.addPointer(event);
}
}
@override
paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
// update padding
padding = offset;
final Paint paintBorder = new Paint()
..strokeWidth = 1.0
..style = PaintingStyle.stroke
..color = Colors.white.withAlpha(128);
canvas.drawRect(offset & size, paintBorder);
final Paint paintPath = new Paint()
..strokeWidth = 5.0
..style = PaintingStyle.stroke
..color = Colors.white;
_lines.forEach((path) {
canvas.drawPath(path, paintPath);
});
}
// check if the point lies inside drawable area
bool _canDraw(Offset offset){
return (padding & size).contains(offset);
}
void _handleDragStart(DragStartDetails details) {
_currentPath = new Path();
Offset point = globalToLocal(details.globalPosition); // convert globalPosition to localPosition
point = padding + point; // add the padding to localPosition if any
// check if point lies inside drawable area and then markNeedsPaint
if(_canDraw(point)){
_currentPath?.moveTo(point.dx, point.dy);
_lines.add(_currentPath);
markNeedsPaint();
}
}
void _handleDragUpdate(DragUpdateDetails details) {
Offset point = globalToLocal(details.globalPosition); // convert globalPosition to localPosition
point = padding + point; // add the padding to localPosition if any
// check if point lies inside drawable area and then markNeedsPaint
if(_canDraw(point)){
_currentPath?.lineTo(point.dx, point.dy);
markNeedsPaint();
}
}
void _handleDragEnd(DragEndDetails details) {
_currentPath = null;
markNeedsPaint();
}
}
有一个类似用例的问题允许用户在屏幕上签名。希望这可以帮助您了解如何跟踪路径。你可以看看.
希望对您有所帮助!
我尝试添加一个 PageView
,它没有填满整个屏幕。
为此,我将 PageView 放在 Column
:
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Column(
children: <Widget>[
new SizedBox(height: 100.0, child: new Center(child: new Text("sticky header"))),
new Expanded(
child: new PageView(
children: <Widget>[
new Container(
color: Colors.red,
child: new Padding(
padding: const EdgeInsets.all(50.0),
child: new _Painter(),
),
),
new Container(
color: Colors.green,
child: new Padding(
padding: const EdgeInsets.all(50.0),
child: new _Painter(),
),
),
],
),
),
],
),
);
}
}
到目前为止这有效。
每个 PageView
都有一个 _Painter
which has a RenderBox
可以画东西。
我的问题来了:我使用 handleEvent
方法检测拖动事件,但 y
位置错误。可以看到画出来的线不是我触摸屏幕的地方(透明气泡)。
我该如何解决这个问题?我必须自己计算正确的 y
位置吗?
您可以找到 full source here.
更新
globalToLocal
中途修复了问题,但我仍然必须在计算中包括填充。有没有办法获取小部件的填充?
void _handleDragUpdate(DragUpdateDetails details) {
final pos = globalToLocal(details.globalPosition);
_currentPath?.lineTo(pos.dx + 50.0, pos.dy + 50.0);
markNeedsPaint();
}
奖励积分
当我左右拖动 PageView
时,我的 _PainterRenderBox
忘记了绘制的线条。记住这些台词的最佳位置在哪里?将它们存储在 _Painter
或 _MyHomePageState
?
您缺少的是将 globalPosition
相对于 RenderBox
转换为 localPosition
。你可以这样实现
// onDragUpdate with the Painting Context
RenderBox referenceBox = context.findRenderObject();
Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
// then use the localPosition to draw
您的用例的用法示例,如 here:
class _PainterRenderBox extends RenderBox {
final _lines = new List<Path>();
PanGestureRecognizer _drag;
Path _currentPath;
// variable to store padding
Offset padding;
_PainterRenderBox() {
final GestureArenaTeam team = new GestureArenaTeam();
_drag = new PanGestureRecognizer()
..team = team
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd;
}
@override
bool get sizedByParent => true;
@override
bool hitTestSelf(Offset position) => true;
@override
handleEvent(PointerEvent event, BoxHitTestEntry entry) {
assert(debugHandleEvent(event, entry));
if (event is PointerDownEvent) {
_drag.addPointer(event);
}
}
@override
paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
// update padding
padding = offset;
final Paint paintBorder = new Paint()
..strokeWidth = 1.0
..style = PaintingStyle.stroke
..color = Colors.white.withAlpha(128);
canvas.drawRect(offset & size, paintBorder);
final Paint paintPath = new Paint()
..strokeWidth = 5.0
..style = PaintingStyle.stroke
..color = Colors.white;
_lines.forEach((path) {
canvas.drawPath(path, paintPath);
});
}
// check if the point lies inside drawable area
bool _canDraw(Offset offset){
return (padding & size).contains(offset);
}
void _handleDragStart(DragStartDetails details) {
_currentPath = new Path();
Offset point = globalToLocal(details.globalPosition); // convert globalPosition to localPosition
point = padding + point; // add the padding to localPosition if any
// check if point lies inside drawable area and then markNeedsPaint
if(_canDraw(point)){
_currentPath?.moveTo(point.dx, point.dy);
_lines.add(_currentPath);
markNeedsPaint();
}
}
void _handleDragUpdate(DragUpdateDetails details) {
Offset point = globalToLocal(details.globalPosition); // convert globalPosition to localPosition
point = padding + point; // add the padding to localPosition if any
// check if point lies inside drawable area and then markNeedsPaint
if(_canDraw(point)){
_currentPath?.lineTo(point.dx, point.dy);
markNeedsPaint();
}
}
void _handleDragEnd(DragEndDetails details) {
_currentPath = null;
markNeedsPaint();
}
}
有一个类似用例的问题允许用户在屏幕上签名。希望这可以帮助您了解如何跟踪路径。你可以看看
希望对您有所帮助!