Рисунок холста Flutter исчезает при попытке увеличить/уменьшить масштабAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Рисунок холста Flutter исчезает при попытке увеличить/уменьшить масштаб

Сообщение Anonymous »

У меня есть приложение, в котором линии рисуются в зависимости от чисел, которые вводит пользователь, и от места, где пользователь нажимает. Я добавил кнопки для увеличения и уменьшения масштаба в дочернее поле моего класса CustomPainter. Там я обновляю параметр _scaleFactor, который затем передаю в класс рисования, где он используется для увеличения или уменьшения линий. Я также загружаю изображение ресурса и не уверен, повлияет ли оно на мою проблему.
Проблема в том, что каждый раз, когда я нажимаю на одну из кнопок, все на холсте действительно масштабируется, и вы можете видите его на секунду, но после этого все исчезает, и вы можете заставить его появиться, только перетаскивая палец по экрану (полагаю, виджет GestureDetector начинает работать).
Это мой код:< /p>

Код: Выделить всё

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});

static const PREFERENCES_IS_FIRST_LAUNCH_STRING =
"PREFERENCES_IS_FIRST_LAUNCH_STRING";

@override
State createState() => _MyHomePageState();
}

class _MyHomePageState extends State
with SingleTickerProviderStateMixin {
final myController1 = TextEditingController();
final myController2 = TextEditingController();
final myController3 = TextEditingController();
final myController4 = TextEditingController();
bool isComplete = false;
int ratio1 = 10;
int ratio2 = 10;
int ratio3 = 10;
int ratio4 = 10;
double _progress1 = 0.0;
late Animation animation1;
late AnimationController controller1;
var tappedPoint = const Offset(0, 0);
double _scaleFactor = 35.0;
double _baseScaleFactor = 35.0;
bool _dragging = false;
var xPos = 0.0;
var yPos = 0.0;

int _numRoots = 0;
final List _res = [];
final List _binRes = [];
String _roots = "";
bool shown = false;

final GlobalKey run = GlobalKey();
final GlobalKey input = GlobalKey();
final GlobalKey xPoint = GlobalKey();
final GlobalKey pOfX = GlobalKey();
final GlobalKey keyNumRoots = GlobalKey();
final GlobalKey drawing = GlobalKey();

late Future _imageFuture;

@override
void initState() {
super.initState();

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_isFirstLaunch().then((result) {
if (result) {
ShowCaseWidget.of(context)
.startShowCase([input, run, xPoint, pOfX, keyNumRoots, drawing]);
}
});
});

controller1 = AnimationController(
duration: const Duration(milliseconds: 3000), vsync: this)
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
isComplete = true;
} else {
isComplete = false;
}
});

animation1 = Tween(begin: 0.0, end: 1.0).animate(controller1)
..addListener(() {
setState(() {
_progress1 = animation1.value;
});
});

_imageFuture = _loadImage("assets/images/turtle.png");
}

Future _isFirstLaunch() async {
final sharedPreferences = await SharedPreferences.getInstance();
bool isFirstLaunch = sharedPreferences
.getBool(MyHomePage.PREFERENCES_IS_FIRST_LAUNCH_STRING) ??
true;
if (isFirstLaunch) {
sharedPreferences.setBool(
MyHomePage.PREFERENCES_IS_FIRST_LAUNCH_STRING, false);
}
return isFirstLaunch;
}

@override
void dispose() {
myController1.dispose();
myController2.dispose();
myController3.dispose();
myController4.dispose();
super.dispose();
}

Future _loadImage(String imagePath) async {
ByteData bd = await rootBundle.load(imagePath);
final Uint8List bytes = Uint8List.view(bd.buffer);
final ui.Codec codec = await ui.instantiateImageCodec(bytes,
targetHeight: 60, targetWidth: 60);
final ui.Image image = (await codec.getNextFrame()).image;

return image;
}

onPan(double x, double y) {
setState(() {
tappedPoint =
Offset(x, y);
MyPainter.setScale(_scaleFactor.toInt());
});
}

