2017-06-13 37 views
2

ユーザーが境界のある矩形内でポインタをドラッグできるカスタムコントロールを作成する必要があります。 https://github.com/zerokol/JoystickViewFlutter - Flutterでカスタムコントロールを作成する

コントロールポイントを描画するためにカスタムペインタを使用し、ユーザがビュー上でポインタをドラッグする場所を追跡するためにGestureDetectorを使用して、何かを一緒にコブルすることができました。しかし、パン入力をキャプチャすることはできません。私はそれをすべての入力をキャプチャすることはできません。私がやっていることが最善のアプローチであるかどうかは分かりません。私は完全に間違ったトラックにいる可能性があります。ここにコードがあります。

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

void main() { 
    runApp(new TouchTest()); 
} 

class TouchTest extends StatelessWidget { 
    // This widget is the root of your application. 
    @override 
    Widget build(BuildContext context) { 
    return new MaterialApp(
     title: 'Touch Test', 
     theme: new ThemeData(
     primarySwatch: Colors.blue, 
    ), 
     home: new Scaffold(
     appBar: new AppBar(
      title: const Text('Test'), 
     ), 
     body: new Container(

      decoration: new BoxDecoration(
       color: Colors.white, 
       border: new Border.all(
       color: Colors.black, 
       width: 2.0, 
       ), 
      ), 
      child: new Center(
       child: new TouchControl() 
      ), 
      ), 
    ) 
    ); 
    } 
} 

class TouchControl extends StatefulWidget { 
    final double xPos; 
    final double yPos; 
    final ValueChanged<Offset> onChanged; 

    const TouchControl({Key key, 
      this.onChanged, 
      this.xPos:0.0, 
      this.yPos:0.0}) : super(key: key); 

    @override 
    TouchControlState createState() => new TouchControlState(); 
} 

/** 
* Draws a circle at supplied position. 
* 
*/ 
class TouchControlState extends State<TouchControl> { 
    double xPos = 0.0; 
    double yPos = 0.0; 

    GestureDetector _gestureDetector; 

    TouchControl() { 
    _gestureDetector = new GestureDetector(
     onPanStart:_handlePanStart, 
     onPanEnd: _handlePanEnd, 
     onPanUpdate: _handlePanUpdate); 
    } 

    void onChanged(Offset offset) { 
    setState(() { 
     widget.onChanged(offset); 

     xPos = offset.dx; 
     yPos = offset.dy; 
    }); 
    } 

    @override 
    bool hitTestSelf(Offset position) => true; 

    @override 
    void handleEvent(PointerEvent event, BoxHitTestEntry entry) { 
    if (event is PointerDownEvent) { 
    // ?? 
    } 
    } 

    void _handlePanStart(DragStartDetails details) { 
    onChanged(details.globalPosition); 
    } 

    void _handlePanEnd(DragEndDetails details) { 
    // TODO 
    } 

    void _handlePanUpdate(DragUpdateDetails details) { 
    onChanged(details.globalPosition); 
    } 

    @override 
    Widget build(BuildContext context) { 
    return new Center(
     child: new CustomPaint(
     size: new Size(xPos, yPos), 
     painter: new TouchControlPainter(xPos, yPos), 
    ), 
    ); 
    } 
} 

class TouchControlPainter extends CustomPainter { 
    static const markerRadius = 10.0; 
    final double xPos; 
    final double yPos; 

    TouchControlPainter(this.xPos, this.yPos); 

    @override 
    void paint(Canvas canvas, Size size) { 
    final paint = new Paint() 
     ..color = Colors.blue[400] 
     ..style = PaintingStyle.fill; 

    canvas.drawCircle(new Offset(xPos, yPos), markerRadius, paint); 
    } 


    @override 
    bool shouldRepaint(TouchControlPainter old) => xPos != old.xPos && yPos !=old.yPos; 
} 

答えて

3

コードにはGestureDetectorが使用されていません。

CustomPaintbuild()の機能をTouchControlStateに改めてください。

screenshot

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

void main() { 
    runApp(new TouchTest()); 
} 

