Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added rounded stroke cap option #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ ios/Flutter/Generated.xcconfig
ios/Runner/GeneratedPluginRegistrant.*

./idea/
/.idea/
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# circular_check_box

A modifed version of the exisiting checkbox to use a circle instead of a rounded rectangle!
A modified version of the existing checkbox to use a circle instead of a rounded rectangle!

![](https://media.giphy.com/media/1ppul2n7LpKNZieMp1/giphy.gif "Example")

```Dart
CircularCheckBox(
value: someBooleanValue,
materialTapTargetSize: MaterialTapTargetSize.padded,
onChanged: (bool x) {
someBooleanValue = !someBooleanValue;
}
),
value: someBooleanValue,
materialTapTargetSize: MaterialTapTargetSize.padded,
onChanged: (bool x) {
someBooleanValue = !someBooleanValue;
}
),

```

## TO-DO
- Fix/Update the documentaions
- Fix/Update the documentation
- ??


146 changes: 85 additions & 61 deletions lib/circular_check_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

// Modified by Mash Ibtesum
// Modified by Lorenzo Calisti
// Modified by Ben Stein

library circular_check_box;

Expand Down Expand Up @@ -54,10 +55,11 @@ class CircularCheckBox extends StatefulWidget {
this.visualDensity,
this.focusNode,
this.autofocus = false,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(autofocus != null),
super(key: key);
this.roundedCap = false,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(autofocus != null),
super(key: key);

/// Whether this checkbox is checked.
///
Expand Down Expand Up @@ -156,6 +158,11 @@ class CircularCheckBox extends StatefulWidget {
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;

/// If true the checkbox stroke will be rounded at both ends.
///
/// Defaults to false.
final bool roundedCap;

/// The width of a checkbox widget.
static const double width = 18.0;

Expand All @@ -175,7 +182,7 @@ class _CircularCheckBoxState extends State<CircularCheckBox> with TickerProvider
};
}

void _actionHandler(ActivateIntent intent){
void _actionHandler(ActivateIntent intent) {
if (widget.onChanged != null) {
switch (widget.value) {
case false:
Expand All @@ -196,14 +203,18 @@ class _CircularCheckBoxState extends State<CircularCheckBox> with TickerProvider
bool _focused = false;
void _handleFocusHighlightChanged(bool focused) {
if (focused != _focused) {
setState(() { _focused = focused; });
setState(() {
_focused = focused;
});
}
}

bool _hovering = false;
void _handleHoverChanged(bool hovering) {
if (hovering != _hovering) {
setState(() { _hovering = hovering; });
setState(() {
_hovering = hovering;
});
}
}

Expand All @@ -214,13 +225,15 @@ class _CircularCheckBoxState extends State<CircularCheckBox> with TickerProvider
Size size;
switch (widget.materialTapTargetSize ?? themeData.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
size = const Size(2 * kRadialReactionRadius + 8.0, 2 * kRadialReactionRadius + 8.0);
size = const Size(
2 * kRadialReactionRadius + 8.0, 2 * kRadialReactionRadius + 8.0);
break;
case MaterialTapTargetSize.shrinkWrap:
size = const Size(2 * kRadialReactionRadius, 2 * kRadialReactionRadius);
break;
}
size += (widget.visualDensity ?? themeData.visualDensity).baseSizeAdjustment;
size +=
(widget.visualDensity ?? themeData.visualDensity).baseSizeAdjustment;
final BoxConstraints additionalConstraints = BoxConstraints.tight(size);
return FocusableActionDetector(
actions: _actionMap,
Expand All @@ -236,16 +249,17 @@ class _CircularCheckBoxState extends State<CircularCheckBox> with TickerProvider
tristate: widget.tristate,
activeColor: widget.activeColor ?? themeData.toggleableActiveColor,
checkColor: widget.checkColor ?? const Color(0xFFFFFFFF),
inactiveColor: enabled ?
widget.inactiveColor ?? themeData.unselectedWidgetColor:
widget.disabledColor ?? themeData.disabledColor,
inactiveColor: enabled
? widget.inactiveColor ?? themeData.unselectedWidgetColor
: widget.disabledColor ?? themeData.disabledColor,
focusColor: widget.focusColor ?? themeData.focusColor,
hoverColor: widget.hoverColor ?? themeData.hoverColor,
onChanged: widget.onChanged,
additionalConstraints: additionalConstraints,
vsync: this,
hasFocus: _focused,
hovering: _hovering,
roundedCap: widget.roundedCap ?? false,
);
},
),
Expand All @@ -268,17 +282,19 @@ class _CircularCheckBoxRenderObjectWidget extends LeafRenderObjectWidget {
@required this.additionalConstraints,
@required this.hasFocus,
@required this.hovering,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(activeColor != null),
assert(inactiveColor != null),
assert(vsync != null),
super(key: key);
@required this.roundedCap,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(activeColor != null),
assert(inactiveColor != null),
assert(vsync != null),
super(key: key);

final bool value;
final bool tristate;
final bool hasFocus;
final bool hovering;
final bool roundedCap;
final Color activeColor;
final Color checkColor;
final Color inactiveColor;
Expand All @@ -289,23 +305,26 @@ class _CircularCheckBoxRenderObjectWidget extends LeafRenderObjectWidget {
final BoxConstraints additionalConstraints;

@override
_RenderCircularCheckBox createRenderObject(BuildContext context) => _RenderCircularCheckBox(
value: value,
tristate: tristate,
activeColor: activeColor,
checkColor: checkColor,
inactiveColor: inactiveColor,
focusColor: focusColor,
hoverColor: hoverColor,
onChanged: onChanged,
vsync: vsync,
additionalConstraints: additionalConstraints,
hasFocus: hasFocus,
hovering: hovering,
);
_RenderCircularCheckBox createRenderObject(BuildContext context) =>
_RenderCircularCheckBox(
value: value,
tristate: tristate,
activeColor: activeColor,
checkColor: checkColor,
inactiveColor: inactiveColor,
focusColor: focusColor,
hoverColor: hoverColor,
onChanged: onChanged,
vsync: vsync,
additionalConstraints: additionalConstraints,
hasFocus: hasFocus,
hovering: hovering,
roundedCap: roundedCap,
);

@override
void updateRenderObject(BuildContext context, _RenderCircularCheckBox renderObject) {
void updateRenderObject(
BuildContext context, _RenderCircularCheckBox renderObject) {
renderObject
..value = value
..tristate = tristate
Expand Down Expand Up @@ -338,29 +357,30 @@ class _RenderCircularCheckBox extends RenderToggleable {
ValueChanged<bool> onChanged,
bool hasFocus,
bool hovering,
this.roundedCap,
@required TickerProvider vsync,
}) : _oldValue = value,
super(
value: value,
tristate: tristate,
activeColor: activeColor,
inactiveColor: inactiveColor,
focusColor: focusColor,
hoverColor: hoverColor,
onChanged: onChanged,
additionalConstraints: additionalConstraints,
vsync: vsync,
hasFocus: hasFocus,
hovering: hovering,
);
}) : _oldValue = value,
super(
value: value,
tristate: tristate,
activeColor: activeColor,
inactiveColor: inactiveColor,
focusColor: focusColor,
hoverColor: hoverColor,
onChanged: onChanged,
additionalConstraints: additionalConstraints,
vsync: vsync,
hasFocus: hasFocus,
hovering: hovering,
);

bool _oldValue;
Color checkColor;
bool roundedCap;

@override
set value(bool newValue) {
if (newValue == value)
return;
if (newValue == value) return;
_oldValue = value;
super.value = newValue;
}
Expand All @@ -376,21 +396,23 @@ class _RenderCircularCheckBox extends RenderToggleable {
Color _colorAt(double t) {
// As t goes from 0.0 to 0.25, animate from the inactiveColor to activeColor.
return onChanged == null
? inactiveColor
: (t >= 0.25
? activeColor
: Color.lerp(inactiveColor, activeColor, t * 4.0));
? inactiveColor
: (t >= 0.25
? activeColor
: Color.lerp(inactiveColor, activeColor, t * 4.0));
}

// checkColor stroke used to paint the check and dash.
Paint _createStrokePaint() {
return Paint()
..color = checkColor
..style = PaintingStyle.stroke
..strokeCap = roundedCap ? StrokeCap.round : StrokeCap.butt
..strokeWidth = _kStrokeWidth;
}

void _drawCircleBorder(Canvas canvas, Offset center, double radius, double t, Paint paint) {
void _drawCircleBorder(
Canvas canvas, Offset center, double radius, double t, Paint paint) {
assert(t >= 0.0 && t <= 0.5);
paint
..strokeWidth = _kStrokeWidth
Expand Down Expand Up @@ -439,11 +461,13 @@ class _RenderCircularCheckBox extends RenderToggleable {
paintRadialReaction(canvas, offset, size.center(Offset.zero));

final Paint strokePaint = _createStrokePaint();
final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0 as Offset);
final Offset origin =
offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0 as Offset);
final AnimationStatus status = position.status;
final double tNormalized = status == AnimationStatus.forward || status == AnimationStatus.completed
? position.value
: 1.0 - position.value;
final double tNormalized =
status == AnimationStatus.forward || status == AnimationStatus.completed
? position.value
: 1.0 - position.value;
final Offset center = (offset & size).center;

// Four cases: false to null, false to true, null to false, true to false
Expand All @@ -454,7 +478,7 @@ class _RenderCircularCheckBox extends RenderToggleable {
if (t <= 0.5) {
_drawCircleBorder(canvas, center, 11, t, paint);
} else {
canvas.drawCircle(center, 13, paint);
canvas.drawCircle(center, 12, paint);

final double tShrink = (t - 0.5) * 2.0;
if (_oldValue == null || value == null)
Expand All @@ -464,7 +488,7 @@ class _RenderCircularCheckBox extends RenderToggleable {
}
} else {
// Two cases: null to true, true to null
final Paint paint = Paint() ..color = _colorAt(1.0);
final Paint paint = Paint()..color = _colorAt(1.0);
canvas.drawCircle(center, 12, paint);

if (tNormalized <= 0.5) {
Expand All @@ -482,4 +506,4 @@ class _RenderCircularCheckBox extends RenderToggleable {
}
}
}
}
}