* animated_condition_bar.dart
// ignore_for_file: must_be_immutable, unnecessary_null_comparison
import 'package:flutter/material.dart';
import 'package:secondtrack/config/config.dart';
class AnimatedConditionBar extends StatefulWidget {
// int value;
final int value;
final int length;
double? maxWidth;
final String title;
final ValueChanged<int?>? onChanged;
final bool tristate;
AnimatedConditionBar({
Key? key,
this.value = 1,
this.length = 5,
this.maxWidth,
this.title = '',
@required this.onChanged,
this.tristate = false,
}) : assert(tristate != null),
assert(tristate || value != null),
super(key: key);
@override
State<AnimatedConditionBar> createState() => _AnimatedConditionBarState();
}
class _AnimatedConditionBarState extends State<AnimatedConditionBar> {
int delay = 300;
double conditionStatusWidth = 0;
Future resizedConditionStatus(int value) async {
if (value < (widget.value - 1)) {
delay = 300 * (widget.value - 1);
} else {
delay = 300 * (value);
}
await Future.delayed(const Duration(milliseconds: 100), () {
setState(() {
// conditionStatusWidth = SizeConfig.screenWidth - (InnerConfig.large*2);
conditionStatusWidth = (SizeConfig.screenWidth - (InnerConfig.large * 2)) / (widget.length - 1) * (widget.value - 1);
if (conditionStatusWidth == 0) conditionStatusWidth = 1;
});
});
}
void _handleValueChange(int index) {
assert(widget.onChanged != null);
widget.onChanged!(index + 1);
resizedConditionStatus(index);
}
@override
void initState() {
widget.maxWidth ??= SizeConfig.screenWidth - (InnerConfig.large * 2);
resizedConditionStatus(widget.value);
super.initState();
}
@override
Widget build(BuildContext context) {
double btnSize = 40;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.only(
top: 24,
bottom: 5,
left: InnerConfig.normal,
right: InnerConfig.normal,
),
child: Text(
widget.title,
style: const TextStyle(
fontSize: FontConfig.basic,
fontWeight: Weight.Medium,
color: ColorConfig.darkGrey,
),
),
),
Stack(
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: InnerConfig.normal,
horizontal: InnerConfig.large,
),
color: ColorConfig.lightGrey,
child: Column(
children: [
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: SizeConfig.screenWidth - (InnerConfig.large * 2),
height: 2,
color: ColorConfig.grey,
),
AnimatedContainer(
duration: Duration(milliseconds: delay),
curve: Curves.easeOut,
width: conditionStatusWidth,
height: 2,
color: ColorConfig.main,
),
Positioned(
top: -5,
bottom: -5,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < widget.length; i++)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (i != 0)
Container(
width: 5,
color: ColorConfig.lightGrey,
),
AnimatedOpacity(
opacity: conditionStatusWidth == 0 ? 0 : 1,
duration: const Duration(milliseconds: 1000),
curve: Curves.easeOut,
child: ClipOval(
child: Container(
width: 10,
height: 10,
color: widget.value > i ? ColorConfig.main : ColorConfig.grey,
),
),
),
if (i != widget.length - 1)
Container(
width: 5,
color: ColorConfig.lightGrey,
),
],
),
],
),
),
],
),
const SizedBox(height: 10),
AnimatedOpacity(
opacity: conditionStatusWidth == 0 ? 0 : 1,
duration: const Duration(milliseconds: 1000),
curve: Curves.easeOut,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < widget.length; i++) Text('${i + 1}', style: TextStyle(fontSize: FontConfig.info, fontWeight: Weight.Medium, color: widget.value > i ? ColorConfig.main : ColorConfig.grey)),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
vertical: InnerConfig.normal - 18,
horizontal: InnerConfig.large - (btnSize / 2) + 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < widget.length; i++)
ClipRRect(
borderRadius: RadiusConfig.normal,
child: InkWell(
onTap: widget.onChanged != null
? () {
_handleValueChange(i);
}
: null,
borderRadius: BorderRadius.circular(btnSize),
child: Container(
width: btnSize,
height: 60,
color: Colors.transparent,
),
),
),
],
),
),
],
),
],
);
}
}
* 사용
int _value = 0;
.
.
.
AnimatedConditionBar(
value: _value,
length: 5,
title: '제목',
onChanged: (value) {
setState(() {
_value = value!;
});
},
),
'App > Flutter' 카테고리의 다른 글
[ FLUTTER ] GetX 페이지 누적 이동(preventDuplicates) (0) | 2022.02.07 |
---|---|
[ FLUTTER ] launcher icon plugin (0) | 2022.02.03 |
[ FLUTTER ] VScode 지저분한 Dart 코드 Line 정리하기 (2) | 2021.12.23 |
[ FLUTTER ] 패키지 네임 포함 프로젝트 생성 (0) | 2021.12.21 |
[ FLUTTER 커스텀 ] Popup (0) | 2021.12.13 |