【问题标题】:What is the right way to add a sized PageView in Flutter?在 Flutter 中添加大小的 PageView 的正确方法是什么?
【发布时间】:2018-08-25 11:28:04
【问题描述】:

我尝试添加一个不会填满整个屏幕的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 位置错误。可以看到画出来的线不是我触摸屏幕的地方(透明气泡)。

我该如何解决这个问题?我必须自己计算正确的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

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    您缺少的是将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

    希望有帮助!

    【讨论】:

    • 这样就解决了一半的问题。我在 RenderBox 周围有一个填充,它必须包含在计算中。如何在不交出填充物的情况下到达填充物?
    • 您会收到一个OffsetPaintingContext,它告诉您填充数据。在绘图期间将该偏移量添加到路径中的点,或者在将点添加到路径时将其添加到点。
    • 我已编辑我的答案以包含您的代码。希望有帮助!如果它回答了您的问题,请接受答案。
    猜你喜欢
    • 2013-10-04
    • 2016-11-19
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 2011-12-31
    • 2023-01-19
    • 2021-10-22
    相关资源
    最近更新 更多