CustomSwitch

A highly customizable animated toggle switch with label support and smooth transitions.

Features

  • Enhanced Label Support:

    • Text or custom widget labels
    • Flexible left/right positioning
    • Automatic spacing
  • Smooth Animations:

    • Physics-based toggle movement
    • 200ms optimized duration
    • Alignment-based transition
  • Visual Customization:

    • Dual-state color customization
    • Adjustable sizing parameters
    • Configurable border radius
    • Custom border styling for each state

Installation

Add the dependency to your pubspec.yaml:

dependencies:
  apptomate_custom_switch: ^0.0.2

Basic Usage

bool isActive = false;

// Minimal implementation
CustomSwitch(
  value: isActive,
  onToggle: (value) => setState(() => isActive = value),
)

// With text label
CustomSwitch(
  value: isActive,
  onToggle: (value) => setState(() => isActive = value),
  label: "Enable Feature",
)

// With custom label widget
CustomSwitch(
  value: isActive,
  onToggle: (value) => setState(() => isActive = value),
  labelWidget: Row(
    children: [
      Icon(Icons.power_settings_new),
      Text("Power Mode"),
    ],
  ),
  labelPosition: LabelPosition.left,
)

Complete Example

class SwitchExample extends StatefulWidget {
  @override
  _SwitchExampleState createState() => _SwitchExampleState();
}

class _SwitchExampleState extends State<SwitchExample> {
  bool _darkMode = false;
  bool _notifications = true;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        CustomSwitch(
          value: _darkMode,
          onToggle: (val) => setState(() => _darkMode = val),
          label: "Dark Mode",
          activeColor: Colors.black45,
          inactiveColor: Colors.grey[200]!,
          activeToggleColor: Colors.black,
          inactiveToggleColor: Colors.white,
          width: 50,
          height: 30,
        ),
        
        const SizedBox(height: 20),
        
        CustomSwitch(
          value: _notifications,
          onToggle: (val) => setState(() => _notifications = val),
          labelWidget: Row(
            children: [
              Icon(Icons.notifications, size: 18),
              const SizedBox(width: 4),
              const Text("Notifications"),
            ],
          ),
          labelPosition: LabelPosition.left,
          activeColor: Colors.blue[100]!,
          activeToggleColor: Colors.blue,
        ),
      ],
    );
  }
}

Parameter Reference

Core Properties

Parameter Type Required Description
value bool Yes Current switch state
onToggle ValueChanged<bool> Yes State change callback

Label Options

Parameter Type Default Description
label String? null Text label
labelWidget Widget? null Custom label widget
labelPosition LabelPosition right Label position

Color Customization

Parameter Type Default Description
activeColor Color Colors.grey Active background
inactiveColor Color Colors.grey Inactive background
activeToggleColor Color Colors.blue Active toggle color
inactiveToggleColor Color Colors.white Inactive toggle color

Size Customization

Parameter Type Default Description
width double 30.0 Switch width
height double 21.3 Switch height
toggleSize double 11.0 Toggle circle size
borderRadius double 30.0 Container border radius
padding double 3.0 Inner padding

Border Customization

Parameter Type Default Description
activeBorder Border? null Active state border
inactiveBorder Border? null Inactive state border

Advanced Usage

Custom Border Example

CustomSwitch(
  value: _isPremium,
  onToggle: (val) => setState(() => _isPremium = val),
  activeBorder: Border.all(color: Colors.amber, width: 1.5),
  inactiveBorder: Border.all(color: Colors.grey, width: 1),
)

Label Positioning

Row(
  children: [
    CustomSwitch(
      value: _leftAligned,
      onToggle: (val) => setState(() => _leftAligned = val),
      label: "Left Label",
      labelPosition: LabelPosition.left,
    ),
    Spacer(),
    CustomSwitch(
      value: _rightAligned,
      onToggle: (val) => setState(() => _rightAligned = val),
      label: "Right Label",
    ),
  ],
)

Complex Label Widget

CustomSwitch(
  value: _advanced,
  onToggle: (val) => setState(() => _advanced = val),
  labelWidget: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text("Advanced Mode", style: TextStyle(fontWeight: FontWeight.bold)),
      Text("Enable experimental features", 
           style: TextStyle(fontSize: 12, color: Colors.grey)),
    ],
  ),
)

Best Practices

  1. Size Proportions:

    • Maintain toggleSize < height - (padding * 2)
    • Recommended width/height ratio ≈ 1.4:1
  2. Color Contrast:

    • Ensure toggle is visible against background
    • Follow WCAG contrast guidelines
  3. Label Clarity:

    • Use short, descriptive labels
    • Consider icons for quick recognition
  4. State Management:

    • Connect to app state when needed
    • Consider debouncing for rapid toggles

Troubleshooting

Toggle not animating:

  • Verify onToggle updates the state
  • Check animation controller initialization

Label not appearing:

  • Ensure either label or labelWidget is provided
  • Verify there's space in the layout

Visual glitches:

  • Check size proportions
  • Ensure border radius <= height/2