如何在滑块上方添加刻度和标签?

2024-04-26

我尝试使用 Slider().. 划分看起来不错(值 >= 50 ? 10 : 20)

但是,如何在滑块上方添加刻度和标签?

Expect :

勾选将根据滑块位置改变颜色

Actual:

Slider(
 min: 0,
 max: 100,
 value: value,
 onChanged: (val) {
   setState(() {
     value = val;
   });
  },
 divisions: value >= 50 ? 10 : 20,
 label: value.toString(),
),

我的问题是:

  1. 标签和刻度的位置(如果使用列)
  2. 如果滑块位置相同,则更改刻度颜色

我的代码使用 Column(

Column(
      children: [
        Container(
          margin: EdgeInsets.symmetric(horizontal: 20),
          child:
          Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: List.generate(6, (index) => Text('$index')),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: List.generate(
                  16,
                  (index) => SizedBox(
                    height: 8,
                    child: VerticalDivider(
                      width: 8,
                      color: HelperColors.orange,
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
        Slider(
          value: widget.value,
          min: widget.minValue,
          max: widget.maxValue,
          divisions: widget.divisions,
          onChanged: widget.onChanged,
          label: widget.value.toString(),
        ),
      ],
    );

你能帮我解决这个设计上的一些问题吗?


刻度和刻度值布局

与其将刻度线和刻度值行包装在一列中,不如将刻度线和刻度值组合为单个列可能更好。然后,将此列包裹起来Expanded小部件并将其放入List.generate一行。这保证了刻度始终与刻度值对齐,并且每列具有相等的间距。

刻度线和滑块对齐

默认情况下,滑块带有偏移量,以便为拇指和覆盖层腾出空间。即使您精确计算了屏幕上刻度之间的间距,但在不同屏幕尺寸上进行测试时,间距仍然会拉伸。

如果您有兴趣了解有关滑块偏移/边距的更多信息,请查看此链接。
滑块偏移问题 https://github.com/flutter/flutter/issues/37057

为了实现完美对齐,您需要执行以下操作

  1. 通过创建自定义来删除偏移量trackShape的滑块。

  2. 测量一刻度间距的偏移量并将其除以 2。
    公式为MediaQuery.of(context).size.width / numOfTick / 2

  3. 将零偏移滑块包裹起来Paddingwidget 并使用计算出的偏移量作为水平填充值。padding: EdgeInsets.symmetric(horizontal: offset),

    offset
      V
    |---|
    .----------/   /------------.
    |   0   |           |  100  |    
    |       |Ticks area |       |
    |   |   |           |   |   ||
    .----------/   /------------.|
    |                           ||
    |       Slider area         ||Screen edge
    |                           ||
    '----------/  /-------------'|
    
  4. 现在,无论屏幕尺寸如何,刻度线和滑块将始终从边到边完美对齐。

这是例子。您可能仍想根据您的要求改进 UI。

支持什么

  1. 可调整的主要和次要刻度
  2. 当值匹配时勾选突出显示
  3. 数值精度控制
double value = 50;
double actualValue = 50;
double minValue = 0;
double maxValue = 100;
List<double> steps = [0,5,10,15,20,25,30,35,40,45,50,60,70,80,90,100];

// ...

CustomSlider(
            minValue: minValue,
            maxValue: maxValue,
            value: value,
            majorTick: 6,
            minorTick: 2,
            labelValuePrecision: 0,
            tickValuePrecision: 0,
            onChanged: (val) => setState(() {
              value = val;
              actualValue =
                  steps[(val / maxValue * (steps.length - 1)).ceil().toInt()];
              print('Slider value (linear): $value');
              print('Actual value (non-linear): $actualValue');
            }),
            activeColor: Colors.orange,
            inactiveColor: Colors.orange.shade50,
            linearStep: false,
            steps: steps,
          ),

自定义滑块小部件

class CustomSlider extends StatelessWidget {
  final double value;
  final double minValue;
  final double maxValue;
  final int majorTick;
  final int minorTick;
  final Function(double)? onChanged;
  final Color? activeColor;
  final Color? inactiveColor;
  final int labelValuePrecision;
  final int tickValuePrecision;
  final bool linearStep;
  final List<double>? steps;

  CustomSlider({
    required this.value,
    required this.minValue,
    required this.maxValue,
    required this.majorTick,
    required this.minorTick,
    required this.onChanged,
    this.activeColor,
    this.inactiveColor,
    this.labelValuePrecision = 2,
    this.tickValuePrecision = 1,
    this.linearStep = true,
    this.steps,
  });

  @override
  Widget build(BuildContext context) {
    final allocatedHeight = MediaQuery.of(context).size.height;
    final allocatedWidth = MediaQuery.of(context).size.width;
    final divisions = (majorTick - 1) * minorTick + majorTick;
    final double valueHeight =
        allocatedHeight * 0.05 < 41 ? 41 : allocatedHeight * 0.05;
    final double tickHeight =
        allocatedHeight * 0.025 < 20 ? 20 : allocatedHeight * 0.025;
    final labelOffset = allocatedWidth / divisions / 2;

    return Column(
      children: [
        Row(
          children: List.generate(
            divisions,
            (index) => Expanded(
              child: Column(
                children: [
                  Container(
                    alignment: Alignment.bottomCenter,
                    height: valueHeight,
                    child: index % (minorTick + 1) == 0
                        ? Text(
                            linearStep
                                ? '${(index / (divisions - 1) * maxValue).toStringAsFixed(tickValuePrecision)}'
                                : '${(steps?[index])?.toStringAsFixed(tickValuePrecision)}',
                            style: TextStyle(
                              fontSize: 12,
                            ),
                            textAlign: TextAlign.center,
                          )
                        : null,
                  ),
                  Container(
                    alignment: Alignment.bottomCenter,
                    height: tickHeight,
                    child: VerticalDivider(
                      indent: index % (minorTick + 1) == 0 ? 2 : 6,
                      thickness: 1.2,
                      color: (index / (divisions - 1)) * maxValue == value
                          ? activeColor ?? Colors.orange
                          : Colors.grey.shade300,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.symmetric(horizontal: labelOffset),
          child: SliderTheme(
            data: SliderThemeData(
              trackHeight:
                  allocatedHeight * 0.011 < 9 ? 9 : allocatedHeight * 0.011,
              activeTickMarkColor: activeColor ?? Colors.orange,
              inactiveTickMarkColor: inactiveColor ?? Colors.orange.shade50,
              activeTrackColor: activeColor ?? Colors.orange,
              inactiveTrackColor: inactiveColor ?? Colors.orange.shade50,
              thumbColor: activeColor ?? Colors.orange,
              overlayColor: activeColor == null
                  ? Colors.orange.withOpacity(0.1)
                  : activeColor!.withOpacity(0.1),
              thumbShape: RoundSliderThumbShape(enabledThumbRadius: 12.0),
              trackShape: CustomTrackShape(),
              showValueIndicator: ShowValueIndicator.never,
              valueIndicatorTextStyle: TextStyle(
                fontSize: 12,
              ),
            ),
            child: Slider(
              value: value,
              min: minValue,
              max: maxValue,
              divisions: divisions - 1,
              onChanged: onChanged,
              label: value.toStringAsFixed(labelValuePrecision),
            ),
          ),
        ),
      ],
    );
  }
}

class CustomTrackShape extends RoundedRectSliderTrackShape {
  Rect getPreferredRect({
    required RenderBox parentBox,
    Offset offset = Offset.zero,
    required SliderThemeData sliderTheme,
    bool isEnabled = false,
    bool isDiscrete = false,
  }) {
    final double trackHeight = sliderTheme.trackHeight!;
    final double trackLeft = offset.dx;
    final double trackTop =
        offset.dy + (parentBox.size.height - trackHeight) / 2;
    final double trackWidth = parentBox.size.width;
    return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  }
}

Test

编辑(具有非线性步骤的滑块)

由于 Flutter 滑块具有线性值-位置映射,因此基于非线性值更改滑块值可能不是一个好主意。但是,仍然可以通过为实际值创建附加值范围然后将它们映射在一起来实现这一点。

以下是步骤

  1. 创建一个包含非线性值的列表(您创建的列表)
  2. 确保列表的长度与刻度总数匹配。否则,映射将不正确。
    listLength = (majorTick - 1) * minorTick + majorTick

已对上述代码进行编辑以解决此问题。

Test

映射值

                           Start                            End
Slider value (linear)      0.00 6.67 13.33 ... 86.67 93.33 100.0
Actual value (non-linear)  0.00 5.00 10.00 ... 80.00 90.00 100.0
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在滑块上方添加刻度和标签? 的相关文章

随机推荐

  • 如何从纯文本中查找键值存储中的值

    给定一个纯文本文件 其中包含 FOO foo BAR bar BAZ baz 我们如何grep使用键获取值 Use a 向后看 https regex101 com r q3FNpe 1 grep Po lt FOO w file foo
  • OpenCover 与 TFS 集成

    我是 TFS 新手 希望将 OpenCover 与 TFS 集成 如果有人这样做过 请帮忙 这个问题相当老了 但也许你仍然感兴趣 对于当前版本的 TFS 2015 Update 2 现在可以将其作为 vsts 扩展 详细信息请参见此处 ht
  • 如何使用唯一指针向量?

    I use vector
  • 如何将 URL 参数传递到 Wordpress 页面中的 iFrame?

    WordPress 3 2 1 我有一个页面 其中嵌入了外部页面的 iframe 即在 WP 页面中我有以下代码 我可以动态设置外部网站源吗 通过 URL 参数 假设上面的页面是http mysite com myiframe page h
  • AVMutableVideoComposition 内的交叉淡入淡出

    我已经成功地用多个视频剪辑组成了一个 AVMutableComposition 并且可以查看和导出它 并且我希望能够使用交叉淡入淡出在它们之间进行转换 所以我想使用 AVMutableVideoComposition 我找不到任何关于如何连
  • 同一活动的多个通知

    我有一个正在从通知栏打开的活动 但是当我这样做时NotificationManager notify 我给意图一个不同的捆绑 以便每个通知打开相同的活动 但从数据库中获取彼此的其他信息 但是 当我尝试输入任何通知 例如有 3 个通知 时 它
  • C/C++ 有哪些突变测试框架?

    突变测试 https secure wikimedia org wikipedia en wiki Mutation testing已经出现有一段时间了 似乎至少有一两个针对 C C 的商业突变测试框架 你用过它们吗 你有什么经历 有没有开
  • 根据 1 的数量查找数字的排名

    令 f k y 其中 k 是非负整数递增序列中的第 y 个数 其二进制表示形式中的 1 数量与 k 相同 例如f 0 1 f 1 1 f 2 2 f 3 1 f 4 3 f 5 2 f 6 3 等等 给定 k gt 0 计算 f k 我们很
  • Google App Engine 电子邮件进入垃圾邮件文件夹

    当我使用邮件的 send mail 函数通过谷歌应用程序引擎发送电子邮件时 它们通常会被放置在收件人的 SPAM 文件夹中 虽然 GMail 帐户不会出现此问题 但 Yahoo Mail 帐户 可能还有其他几个帐户 会出现此问题 有没有办法
  • 将 JavaScript 中的大字符串与哈希进行比较

    我有一个带有文本区域的表单 其中可以包含使用多个第三方富文本编辑器之一编辑的大量内容 例如博客文章 我正在尝试实现类似自动保存功能的功能 如果内容发生更改 它应该通过ajax 提交内容 然而 我必须解决这样一个事实 我作为选项的一些编辑器不
  • IIS7 和 HTTP 状态代码处理

    我因试图对 IIS7 集成模式 中的错误呈现进行完整的编程控制而感到非常头疼 我想要做的是给出一个错误 找不到页面 内部服务器错误 未经过身份验证等 将整个请求传输到自定义 ASPX 或 HTML 我更喜欢后者 并使用正确的 HTTP 状态
  • 通过json在textview中显示数据

    我想通过php显示mysql数据库中的用户详细信息并将其显示在android textview中 场景是这样的 当用户登录到他的帐户时 他将被重定向到包含 4 个按钮的仪表板 即 新闻源 个人资料 日历和关于 当用户单击个人资料按钮时 用户
  • Angular 9 ngtypecheck

    更新到 Angular 9 后 我收到警告 src main ngtypecheck ts is part of the TypeScript compilation but it s unused Add only entry point
  • 如何在 Swift 中处理 NSUserDefaults 中的非可选值

    从中获取值NSUserDefaults我会做这样的事情 let userDefaults NSUserDefaults standardUserDefaults if let value userDefaults objectForKey
  • 如何将值从对象转换为 Nullable<> [重复]

    这个问题在这里已经有答案了 我有一些带有一些属性的类 我想将值从字符串转换为该属性的类型 我在转换为可为空类型时遇到问题 这是我的转换方法 public static object ChangeType object value Type
  • 绑定到 AvalonDock 2 中的 LayoutAnchorableItem 可见性

    我正在尝试绑定Visibility of LayoutAnchorableItem到 ViewModel 中的布尔值 以便我可以以编程方式显示和隐藏可锚定
  • .rmd 文件的访问名称并在 R 中使用

    我正在编织一个名为MyFile rmd 我如何访问该字符串MyFile在编织过程中并将其用于 在 YAML 标头的标题部分中使用 在后续的 R 块中使用 title r rmarkdown metadata title author My
  • 如何在maven antrun插件中执行输入任务

    我创建了一个 Maven 项目 我正在尝试运行外部脚本 在此外部脚本中 我使用 read 命令来提出问题并获得答案 如果我做一个 它会起作用sudo mvn 包 with 执行 maven 插件 http www mojohaus org
  • Android 位图图像缓存

    嗨 我正在 Android 中实现图像缓存 经历过这个 http developer android com training displaying bitmaps cache bitmap html http developer andr
  • 如何在滑块上方添加刻度和标签?

    我尝试使用 Slider 划分看起来不错 值 gt 50 10 20 但是 如何在滑块上方添加刻度和标签 Expect 勾选将根据滑块位置改变颜色 Actual Slider min 0 max 100 value value onChan