diff --git a/lib/src/components/radio/radio.dart b/lib/src/components/radio/radio.dart index 1ac8e8faa..ab5292b10 100644 --- a/lib/src/components/radio/radio.dart +++ b/lib/src/components/radio/radio.dart @@ -5,7 +5,7 @@ import '../../../zeta_flutter.dart'; /// Zeta Radio Button /// -/// Radio Button can select one single option from a goup of different options. +/// Radio Button can select one single option from a group of different options. class ZetaRadio extends StatefulWidget { /// Constructor for [ZetaRadio]. const ZetaRadio({ @@ -44,55 +44,71 @@ class ZetaRadio extends StatefulWidget { } class _ZetaRadioState extends State> with TickerProviderStateMixin, ToggleableStateMixin { - final ToggleablePainter _painter = _RadioPainter(); + ToggleablePainter? _painter; + bool _isHovered = false; @override Widget build(BuildContext context) { final zetaColors = Zeta.of(context).colors; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Semantics( - inMutuallyExclusiveGroup: true, - checked: widget._selected, - selected: value, - child: buildToggleable( - size: const Size(36, 36), - painter: _painter - ..position = position - ..reaction = reaction - ..reactionFocusFade = reactionFocusFade - ..reactionHoverFade = reactionHoverFade - ..inactiveReactionColor = Colors.transparent - ..reactionColor = Colors.transparent - ..hoverColor = Colors.transparent - ..focusColor = zetaColors.blue.shade50 - ..splashRadius = 12 - ..downPosition = downPosition - ..isFocused = states.contains(WidgetState.focused) - ..isHovered = states.contains(WidgetState.hovered) - ..activeColor = states.contains(WidgetState.disabled) ? zetaColors.cool.shade30 : zetaColors.blue.shade60 - ..inactiveColor = - states.contains(WidgetState.disabled) ? zetaColors.cool.shade30 : zetaColors.cool.shade70, - mouseCursor: WidgetStateProperty.all( - WidgetStateProperty.resolveAs( - WidgetStateMouseCursor.clickable, - states, + _painter ??= _RadioPainter(colors: zetaColors); + return Semantics( + inMutuallyExclusiveGroup: true, + checked: widget._selected, + selected: value, + excludeSemantics: true, + child: MouseRegion( + onEnter: (_) => setState(() => _isHovered = true), + onExit: (_) => setState(() => _isHovered = false), + cursor: states.contains(WidgetState.disabled) ? SystemMouseCursors.forbidden : SystemMouseCursors.click, + child: SelectionContainer.disabled( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + buildToggleable( + size: const Size(ZetaSpacing.x9, ZetaSpacing.x9), + painter: _painter! + ..position = position + ..reaction = reaction + ..reactionFocusFade = reactionFocusFade + ..reactionHoverFade = reactionHoverFade + ..inactiveReactionColor = Colors.transparent + ..reactionColor = Colors.transparent + ..hoverColor = Colors.transparent + ..focusColor = zetaColors.blue.shade50 + ..splashRadius = ZetaSpacing.x3 + ..downPosition = downPosition + ..isFocused = states.contains(WidgetState.focused) + ..isHovered = states.contains(WidgetState.hovered) + ..activeColor = _isHovered + ? zetaColors.cool.shade90 + : states.contains(WidgetState.disabled) + ? zetaColors.cool.shade30 + : zetaColors.blue.shade60 + ..inactiveColor = _isHovered + ? zetaColors.cool.shade90 + : states.contains(WidgetState.disabled) + ? zetaColors.cool.shade30 + : states.contains(WidgetState.focused) + ? zetaColors.blue.shade50 + : zetaColors.cool.shade70, + mouseCursor: WidgetStateProperty.all( + states.contains(WidgetState.disabled) ? SystemMouseCursors.forbidden : SystemMouseCursors.click, + ), ), - ), + if (widget.label != null) + GestureDetector( + onTap: () => onChanged?.call(true), + child: DefaultTextStyle( + style: ZetaTextStyles.bodyMedium.copyWith( + color: states.contains(WidgetState.disabled) ? zetaColors.textDisabled : zetaColors.textDefault, + height: 1.33, + ), + child: widget.label!, + ), + ), + ], ), ), - if (widget.label != null) - GestureDetector( - onTap: () => onChanged?.call(true), - child: DefaultTextStyle( - style: ZetaTextStyles.bodyMedium.copyWith( - color: states.contains(WidgetState.disabled) ? zetaColors.textDisabled : zetaColors.textDefault, - height: 1.33, - ), - child: widget.label!, - ), - ), - ], + ), ); } @@ -125,7 +141,7 @@ class _ZetaRadioState extends State> with TickerProviderStateMix @override void dispose() { - _painter.dispose(); + _painter?.dispose(); super.dispose(); } } @@ -134,17 +150,31 @@ const double _kOuterRadius = 10; const double _kInnerRadius = 5; class _RadioPainter extends ToggleablePainter { + _RadioPainter({required this.colors}); + + final ZetaColors colors; + @override void paint(Canvas canvas, Size size) { paintRadialReaction(canvas: canvas, origin: size.center(Offset.zero)); - final Offset center = (Offset.zero & size).center; - // Outer circle + // Background mask for focus final Paint paint = Paint() - ..color = Color.lerp(inactiveColor, activeColor, position.value)! + ..color = colors.surfacePrimary + ..style = PaintingStyle.stroke + ..strokeWidth = ZetaSpacing.x2_5; + if (isFocused) canvas.drawCircle(center, _kInnerRadius, paint); + + // Outer circle + paint + ..color = isHovered + ? colors.black + : position.isDismissed + ? inactiveColor + : activeColor ..style = PaintingStyle.stroke - ..strokeWidth = 2; + ..strokeWidth = ZetaSpacing.x0_5; canvas.drawCircle(center, _kOuterRadius, paint); // Inner circle