Flutter - 使用 Flutter 创建自定义控件
Flutter - Creating a custom control with Flutter
我需要创建一个允许用户在有界矩形内拖动指针的自定义控件。非常喜欢这里的摇杆控制:https://github.com/zerokol/JoystickView
我已经设法使用 CustomPainter 来绘制控制点,并使用 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;
}
您的代码没有在任何地方使用 GestureDetector
。
你应该用它来包装 CustomPaint
和 TouchControlState
的 build()
函数。
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;
}
我需要创建一个允许用户在有界矩形内拖动指针的自定义控件。非常喜欢这里的摇杆控制:https://github.com/zerokol/JoystickView
我已经设法使用 CustomPainter 来绘制控制点,并使用 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;
}
您的代码没有在任何地方使用 GestureDetector
。
你应该用它来包装 CustomPaint
和 TouchControlState
的 build()
函数。
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;
}