flutter 如何在SingleChildRenderObjectWidget中使文本表单字段具有交互性?

5jvtdoz2  于 2023-05-19  发布在  Flutter
关注(0)|答案(1)|浏览(133)

我使用SingleChildRenderObjectWidget构造了一个小部件,并在paintChild方法的帮助下在paint方法中绘制了文本表单字段小部件。但是文本表单域是不交互的,如何使这个文本表单域交互。
代码段:

Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample'),
      ),
      body: InteractiveViewer(
        child: Stack(
          children: [
            Center(
              child: Image.network('https://picsum.photos/250?image=9'),
            ),
            const DrawCanvas(
              child: SizedBox(
                height: 100,
                width: 100,
                child: TextField(
                  decoration: InputDecoration(
                    enabledBorder: OutlineInputBorder(
                        

borderSide: BorderSide(width: 3, color: Colors.blue)),
                        border: OutlineInputBorder(
                            borderSide: BorderSide(width: 3, color: Colors.blue)),
                        labelText: 'NAME',
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }  

    ///
    class DrawCanvas extends SingleChildRenderObjectWidget {
      const DrawCanvas({
        Widget? child,
      }) : super(child: child);
    
      @override
      RenderCanvas createRenderObject(BuildContext context) {
        return RenderCanvas();
      }
    }
    
    class RenderCanvas extends RenderProxyBox {
      RenderCanvas({
        RenderBox? child,
      });
    
      @override
      void paint(PaintingContext context, Offset offset) {
        if (child != null) {
          context.paintChild(child!, const Offset(550, 200));
        }
      }
    }
du7egjpx

du7egjpx1#

你可以复制粘贴下面运行完整的代码
原因:hitTest失败
context.paintChild(child!, const Offset(550, 200));
你在Offset(550, 200)中绘制子进程导致hitTest失败
解决方案:如果是错字,可以执行context.paintChild(child!, offset)
或者你可以传递offset并覆盖hitTestChildren(见下文)
代码片段

class RenderCanvas extends RenderProxyBox {
  final Offset translation;
...
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
        assert(!debugNeedsLayout);
        return result.addWithPaintOffset(
          offset: Offset(translation.dx , translation.dy),
          position: position,
          hitTest: (BoxHitTestResult result, Offset position) {
            return super.hitTestChildren(result, position: position);
          },
        );
      }
...
context.paintChild(child as RenderObject, offset + translation);

全码

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: MyWidget(),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample'),
      ),
      body: InteractiveViewer(
        child: Stack(
          children: [
            Center(
              child: Image.network('https://picsum.photos/250?image=9'),
            ),
            const DrawCanvas(
              translation: Offset(550, 200),
              child: SizedBox(
                height: 100,
                width: 100,
                child: TextField(
                  decoration: InputDecoration(
                    enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(width: 3, color: Colors.blue)),
                    border: OutlineInputBorder(
                        borderSide: BorderSide(width: 3, color: Colors.blue)),
                    labelText: 'NAME',
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class DrawCanvas extends SingleChildRenderObjectWidget {
  final Offset translation;

  const DrawCanvas({
    required this.translation,
    required Widget child,
  }) : super(child: child);

  @override
  RenderCanvas createRenderObject(BuildContext context) {
    return RenderCanvas(translation);
  }

  @override
  void updateRenderObject(BuildContext context, RenderCanvas renderObject) {
    renderObject.translation = translation;
  }
}

class RenderCanvas extends RenderProxyBox {
  RenderCanvas(
    Offset translation,
  ) : _translation = translation;

  Offset get translation => _translation;
  Offset _translation;
  set translation(Offset value) {
    if (_translation == value) {
      return;
    }
    _translation = value;
    markNeedsPaint();
    markNeedsSemanticsUpdate();
  }

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    return hitTestChildren(result, position: position);
  }

  @override
  bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
    assert(!debugNeedsLayout);
    return result.addWithPaintOffset(
      offset: Offset(translation.dx, translation.dy),
      position: position,
      hitTest: (BoxHitTestResult result, Offset position) {
        return super.hitTestChildren(result, position: position);
      },
    );
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    if (child != null) {
      context.paintChild(child as RenderObject, offset + translation);
    }
  }
}

执行结果

相关问题