自定义滑块拇指可选区域与自定义滑块轨道不正确

时间:2021-05-31 15:15:25

标签: flutter dart

在我的自定义滑块拇指和轨道中,可以选择不正确的滑块拇指区域进行拖动。代码如下:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: [
            SizedBox(height: 100),
            Row(children: [
              SizedBox(width: 100),
              CustomSlider()
            ])
          ]
        )
      )
    );
  }
}


class CustomSlider extends StatefulWidget {
  CustomSlider({Key? key}) : super(key: key);

  @override
  _CustomSliderState createState() => _CustomSliderState();
}

class _CustomSliderState extends State<CustomSlider> {
  double _value = .5;

  @override
  Widget build(BuildContext context) {
    return SliderTheme(
        data: SliderThemeData(
          thumbShape: _SliderThumbImage(),
          trackShape: _SliderTrack(), // Commenting results in correct selectable thumb region
        ),
        child: Slider(
          min: .1, max: 1, value: _value,
          onChanged: (value) => setState(() { _value = value; })
        ));
  }
}

class _SliderThumbImage extends SliderComponentShape {
  static const thumbSideLength = 60.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;

    Offset thumbDrawOffset = Offset(center.dx - (thumbSideLength / 2), center.dy - (thumbSideLength / 2));

    canvas.drawRect(Rect.fromLTWH(thumbDrawOffset.dx, thumbDrawOffset.dy, thumbSideLength, thumbSideLength),
                    Paint()..color = Colors.black);
  }

  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) {
    return Size(thumbSideLength, thumbSideLength);
  }
}

class _SliderTrack extends SliderTrackShape {
  static const width = 184.0;
  static const trackHeight = 16.0;

  @override
  Rect getPreferredRect(
      {required RenderBox parentBox, Offset offset = Offset.zero, required SliderThemeData sliderTheme, bool isEnabled = true, bool isDiscrete = true}) {
    return Rect.fromLTWH(0, 0, width, trackHeight);
  }

  @override
  void paint(PaintingContext context, Offset offset,
      {required RenderBox parentBox, required SliderThemeData sliderTheme, required Animation<double> enableAnimation, required Offset thumbCenter, bool isEnabled = true, bool isDiscrete = true, required TextDirection textDirection}) {
    final canvas = context.canvas;

    canvas.drawLine(
        Offset(offset.dx, offset.dy + trackHeight / 2),
        Offset(offset.dx + width, offset.dy + trackHeight / 2),
        Paint()
          ..color = Colors.amber
          ..strokeCap = StrokeCap.round
          ..strokeWidth = trackHeight);
  }
}

这将呈现以下内容。黑色方块的上半部分不可拖动,而滑块的整个下半部分是可选择的。滑块的上半部分或滑块拇指应该是可选的。

enter image description here

如果我注释掉 trackShape 参数,则可以选择拇指的正确区域。

1 个答案:

答案 0 :(得分:0)

可用于调整滑块值的滑块区域由轨道尺寸和拇指尺寸共同配置。如果将拇指配置为 50x50,将轨道配置为 100x10,则可选择的区域是滑块的 50x100 边界框,而不是 50x50 的拇指区域。例如,下面突出显示的区域是可选区域: enter image description here

这也是没有主题的默认滑块的行为。

考虑到这一点,我在此边界框内适当地绘制了轨迹和拇指偏移。

import 'package:flutter/material.dart';

const thumbSideLength = 60.0;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: [
            SizedBox(height: 100),
            Row(children: [
              SizedBox(width: 100),
              CustomSlider()
            ])
          ]
        )
      )
    );
  }
}


class CustomSlider extends StatefulWidget {
  CustomSlider({Key? key}) : super(key: key);

  @override
  _CustomSliderState createState() => _CustomSliderState();
}

class _CustomSliderState extends State<CustomSlider> {
  double _value = .5;

  @override
  Widget build(BuildContext context) {
    return SliderTheme(
        data: SliderThemeData(
          thumbShape: _SliderThumbImage(),
          trackShape: _SliderTrack(), // Commenting results in correct selectable thumb region
        ),
        child: Slider(
          min: .1, max: 1, value: _value,
          onChanged: (value) => setState(() { _value = value; })
        ));
  }
}

class _SliderThumbImage extends SliderComponentShape {  
  @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;
    Offset thumbCenter = Offset(center.dx, thumbSideLength/2);

    canvas.drawRect(Rect.fromCenter(center: thumbCenter, width: thumbSideLength, height: thumbSideLength), Paint()..color = Colors.black);
  }

  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) {
    return Size(thumbSideLength, thumbSideLength);
  }
}

class _SliderTrack extends SliderTrackShape {
  static const width = 184.0;
  static const trackHeight = 16.0;

  @override
  Rect getPreferredRect(
      {required RenderBox parentBox, Offset offset = Offset.zero, required SliderThemeData sliderTheme, bool isEnabled = true, bool isDiscrete = true}) {
    return Rect.fromLTWH(0, 0, width, trackHeight);
  }

  @override
  void paint(PaintingContext context, Offset offset,
      {required RenderBox parentBox, required SliderThemeData sliderTheme, required Animation<double> enableAnimation, required Offset thumbCenter, bool isEnabled = true, bool isDiscrete = true, required TextDirection textDirection}) {
    final canvas = context.canvas;

    canvas.drawLine(
      Offset(offset.dx, offset.dy + thumbSideLength/2),
      Offset(offset.dx + width, offset.dy + thumbSideLength / 2),
      Paint()
      ..color = Colors.amber
      ..strokeCap = StrokeCap.round
      ..strokeWidth = trackHeight);
  }
}