颤动将滑块拇指更改为图像

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