颤动将滑块拇指更改为图像
Flutter change slider thumb to image
我想创建这样的东西。
我已经成功创建了它,但是每当我启动应用程序时,我都会收到 LateInitializationError,在滑块显示之前显示 LateInitializationError: Field 'customImage' has not been initialized.
。
这是我的代码。我究竟做错了什么?我还尝试了 flutter xlider 包,但它不再起作用,因为它不支持空安全。如果您有更好的更改滑块滑块的方法,将不胜感激。
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
class CustomSlider extends StatefulWidget {
const CustomSlider({Key? key}) : super(key: key);
@override
_CustomSliderState createState() => _CustomSliderState();
}
class _CustomSliderState extends State<CustomSlider> {
late ui.Image customImage;
double sliderValue = 0.0;
Future<ui.Image> loadImage(String assetPath) async {
ByteData data = await rootBundle.load(assetPath);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
}
@override
void initState() {
loadImage('images/star.png').then((image) {
setState(() {
customImage = image;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SliderTheme(
data: SliderThemeData(
trackHeight: 28,
inactiveTrackColor: Colors.grey.shade300,
activeTrackColor: const Color(0xFFFFE900),
thumbShape: SliderThumbImage(customImage),
),
child: Slider(
value: 50,
min: 0,
max: 100,
onChanged: (value) {},
),
);
}
}
class SliderThumbImage extends SliderComponentShape {
final ui.Image image;
SliderThumbImage(this.image);
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return const Size(0, 0);
}
@override
void paint(PaintingContext context, Offset center,
{required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow}) {
final canvas = context.canvas;
final imageWidth = image.width;
final imageHeight = image.height;
Offset imageOffset = Offset(
center.dx - (imageWidth / 2),
center.dy - (imageHeight / 2),
);
Paint paint = Paint()..filterQuality = FilterQuality.high;
canvas.drawImage(image, imageOffset, paint);
}
}
所有非延迟变量都初始化为空。如果一个变量是不可为空的,如果它曾经包含 null 就会出错,所以这是一个编译时错误:
int? number; // initialized to null
var str; // compile-time error
使您的字段可为空
ui.Image? customImage;
initState
运行s 在构建小部件之前,但不能是异步函数,因此 customImage = image;
几乎肯定会 运行 晚于 build
函数。由于您在 build
函数中使用 customImage
,并且 customImage
被标记为迟到,因此您会收到此错误。
您可以删除 late
关键字,使 customImage
可为空,并在 build
方法中检查其值。如果为空(图片尚未加载),例如显示进度指示器。
但这并不完美,因为根据图像加载所花费的时间,有可能在构建小部件时调用 setState
,这会触发另一个错误。
虽然您可以使用 addPostFrameCallback
解决上述问题,但最好的方法是使用 FutureBuilder
,先加载图像,然后构建您的小部件:
late Future<ui.Image> _loadImage;
@override
void initState()
super.initState();
_loadImage = loadImage();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<ui.Image>(
future: _loadImage,
builder: (context, snapshot) {
if (snapshot.hasData || snapshot.data != null) {
return SliderTheme(
data: SliderThemeData(
trackHeight: 28,
inactiveTrackColor: Colors.grey.shade300,
activeTrackColor: const Color(0xFFFFE900),
thumbShape: SliderThumbImage(snapshot.data!),
),
child: Slider(
value: 50,
min: 0,
max: 100,
onChanged: (value) {},
),
);
}
// progress indicator while loading image,
// you can return and empty Container etc. if you like
return CircularProgressIndicator();
});
}
我想创建这样的东西。
我已经成功创建了它,但是每当我启动应用程序时,我都会收到 LateInitializationError,在滑块显示之前显示 LateInitializationError: Field 'customImage' has not been initialized.
。
这是我的代码。我究竟做错了什么?我还尝试了 flutter xlider 包,但它不再起作用,因为它不支持空安全。如果您有更好的更改滑块滑块的方法,将不胜感激。
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
class CustomSlider extends StatefulWidget {
const CustomSlider({Key? key}) : super(key: key);
@override
_CustomSliderState createState() => _CustomSliderState();
}
class _CustomSliderState extends State<CustomSlider> {
late ui.Image customImage;
double sliderValue = 0.0;
Future<ui.Image> loadImage(String assetPath) async {
ByteData data = await rootBundle.load(assetPath);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
}
@override
void initState() {
loadImage('images/star.png').then((image) {
setState(() {
customImage = image;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SliderTheme(
data: SliderThemeData(
trackHeight: 28,
inactiveTrackColor: Colors.grey.shade300,
activeTrackColor: const Color(0xFFFFE900),
thumbShape: SliderThumbImage(customImage),
),
child: Slider(
value: 50,
min: 0,
max: 100,
onChanged: (value) {},
),
);
}
}
class SliderThumbImage extends SliderComponentShape {
final ui.Image image;
SliderThumbImage(this.image);
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return const Size(0, 0);
}
@override
void paint(PaintingContext context, Offset center,
{required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow}) {
final canvas = context.canvas;
final imageWidth = image.width;
final imageHeight = image.height;
Offset imageOffset = Offset(
center.dx - (imageWidth / 2),
center.dy - (imageHeight / 2),
);
Paint paint = Paint()..filterQuality = FilterQuality.high;
canvas.drawImage(image, imageOffset, paint);
}
}
所有非延迟变量都初始化为空。如果一个变量是不可为空的,如果它曾经包含 null 就会出错,所以这是一个编译时错误:
int? number; // initialized to null
var str; // compile-time error
使您的字段可为空
ui.Image? customImage;
initState
运行s 在构建小部件之前,但不能是异步函数,因此 customImage = image;
几乎肯定会 运行 晚于 build
函数。由于您在 build
函数中使用 customImage
,并且 customImage
被标记为迟到,因此您会收到此错误。
您可以删除 late
关键字,使 customImage
可为空,并在 build
方法中检查其值。如果为空(图片尚未加载),例如显示进度指示器。
但这并不完美,因为根据图像加载所花费的时间,有可能在构建小部件时调用 setState
,这会触发另一个错误。
虽然您可以使用 addPostFrameCallback
解决上述问题,但最好的方法是使用 FutureBuilder
,先加载图像,然后构建您的小部件:
late Future<ui.Image> _loadImage;
@override
void initState()
super.initState();
_loadImage = loadImage();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<ui.Image>(
future: _loadImage,
builder: (context, snapshot) {
if (snapshot.hasData || snapshot.data != null) {
return SliderTheme(
data: SliderThemeData(
trackHeight: 28,
inactiveTrackColor: Colors.grey.shade300,
activeTrackColor: const Color(0xFFFFE900),
thumbShape: SliderThumbImage(snapshot.data!),
),
child: Slider(
value: 50,
min: 0,
max: 100,
onChanged: (value) {},
),
);
}
// progress indicator while loading image,
// you can return and empty Container etc. if you like
return CircularProgressIndicator();
});
}