advance_ruler_slider 0.0.1 copy "advance_ruler_slider: ^0.0.1" to clipboard
advance_ruler_slider: ^0.0.1 copied to clipboard

A highly customizable and reusable Flutter ruler/scale slider widget with optional haptic feedback, scroll animations, and custom indicator support.

📏 Advance Ruler Slider

A highly customizable and reusable Flutter ruler/scale slider widget designed for precise value selection. This package offers a flexible and visually rich UI component that can be adapted to a wide range of applications, from health trackers to audio editors.

✨ Features

The advance_ruler_slider comes packed with a wide array of features to give you full control over its appearance and behavior:

Customizable Value Range: Easily define the minValue and maxValue for your ruler.

Granular Tick Control:

Set majorTickInterval for primary markers (e.g., every 10 units).

Control minorTickCount between major ticks for finer subdivisions.

Customize majorTickColor, minorTickColor, majorTickWidth, minorTickWidth, majorTickLength, and minorTickLength.

Choose the tickStrokeCap (e.g., StrokeCap.round, StrokeCap.square) for tick ends.

Directional Flexibility: Render the ruler as either Axis.horizontal or Axis.vertical.

Dynamic Value Display:

Central Indicator: A prominent indicator at the center of the ruler's viewport.

Optional Numeric Value: Toggle the visibility of the numeric value displayed at the indicator using showIndicatorValue.

Customizable Indicator:

Define indicatorColor and indicatorWidth.

Apply indicatorGradient for a visually rich indicator (overrides indicatorColor).

Add an optional triangular pointer/arrow using showIndicatorPointer, with customizable indicatorPointerLength, indicatorPointerWidth, and indicatorPointerColor.

Full Customization: Provide your own customIndicator widget for ultimate design freedom (overrides all default indicator styling).

Background Styling:

Set a solid backgroundColor.

Apply a backgroundGradient for dynamic backgrounds (overrides backgroundColor).

Add borderRadius to the ruler's container for rounded corners.

User Interaction & Feedback:

Smooth Scroll Animations: Programmatic jumps (jumpToValue) and initial scroll can use animateTo for smooth transitions by setting useScrollAnimation to true. Customize scrollAnimationDuration and scrollAnimationCurve.

Haptic Feedback: Enable hapticFeedbackEnabled to provide tactile feedback (HapticFeedback.selectionClick()) whenever the ruler's value changes.

Read-Only Mode: Disable user scrolling interaction with isReadOnly, while still allowing programmatic control.

Custom Scroll Physics: Apply any ScrollPhysics (e.g., BouncingScrollPhysics, ClampingScrollPhysics) using the scrollPhysics property.

Snap to Ticks on Release: Automatically animate the ruler to snap its indicator to the nearest major or minor tick after a user completes a scroll gesture using snapToTicksOnRelease.

Label Customization:

Define labelStyle for the tick labels.

Provide a labelFormatter function for advanced text formatting (e.g., adding units, custom text).

Adjust labelOffset to control the spacing between tick marks and their labels.

Option to always show minValue and maxValue labels, even if they don't align with major ticks, using showBoundaryLabels.

Active Range Highlighting: Visually highlight the currently visible portion of the ruler with activeRangeColor and activeRangeOpacity.

Scrollable Value Clamping: Restrict the effective scrollable range of the ruler using minScrollValue and maxScrollValue, which can be a sub-range of minValue and maxValue.

📦 Installation

To use this package, add advance_ruler_slider to your pubspec.yaml file:

dependencies: advance_ruler_slider: ^0.0.1 # Always use the latest version

Then, run flutter pub get in your project's root directory.

🚀 Basic Usage

Here's a simple example demonstrating a horizontal weight ruler:

import 'package:flutter/material.dart'; import 'package:advance_ruler_slider/advance_ruler_slider.dart'; // Import your package

