首页 文章

在Flutter中添加大小的PageView的正确方法是什么?

提问于
浏览
0

我尝试添加一个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,它有RenderBox来绘制一些东西 .

这就是我的问题:我使用handleEvent方法来检测拖动事件,但 y 位置是错误的 . 您可以看到绘制的线不是我触摸屏幕的位置(透明气泡) .

enter image description here

我怎样才能解决这个问题?我自己必须计算正确的 y 位置吗?

你可以找到full source here .

Update

globalToLocal 中途修复了问题,但我仍然需要在计算中包含填充 . 有没有办法获得小部件的填充?

void _handleDragUpdate(DragUpdateDetails details) {
  final pos = globalToLocal(details.globalPosition);
  _currentPath?.lineTo(pos.dx + 50.0, pos.dy + 50.0);
  markNeedsPaint();
}

Bonus Points

当我向左和向右拖动 PageView 时,我的 _PainterRenderBox 会忘记绘制的线条 . 记住这条线的最佳位置在哪里?将它们存储在 _Painter_MyHomePageState 中?

1 回答

  • 2

    您缺少的是将 globalPosition 转换为 localPosition ,相对于 RenderBox . 你可以实现它

    // 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();
      }
    }
    

    有一个类似用例的问题,允许用户在屏幕上签名 . 希望这可以帮助您了解如何跟踪路径 . 你可以看一下here .

    希望有所帮助!

相关问题