Flutter-使用Flutter创建自定义控件 [英] Flutter - Creating a custom control with Flutter

查看:1443
本文介绍了Flutter-使用Flutter创建自定义控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个自定义控件,该控件允许用户在有界矩形内拖动指针。非常类似于此操纵杆控件:

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

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

类TouchTest扩展了StatelessWidget {
//此小部件是应用程序的根。
@override
小部件构建(BuildContext上下文){
返回新的MaterialApp(
标题:触摸测试,
主题:新的ThemeData(
primarySwatch :Colors.blue,
),
主页:new Scaffold(
appBar:new AppBar(
title:const Text('Test'),
),
正文:新Container(

装饰:new BoxDecoration(
颜色:Colors.white,
边框:new Border.all(
颜色:Colors。黑色,
宽度:2.0,
),
),
子级:new Center(
子级:new TouchControl()
),
),

);
}
}

类TouchControl扩展了StatefulWidget {
final double xPos;
最终双倍yPos;
final ValueChanged< Offset> onChanged;

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

@override
TouchControlState createState()=>新的TouchControlState();
}

/ **
*在提供的位置绘制一个圆圈。
*
* /
类TouchControlState扩展了State< TouchControl> {
double xPos = 0.0;
double yPos = 0.0;

GlobalKey _painterKey = new GlobalKey();

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

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

@override
bool hitTestSelf(Offset position)=>真正;

@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
小部件构建(BuildContext上下文){
返回new ConstrainedBox(
约束:new BoxConstraints.expand(),
子:new GestureDetector(
行为:HitTestBehavior.opaque,
onPanStart:_handlePanStart,
onPanEnd:_handlePanEnd,
onPanUpdate:_handlePanUpdate,
子级:new CustomPaint(
size:new Size(xPos,yPos),
画家:new TouchControlPainter(xPos,yPos),
),
),
);
}
}

类TouchControlPainter扩展了CustomPainter {
静态const markerRadius = 10.0;
最终双倍xPos;
最终双倍yPos;

TouchControlPainter(this.xPos,this.yPos);

@override
无效绘画(画布画布,大小大小){
最终绘画= 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;
}


I need to create a custom control which allows a user to drag a pointer within a bounded rectangle. Very like this joystick control here :https://github.com/zerokol/JoystickView

I have managed to cobble something together using a CustomPainter to draw the control point and a GestureDetector to track where the user drags the pointer on the view. However, I can't get this to capture the panning input. I can't get it to capture any input at all. I don't know if what I am doing is the best approach. I could be on the totally wrong track. Here is the code.

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;
}

解决方案

Your code isn't using the GestureDetector anywhere.

You should use it to wrap the CustomPaint the build() function of TouchControlState.

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;
}

这篇关于Flutter-使用Flutter创建自定义控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