Afd*_*dra 4 flutter flutter-layout
我尝试使用 Slider().. 划分看起来不错(值 >= 50 ? 10 : 20)
但是,如何在滑块上方添加刻度和标签?
预计 :
勾选将根据滑块位置改变颜色
实际的:
Slider(
min: 0,
max: 100,
value: value,
onChanged: (val) {
setState(() {
value = val;
});
},
divisions: value >= 50 ? 10 : 20,
label: value.toString(),
),
Run Code Online (Sandbox Code Playgroud)
我的问题是:
我的代码使用 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(),
),
],
);
Run Code Online (Sandbox Code Playgroud)
你能帮我解决这个设计上的一些问题吗?
与其将刻度线和刻度值行包装在一列中,不如将刻度线和刻度值组合为单个列可能更好。然后,用小部件包裹这一列Expanded并将其放在List.generate一行中。这保证了刻度始终与刻度值对齐,并且每列具有相等的间距。
默认情况下,滑块带有偏移量,以便为拇指和覆盖层腾出空间。即使您精确计算了屏幕上刻度之间的间距,但在不同屏幕尺寸上进行测试时,间距仍然会拉伸。
如果您有兴趣了解有关滑块偏移/边距的更多信息,请查看此链接。
滑块偏移问题
为了实现完美对齐,您需要执行以下操作
trackShape通过创建自定义滑块来消除偏移。
测量一刻度间距的偏移量并将其除以 2。
公式为MediaQuery.of(context).size.width / numOfTick / 2
用小部件包裹零偏移滑块Padding,并使用计算出的偏移量作为水平填充值。padding: EdgeInsets.symmetric(horizontal: offset),
offset
V
|---|
.----------/ /------------.
| 0 | | 100 |
| |Ticks area | |
| | | | | ||
.----------/ /------------.|
| ||
| Slider area ||Screen edge
| ||
'----------/ /-------------'|
Run Code Online (Sandbox Code Playgroud)
现在,无论屏幕尺寸如何,刻度线和滑块将始终从边到边完美对齐。
这是例子。您可能仍想根据您的要求改进 UI。
支持什么
offset
V
|---|
.----------/ /------------.
| 0 | | 100 |
| |Ticks area | |
| | | | | ||
.----------/ /------------.|
| ||
| Slider area ||Screen edge
| ||
'----------/ /-------------'|
Run Code Online (Sandbox Code Playgroud)
自定义滑块小部件
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,
),
Run Code Online (Sandbox Code Playgroud)
测试
由于 Flutter 滑块具有线性值-位置映射,因此基于非线性值更改滑块值可能不是一个好主意。但是,仍然可以通过为实际值创建附加值范围然后将它们映射在一起来实现这一点。
以下是步骤
listLength = (majorTick - 1) * minorTick + majorTick已对上述代码进行编辑以解决此问题。
测试
映射值
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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4063 次 |
| 最近记录: |