class BasicRulerDemo extends StatefulWidget { const BasicRulerDemo({super.key});

@override State

class _BasicRulerDemoState extends State

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Basic Ruler Slider Demo'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Selected Weight: ${_currentWeight.toStringAsFixed(1)} kg', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 30), Container( height: 80, // Height for the horizontal ruler margin: const EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(15), border: Border.all(color: Colors.blue.shade200, width: 2), ), child: RulerScale( controller: _weightRulerController, minValue: 0.0, maxValue: 150.0, initialValue: _currentWeight, majorTickInterval: 10.0, minorTickCount: 9, // 9 minor ticks means 10 segments (1.0 granularity) pixelsPerUnit: 25.0, // Adjust for desired spacing indicatorColor: Colors.blueAccent, indicatorWidth: 3.0, labelStyle: const TextStyle(color: Colors.black87, fontSize: 13), onValueChanged: (value) { setState(() { _currentWeight = value; }); }, showIndicatorPointer: true, indicatorPointerLength: 12.0, indicatorPointerWidth: 12.0, indicatorPointerColor: Colors.blueAccent, hapticFeedbackEnabled: true, useScrollAnimation: true, borderRadius: BorderRadius.circular(15), ), ), const SizedBox(height: 30), ElevatedButton( onPressed: () { _weightRulerController.jumpToValue(95.0); // Programmatic jump }, child: const Text('Jump to 95.0 kg'), ), ], ), ), ); } }

// To run this example, replace your main.dart content with: // void main() { // runApp(const MaterialApp(home: BasicRulerDemo())); // }

🖼️ Screenshots / GIFs

(Replace this section with actual screenshots or GIFs of your ruler in action. This is crucial for attracting users!)

⚙️ Advanced Usage & Customization Examples

The RulerScale widget is highly configurable. Here are more examples demonstrating various properties:

Vertical Ruler with Custom Formatting and Physics

import 'package:flutter/material.dart'; import 'package:advance_ruler_slider/advance_ruler_slider.dart';

class AdvancedVerticalRuler extends StatefulWidget { const AdvancedVerticalRuler({super.key});

@override State

class _AdvancedVerticalRulerState extends State

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Vertical Ruler Demo')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Selected Height: ${_currentHeight.toStringAsFixed(1)}m', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 20), Container( width: 100, // Width for the vertical ruler height: 300, // Height for the vertical ruler decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(10), gradient: LinearGradient( colors: [Colors.green.shade100, Colors.green.shade300], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: RulerScale( direction: Axis.vertical, minValue: 0.0, maxValue: 20.0, majorTickInterval: 5.0, minorTickCount: 4, // 4 minor ticks = 5 segments between major ticks (0.5 granularity) pixelsPerUnit: 50.0, // More space for vertical ruler initialValue: _currentHeight, indicatorColor: Colors.green.shade700, indicatorWidth: 3.0, rulerExtent: 80.0, // Width of the ruler component itself labelStyle: const TextStyle(color: Colors.green, fontSize: 14), onValueChanged: (value) { setState(() { _currentHeight = value; }); }, showIndicatorValue: true, showIndicatorPointer: true, indicatorPointerLength: 15.0, indicatorPointerWidth: 15.0, indicatorPointerColor: Colors.green.shade900, hapticFeedbackEnabled: true, labelFormatter: (value) { if (value == 0) return 'Start'; if (value == 20) return 'End'; return '${value.toStringAsFixed(1)}m'; // Custom unit }, activeRangeColor: Colors.green, activeRangeOpacity: 0.1, showBoundaryLabels: true, onScrollStart: () => print('Vertical ruler scroll started!'), onScrollEnd: () => print('Vertical ruler scroll ended!'), snapToTicksOnRelease: true, // Snap to nearest tick after scroll scrollPhysics: const BouncingScrollPhysics(), // iOS-like bounce indicatorGradient: LinearGradient( colors: [Colors.lime.shade200, Colors.lime.shade700], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), minScrollValue: 5.0, // User can only scroll between 5.0 and 15.0 maxScrollValue: 15.0, ), ), ], ), ), ); } }

// To run this example, replace your main.dart content with: // void main() { // runApp(const MaterialApp(home: AdvancedVerticalRuler())); // }

Ruler with a Custom Indicator Widget

import 'package:flutter/material.dart'; import 'package:advance_ruler_slider/advance_ruler_slider.dart';

class CustomIndicatorRuler extends StatefulWidget { const CustomIndicatorRuler({super.key});

@override State

class _CustomIndicatorRulerState extends State

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Custom Indicator Demo')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Selected Value: ${_currentValue.toStringAsFixed(0)}%', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 30), Container( height: 100, margin: const EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(15), ), child: RulerScale( direction: Axis.horizontal, minValue: 0.0, maxValue: 100.0, majorTickInterval: 25.0, minorTickCount: 4, pixelsPerUnit: 40.0, initialValue: _currentValue, rulerExtent: 70.0, labelStyle: const TextStyle(color: Colors.orange, fontSize: 14), onValueChanged: (value) { setState(() { _currentValue = value; }); }, // Provide a custom indicator widget customIndicator: Container( width: 40, height: 40, decoration: BoxDecoration( color: Colors.orange.shade700, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 5, spreadRadius: 2, ), ], ), child: const Icon(Icons.star, color: Colors.white, size: 24), ), showIndicatorValue: true, // Value will still appear below custom indicator labelOffset: 10.0, // Adjust label offset if needed ), ), ], ), ), ); } }

// To run this example, replace your main.dart content with: // void main() { // runApp(const MaterialApp(home: CustomIndicatorRuler())); // }

Read-Only Ruler

import 'package:flutter/material.dart'; import 'package:advance_ruler_slider/advance_ruler_slider.dart';

class ReadOnlyRulerDemo extends StatefulWidget { const ReadOnlyRulerDemo({super.key});

@override State

class _ReadOnlyRulerDemoState extends State

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Read-Only Ruler Demo')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Display Value: ${_displayValue.toStringAsFixed(1)}', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 30), Container( height: 80, margin: const EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey.shade300, width: 1), ), child: RulerScale( controller: _readOnlyRulerController, minValue: 0.0, maxValue: 200.0, initialValue: _displayValue, majorTickInterval: 20.0, minorTickCount: 9, pixelsPerUnit: 15.0, indicatorColor: Colors.purple, labelStyle: const TextStyle(color: Colors.black54, fontSize: 12), isReadOnly: true, // Make the ruler read-only showIndicatorValue: true, showIndicatorPointer: true, indicatorPointerColor: Colors.purple, hapticFeedbackEnabled: false, // No haptic feedback for read-only ), ), const SizedBox(height: 30), ElevatedButton( onPressed: () { // You can still programmatically change the value setState(() { _displayValue = (_displayValue + 10).clamp(0.0, 200.0); }); _readOnlyRulerController.jumpToValue(_displayValue); }, child: const Text('Increment Value'), ), ], ), ), ); } }

// To run this example, replace your main.dart content with: // void main() { // runApp(const MaterialApp(home: ReadOnlyRulerDemo())); // }

📚 API Reference

Here's a quick overview of the available properties for the RulerScale widget:

Property

Type

Default Value

Description

minValue

double

0.0

The minimum value of the ruler.

maxValue

double

100.0

The maximum value of the ruler.

majorTickInterval

double

10.0

The interval between major ticks (e.g., 10.0 for every 10 units).

minorTickCount

int

9

The number of minor ticks between major ticks. (9 minor ticks means 10 segments).

direction

Axis

Axis.horizontal

The orientation of the ruler (Axis.horizontal or Axis.vertical).

majorTickColor

Color

Colors.black

Color of the major ticks.

minorTickColor

Color

Colors.grey

Color of the minor ticks.

majorTickWidth

double

2.0

Width of the major ticks.

minorTickWidth

double

1.0

Width of the minor ticks.

majorTickLength

double

20.0

Length of the major ticks.

minorTickLength

double

10.0

Length of the minor ticks.

labelStyle

TextStyle

TextStyle(...)

Text style for the labels displayed on major ticks.

indicatorColor

Color

Colors.red

Color of the central indicator line. Ignored if customIndicator or indicatorGradient is provided.

indicatorWidth

double

2.0

Width of the central indicator line.

backgroundColor

Color

Colors.white

Background color of the ruler. Ignored if backgroundGradient is provided.

rulerExtent

double

60.0

The fixed dimension of the ruler (height for horizontal, width for vertical).

onValueChanged

ValueChanged

null

Callback triggered when the value at the center of the ruler changes (during scroll and on jump).

onScrollStart

VoidCallback?

null

Callback triggered when user scrolling starts.

onScrollEnd

VoidCallback?

null

Callback triggered when user scrolling stops.

initialValue

double

0.0

The initial value to set the ruler to.

pixelsPerUnit

double

20.0

How many pixels represent one unit of value. Controls ruler density/spacing. Increase this value to make the ruler appear more spread out and allow for finer manual control.

step

double

1.0

The smallest logical increment for the ruler's value. The displayed value will snap to multiples of this step.

controller

RulerScaleController?

null

An optional controller to programmatically control the ruler (e.g., jumpToValue).

showIndicatorValue

bool

true

Whether to show the numeric value at the indicator.

showIndicatorPointer

bool

false

Whether to show a triangular pointer on the indicator. Ignored if customIndicator is provided.

indicatorPointerLength

double

10.0

The length (height) of the triangular pointer.

indicatorPointerWidth

double

10.0

The width (base) of the triangular pointer.

indicatorPointerColor

Color?

null

The color of the indicator pointer. Defaults to indicatorColor if null.

useScrollAnimation

bool

false

Whether to use smooth animation for programmatic jumps and initial scroll.

scrollAnimationDuration

Duration

Duration(300ms)

The duration of the scroll animation when useScrollAnimation is true.

scrollAnimationCurve

Curve

Curves.easeOutCubic

The curve of the scroll animation when useScrollAnimation is true.

hapticFeedbackEnabled

bool

false

Whether to enable haptic feedback (HapticFeedback.selectionClick()) when the value changes.

borderRadius

BorderRadiusGeometry?

null

The border radius for the ruler's background container.

isReadOnly

bool

false

Whether the ruler is read-only (disables user scrolling).

labelFormatter

String Function(double)?

null

A custom function to format the labels displayed on the ticks.

activeRangeColor

Color?

null

The color to use for highlighting the currently visible range. If null, no highlight.

activeRangeOpacity

double

0.2

The opacity of the active range highlight (0.0 to 1.0).

showBoundaryLabels

bool

false

Whether to always show labels for minValue and maxValue.

scrollPhysics

ScrollPhysics?

null

Custom scroll physics for the SingleChildScrollView (e.g., BouncingScrollPhysics).

customIndicator

Widget?

null

A custom widget to use as the indicator. Overrides default indicator styling.

labelOffset

double

5.0

The offset from the tick mark where the label should be painted.

tickStrokeCap

StrokeCap

StrokeCap.round

The stroke cap style for the tick marks.

backgroundGradient

Gradient?

null

A gradient to use for the background of the ruler. Overrides backgroundColor.

indicatorGradient

Gradient?

null

A gradient to use for the default line indicator. Overrides indicatorColor.

minScrollValue

double?

null (uses minValue)

The minimum value that the ruler can scroll to or report. Clamps the effective scrollable range.

maxScrollValue

double?

null (uses maxValue)

The maximum value that the ruler can scroll to or report. Clamps the effective scrollable range.

snapToTicksOnRelease

bool

false

If true, the ruler will animate to snap its indicator to the nearest major or minor tick after a user finishes scrolling.

🤝 Contributing

Contributions are welcome! If you find a bug, have a feature request, or want to contribute code, please feel free to:

Open an issue: Describe the bug or feature you'd like to see.

Submit a pull request: Fork the repository, make your changes, and submit a pull request.

Please ensure your code adheres to the existing style and includes relevant tests.

📄 License

This package is distributed under the MIT License. See the LICENSE file for more information.

2
likes
0
points
32
downloads

Publisher

unverified uploader

Weekly Downloads

A highly customizable and reusable Flutter ruler/scale slider widget with optional haptic feedback, scroll animations, and custom indicator support.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on advance_ruler_slider