我想实现这个滑块,允许用户选择时间。当代表刻钟、半小时和整小时的条形位于锚点区域时,它们应变为紫色(与图钉/锚点颜色相同)。我将其用作垂直可滚动屏幕中的组件。
我还附上了我当前的实现。但我对如何获取时间值以及如何更改当前条的颜色感到困惑。
class FixedPinTimePicker extends StatefulWidget {
FixedPinTimePicker({super.key, required this.width});
double width;
@override
State<FixedPinTimePicker> createState() => _FixedPinTimePickerState();
}
Widget hourBar() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 100,
width: 5,
color: Colors.grey,
),
);
}
Widget halfHourBar() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 70,
width: 5,
color: Colors.grey,
),
);
}
Widget quarterHourBar() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 50,
width: 5,
color: Colors.grey,
),
);
}
Widget getBarBasedOnIndex(int index) {
if (index % 4 == 0) {
return halfHourBar();
} else if (index % 2 == 0) {
return hourBar();
} else {
return quarterHourBar();
}
}
String getTimeBasedOnIndex(int index) {
final int hour = index ~/ 2;
final int minute = index % 2 == 0 ? 0 : 30;
return index % 2 == 0 ? '$hour:$minute' : '';
}
class _FixedPinTimePickerState extends State<FixedPinTimePicker> {
ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
log("Width: ${widget.width}");
return SizedBox(
height: 150,
child: Stack(
children: [
ListView.builder(
controller: _scrollController,
scrollDirection: Axis.horizontal,
itemCount: 49,
itemBuilder: (context, index) {
log("Controller: ${_scrollController.offset}");
return Stack(
children: [
getBarBasedOnIndex(index),
Positioned(
bottom: 0,
child: Text(
getTimeBasedOnIndex(index),
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
),
],
);
},
),
Positioned(
top: 0,
right: widget.width / 2 - 40,
child: CustomPaint(
painter: InvertedTrianglePainter(),
size: Size(30, 60),
)),
],
),
);
}
}
import 'package:flutter/material.dart';
class FixedPinTimePicker extends StatefulWidget {
const FixedPinTimePicker({
super.key,
required this.width,
required this.onTimeSelected,
});
final double width;
final ValueChanged<String> onTimeSelected;
@override
State<FixedPinTimePicker> createState() => _FixedPinTimePickerState();
}
class _FixedPinTimePickerState extends State<FixedPinTimePicker> {
final ScrollController _scrollController = ScrollController();
int _currentHighlightedIndex = 0;
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
Widget _buildBar(int index, bool isHighlighted) {
Color barColor = isHighlighted ? Colors.purple : Colors.grey;
if (index % 4 == 0) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
height: 100,
width: 5,
color: barColor,
),
);
} else if (index % 2 == 0) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(height: 70, width: 5, color: barColor),
);
} else {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(height: 50, width: 5, color: barColor),
);
}
}
String _getTimeBasedOnIndex(int index) {
final int hour = index ~/ 2;
final int minute = index % 2 == 0 ? 0 : 30;
return index % 2 == 0 ? '$hour:$minute' : '';
}
void _updateHighlightedIndex() {
double anchorPosition = widget.width / 2; // Center of the widget
double closestDistance = double.infinity;
int closestIndex = 0;
for (int i = 0; i < 49; i++) {
double barPosition = (i * 45) +
5 -
_scrollController.offset; // Assuming each bar has a width of 50
double distance = (barPosition - anchorPosition).abs();
if (distance < closestDistance) {
closestDistance = distance;
closestIndex = i;
}
}
if (_currentHighlightedIndex != closestIndex) {
setState(() {
_currentHighlightedIndex = closestIndex;
});
widget.onTimeSelected(_getTimeBasedOnIndex(closestIndex));
}
}
@override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollUpdateNotification) {
_updateHighlightedIndex();
}
return true;
},
child: SizedBox(
width: widget.width,
height: 150,
child: Stack(
children: [
ListView.builder(
controller: _scrollController,
scrollDirection: Axis.horizontal,
itemCount: 49,
itemBuilder: (context, index) {
bool isHighlighted = index == _currentHighlightedIndex;
return Stack(
children: [
const SizedBox(
height: 10,
),
_buildBar(index, isHighlighted),
const SizedBox(height: 10),
Positioned(
bottom: 0,
child: Text(
_getTimeBasedOnIndex(index),
style: TextStyle(
color: isHighlighted ? Colors.purple : Colors.black,
fontSize: 18,
),
),
),
],
);
},
),
Positioned(
top: -20,
right: widget.width / 2 - 25,
child: const Icon(
Icons.arrow_drop_down,
color: Colors.purple,
size: 50,
),
),
],
),
),
);
}
}
复制并粘贴,如果它适合您,请接受作为答案。我花了很多时间。