class TouchTest extends StatelessWidget { 
    // This widget is the root of your application. 
    @override 
    Widget build(BuildContext context) { 
    return new MaterialApp(
     title: 'Touch Test', 
     theme: new ThemeData(
     primarySwatch: Colors.blue, 
    ), 
     home: new Scaffold(
     appBar: new AppBar(
      title: const Text('Test'), 
     ), 
     body: new Container(

      decoration: new BoxDecoration(
      color: Colors.white, 
      border: new Border.all(
       color: Colors.black, 
       width: 2.0, 
      ), 
     ), 
      child: new Center(
      child: new TouchControl() 
     ), 
     ), 
    ) 
    ); 
    } 
} 

class TouchControl extends StatefulWidget { 
    final double xPos; 
    final double yPos; 
    final ValueChanged<Offset> onChanged; 

    const TouchControl({Key key, 
    this.onChanged, 
    this.xPos:0.0, 
    this.yPos:0.0}) : super(key: key); 

    @override 
    TouchControlState createState() => new TouchControlState(); 
} 

/** 
* Draws a circle at supplied position. 
* 
*/ 
class TouchControlState extends State<TouchControl> { 
    double xPos = 0.0; 
    double yPos = 0.0; 

    GlobalKey _painterKey = new GlobalKey(); 

    void onChanged(Offset offset) { 
    final RenderBox referenceBox = context.findRenderObject(); 
    Offset position = referenceBox.globalToLocal(offset); 
    if (widget.onChanged != null) 
     widget.onChanged(position); 

    setState(() { 
     xPos = position.dx; 
     yPos = position.dy; 
    }); 
    } 

    @override 
    bool hitTestSelf(Offset position) => true; 

    @override 
    void handleEvent(PointerEvent event, BoxHitTestEntry entry) { 
    if (event is PointerDownEvent) { 
     // ?? 
    } 
    } 

    void _handlePanStart(DragStartDetails details) { 
    onChanged(details.globalPosition); 
    } 

    void _handlePanEnd(DragEndDetails details) { 
    print('end'); 
    // TODO 
    } 

    void _handlePanUpdate(DragUpdateDetails details) { 
    onChanged(details.globalPosition); 
    } 

    @override 
    Widget build(BuildContext context) { 
    return new ConstrainedBox(
     constraints: new BoxConstraints.expand(), 
     child: new GestureDetector(
     behavior: HitTestBehavior.opaque, 
     onPanStart:_handlePanStart, 
     onPanEnd: _handlePanEnd, 
     onPanUpdate: _handlePanUpdate, 
     child: new CustomPaint(
      size: new Size(xPos, yPos), 
      painter: new TouchControlPainter(xPos, yPos), 
     ), 
    ), 
    ); 
    } 
} 

class TouchControlPainter extends CustomPainter { 
    static const markerRadius = 10.0; 
    final double xPos; 
    final double yPos; 

    TouchControlPainter(this.xPos, this.yPos); 

    @override 
    void paint(Canvas canvas, Size size) { 
    final paint = new Paint() 
     ..color = Colors.blue[400] 
     ..style = PaintingStyle.fill; 

    canvas.drawCircle(new Offset(xPos, yPos), markerRadius, paint); 
    } 


    @override 
    bool shouldRepaint(TouchControlPainter old) => xPos != old.xPos && yPos !=old.yPos; 
} 
+0

ああ、今私はそれを参照してくださいという意味をなすようお願いします。しかし、これを試しても、私はまだGestureDetectorからの入力を捕まえることができません。特定の種類の親または子供が必要ですか? – alrutherford

+0

'xPos'と' yPos'の両方が '0.0'にデフォルト設定されているので、カスタムペインタに' Size'の '(0.0、0.0)'を渡していました。また、グローバル座標から相対座標に変換する必要があります。私は完全な作業サンプルで私の答えを更新しました。 –

+0

私はFlutterウィジェットのソースを掘り下げていましたが、物事が一緒に(非常に成功することなく)どのようにぶら下がっているか把握しようとしています。 – alrutherford

関連する問題