String calcDistance(String solution) {
double p = MyPainter.getP();
if (p.isNaN) {
return "0";
} else {
if ((p.abs() 
toastification.show(
title: Text(AppLocalizations.of(context)!.allRoots),
style: ToastificationStyle.flatColored,
primaryColor: Colors.green,
autoCloseDuration: const Duration(seconds: 5)));
}
if (found) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
toastification.show(
title: Text(AppLocalizations.of(context)!.congrats),
autoCloseDuration: const Duration(seconds: 3)));
}
}
}
return p.toStringAsFixed(5);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Turtle Math"), actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>  OnBoardingScreen()));
},
icon: const Icon(Icons.help_outline, color: Colors.white))
]),
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Column(
children: [
AnimatedBuilder(
animation: controller1,
builder: (BuildContext context, _) {
return Showcase(
key: input,
description: AppLocalizations.of(context)!.coefficients,
child: Row(
children: [
const Spacer(flex: 1),
Expanded(
flex: 5,
child: SizedBox(
height: 50,
child: TextField(
textAlign: TextAlign.center,
controller: myController1,
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: "#1"),
),
),
),
Expanded(
flex: 5,
child: SizedBox(
height: 50,
child: TextField(
textAlign: TextAlign.center,
controller: myController2,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
// prefixIcon: const Icon(PiSymbol.pi_outline),
hintText: "#2",
),
),
),
),
Expanded(
flex: 5,
child: SizedBox(
height: 50,
child: TextField(
textAlign: TextAlign.center,
controller: myController3,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
// prefixIcon: const Icon(PiSymbol.pi_outline),
hintText: "#3",
),
),
),
),
Expanded(
flex: 5,
child: SizedBox(
height: 50,
child: TextField(
textAlign: TextAlign.center,
controller: myController4,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
// prefixIcon: const Icon(PiSymbol.pi_outline),
hintText: "#4",
),
),
),
),
Showcase(
key: run,
description:
AppLocalizations.of(context)!.startButton,
child: ElevatedButton(
onPressed:  () {
setState(() {
if (myController1.text.isNotEmpty &
myController2.text.isNotEmpty &
myController3.text.isNotEmpty &
myController4.text.isNotEmpty) {
shown = false;
_res.clear();
_binRes.clear();
_numRoots = 0;

ratio1 = int.parse(myController1.text);
ratio2 = int.parse(myController2.text);
ratio3 = int.parse(myController3.text);
ratio4 = int.parse(myController4.text);
_roots = getRoots(
myController1.text,
myController2.text,
myController3.text,
myController4.text);

controller1.reset();
controller1.forward();
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text(
AppLocalizations.of(
context)!
.error)));
}
});
},
child:
Text(AppLocalizations.of(context)!.run))),
const Spacer(
flex: 1), // child: Text(Platform.localeName)),
],
),
);
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
getCoefficients(myController1.text, myController2.text,
myController3.text, myController4.text),
style: const TextStyle(fontSize: 18)),
),
Padding(
padding: const EdgeInsets.all(1.0),
child: Row(
children: [
Expanded(
child: Showcase(
key: xPoint,
description: AppLocalizations.of(context)!.xPoint,
child: Text(
"x = ${calcK(constraints.maxWidth / 2, constraints.maxHeight / 2)}",
style: const TextStyle(fontSize: 18),
textAlign: TextAlign.center),
),
),
Expanded(
child: Showcase(
key: pOfX,
description: AppLocalizations.of(context)!.pOfX,
child: Text(
"p(x) = ${calcDistance(calcK(constraints.maxWidth / 2, constraints.maxHeight / 2))}",
style: const TextStyle(fontSize: 18),
textAlign: TextAlign.center),
),
)
],
),
),
Padding(
padding: const EdgeInsets.all(1.0),
child:
// Text("$_roots ${_binRes.toString()} $_numRoots",
Showcase(
key: keyNumRoots,
description:
AppLocalizations.of(context)!.rootsDescription,
child: Text(
"${AppLocalizations.of(context)!.numRoots} $_numRoots",
style: const TextStyle(fontSize: 18),
textAlign:  TextAlign.center),
)),
Expanded(
child: FutureBuilder(
future: _imageFuture,
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return GestureDetector(
// scaling
onScaleStart: (details) {
_dragging = true;
_baseScaleFactor = _scaleFactor;
},
onScaleUpdate: (scaleDetails) {
if (scaleDetails.pointerCount == 3) {
setState(() {
_scaleFactor =
_baseScaleFactor * scaleDetails.scale;
});
}
if (scaleDetails.pointerCount == 1) {
onPan(scaleDetails.localFocalPoint.dx, scaleDetails.localFocalPoint.dy);
}
if (scaleDetails.pointerCount == 2) {
if (_dragging) {
setState(() {
xPos += scaleDetails.focalPointDelta.dx;
yPos += scaleDetails.focalPointDelta.dy;
});
}
}
},
onScaleEnd: (scaleDetails) {
_dragging = false;
},
// onPanUpdate: (details) => onPan(details),
child: Showcase(
key: drawing,
description:
AppLocalizations.of(context)!.drawing,
child: ClipRect(
child: CustomPaint(
painter: MyPainter(
constraints.maxWidth / 2,
constraints.maxHeight / 2,
ratio1,
ratio2,
ratio3,
ratio4,
isComplete,
_progress1,
tappedPoint,
xPos,
yPos,
snapshot.data),
size: Size(constraints.maxWidth,
constraints.maxHeight),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(
onPressed: () {
setState(() {
_scaleFactor =
_baseScaleFactor - 5;
MyPainter.setScale(_scaleFactor.toInt());
});
},
icon: const Icon(Icons.zoom_out),
iconSize: 50,
),
IconButton(
onPressed: () {
setState(() {
_scaleFactor =
_baseScaleFactor + 5;
MyPainter.setScale(_scaleFactor.toInt());
});
},
icon: const Icon(Icons.zoom_in),
iconSize: 50,
)
],
),
),
),
),
);
} else {
return GestureDetector(
onScaleStart: (details) {
_baseScaleFactor = _scaleFactor;
},
onScaleUpdate: (scaleDetails) {
if (scaleDetails.pointerCount == 3) {
setState(() {
_scaleFactor =
_baseScaleFactor * scaleDetails.scale;
});
}
if (scaleDetails.pointerCount == 1) {
onPan(scaleDetails.localFocalPoint.dx, scaleDetails.localFocalPoint.dy);
}
},
child: CustomPaint(
painter: MyPainter(
constraints.maxWidth / 2,
constraints.maxHeight / 2,
ratio1,
ratio2,
ratio3,
ratio4,
isComplete,
_progress1,
tappedPoint,
xPos,
yPos),
size: Size(constraints.maxWidth,
constraints.maxHeight)),
);
}
})),
],
);
},
));
}
}

class MyPainter extends CustomPainter {
ui.Image? image;
double _width = 0;
static double _height = 0;
static int _ratio1 = 0;
static int _ratio2 = 0;
static int _ratio3 = 0;
static int _ratio4 = 0;
static int _scale = 35;
final double _progress;
Offset tappedPoint;
static bool _isComplete = false;
static double k = 0;
double _xPos = 0;
double _yPos = 0;

MyPainter(width, height, ratio1, ratio2, ratio3, ratio4, isComplete,
this._progress, this.tappedPoint, this._xPos, this._yPos,
[this.image]) {
_width = width;
_height = height;
_ratio1 = ratio1;
_ratio2 = ratio2;
_ratio3 = ratio3;
_ratio4 = ratio4;
_isComplete = isComplete;
// _scale = (_width / 10).toInt();
}

static void setScale(int newScale) {
_scale = newScale;
}

static double getP() {
if (_isComplete == true) {
return (_ratio4 - k * (_ratio3 - k * (_ratio2 - k * _ratio1))) / _scale;
} else {
return -1;
}
}

static double getK() {
return k;
}

@override
void paint(Canvas canvas, Size size) {
Paint linePaint = Paint()
..strokeWidth = 20
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;

Paint solutionPaint = Paint()
..strokeWidth = 8
..strokeCap = ui.StrokeCap.butt
..style = ui.PaintingStyle.stroke
..color = Colors.redAccent;

Paint imaginaryPaint = Paint()
..strokeWidth = 5
..strokeCap = ui.StrokeCap.butt
..style = ui.PaintingStyle.stroke
..color = const Color.fromRGBO(105, 105, 105, 0.5);

_ratio1 *= _scale;
_ratio2 *= _scale;
_ratio3 *= _scale;
_ratio4 *= _scale;

_width += _xPos;
_height += _yPos;

_width += (math.max(_ratio1, _ratio3) / 2) - _ratio1;
_height += (math.max(_ratio2, _ratio4) / 2);

var path = getPath();
Rect bounds = path.getBounds();
if (bounds.bottom >= size.height) {
path = path
.shift(Offset(0, -(bounds.bottom - _height + bounds.center.dy / 10)));
}

ui.PathMetrics pathMetrics = path.computeMetrics();

ui.PathMetric pathMetric = pathMetrics.elementAt(0);
final pos = pathMetric.getTangentForOffset(pathMetric.length * _progress);
Path extracted = pathMetric.extractPath(0.0, pathMetric.length * _progress);

linePaint.strokeWidth = 6;

canvas.drawPath(extracted, linePaint);
if (image == null) {
canvas.drawCircle(pos!.position, linePaint.strokeWidth / 2, linePaint);
} else {
Offset location = Offset(pos!.position.dx - image!.width / 2,
pos.position.dy - image!.height / 2);
canvas.save();
double cx = pos.position.dx;
double cy = pos.position.dy;
double angle = pos.angle;
if (angle == math.pi / 2) {
angle = -angle;
} else if (angle == -(math.pi / 2)) {
angle = math.pi / 2;
}
rotateTurtle(canvas: canvas, cx: cx, cy: cy, angle: angle);
canvas.drawPoints(ui.PointMode.points, [Offset(cx, cy)], linePaint);
canvas.drawImage(image!, location, linePaint);
canvas.restore();
if (_isComplete) {
// canvas.drawLine(Offset(_width, _height), tappedPoint, solutionPaint);
k = (tappedPoint.dy - _height) / (_width - tappedPoint.dx);
var solution = getSolution(k);
double shift = 0;

if (bounds.bottom >= size.height) {
shift = (bounds.bottom - _height + bounds.center.dy / 10);
solution = solution.shift(
Offset(0, -(bounds.bottom - _height + bounds.center.dy / 10)));
}

// imaginary lines
checkSolution(canvas, k, imaginaryPaint, extracted, shift);

canvas.drawPath(solution, solutionPaint);
}
}
}

Path getSolution(tangent) {
return Path()
..moveTo(_width, _height)
..lineTo(_width + _ratio1, _height - tangent * _ratio1)
..lineTo(_width + _ratio1 - tangent * (_ratio2 - tangent * _ratio1),
_height - _ratio2)
..lineTo(
_width + _ratio1 - _ratio3,
_height -
_ratio2 +
tangent * (_ratio3 - tangent * (_ratio2 - tangent * _ratio1)));
}

void rotateTurtle(
{required Canvas canvas,
required double cx,
required double cy,
required double angle}) {
canvas.translate(cx, cy);
canvas.rotate(angle);
canvas.translate(-cx, -cy);
}

Path getPath() {
return Path()
..moveTo(_width, _height)
..lineTo(_width + _ratio1, _height)
..lineTo(_width + _ratio1, _height - _ratio2)
..lineTo(_width + _ratio1 - _ratio3, _height - _ratio2)
..lineTo(_width + _ratio1 - _ratio3, _height - _ratio2 + _ratio4);
}

@override
bool shouldRepaint(covariant MyPainter oldDelegate) {
return (oldDelegate._progress != _progress);
}
}
Может кто-нибудь помочь мне понять, почему возникает эта задержка при нажатии кнопки масштабирования? Заранее спасибо.

Подробнее здесь: https://stackoverflow.com/questions/790 ... oom-in-out
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Рисунок холста Flutter исчезает при попытке увеличить/уменьшить масштаб
    Anonymous » » в форуме Android
    0 Ответы
    26 Просмотры
    Последнее сообщение Anonymous
  • Как мне увеличить и уменьшить масштаб веб-сайта, используя процентные единицы, такие как vh vw и %, без увеличения разме
    Anonymous » » в форуме CSS
    0 Ответы
    22 Просмотры
    Последнее сообщение Anonymous
  • Как найти точки соприкосновения линии с границами холста после поворота холста
    Гость » » в форуме Javascript
    0 Ответы
    106 Просмотры
    Последнее сообщение Гость
  • Макет меню вне холста не работает из-за холста на iOS
    Anonymous » » в форуме CSS
    0 Ответы
    121 Просмотры
    Последнее сообщение Anonymous
  • Макет меню вне холста не работает из-за холста на iOS
    Anonymous » » в форуме IOS
    0 Ответы
    60 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»