Logo

dev-resources.site

for different kinds of informations.

Flutter. A Quarter Round Slider.

Published at
5/12/2020
Categories
flutter
slider
custompainter
Author
cat_yena
Categories
3 categories in total
flutter
open
slider
open
custompainter
open
Author
8 person written this
cat_yena
open
Flutter. A Quarter Round Slider.

Introduction

This post describes the process of creating a custom slider that can be used to select a value from a range of them. The slider resembles the quarter of a circle instead of the typical linear shape.

Custom Painter

Obviously I will need to paint a custom component and this should be done using two Flutter API classes. CustomPainter and CustomPaint.

CustomPainter You must extend this class and overwrite the method void paint(Canvas, Size) in order to draw the Widget UI and bool shouldRepaint(CustomPainter) method to return true if the widget should be repainted when a new instance of CustomPainter is provided.

CustomPaint The class CustomPainter described above is used through the CustomPaint Widget. CustomPaint takes a constructor parameter named painter for this purpose.

The process is quite simple and can be applied to both simple projects like these and larger, more complex components.

Skeleton example

The classes used in the example are:

  1. MyApp extends StatelessWidget. A Stateless Widget which contains the MaterialApp, Scaffold Widgets of the Application.
  2. RoundSlider extends StatefulWidget. Statefull Widget class of the component.
  3. _RoundSliderState extends State Representing the state of the RoundSlider Widget .
  4. RoundPainter extends CustomPainter. The class which paints the UI.

Class MyApp

It's a stateful widget which launches the application and passes to the slider the constructor parameters title, radius and maxvalue which are self-described.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
 return   MaterialApp(
     home: Scaffold(
         appBar: AppBar(title: Text("Example")),
         body: Center(
             child: RoundSlider(
                 title: "Volume", radius: 90, maxvalue: 99))));
  }
}
Enter fullscreen mode Exit fullscreen mode


`

Classes RoundSlider and RoundSliderState

RoundSlider is the main slider Widget. Its a stateful widget and its state class named RoundSliderState returns into the building method, a GestureDetector which captures drag movements and calculates the proper angle.

Notice that the angle is limited in code to the range 0 to pi/2

The GestureDetector wraps an instance of RoundPainter that we will analyze later.

`

class RoundSlider extends StatefulWidget {
  final double radius;
  final double maxvalue;
  final String title;

  RoundSlider({this.radius, this.maxvalue, this.title});
  @override
  _RoundSliderState createState() => _RoundSliderState();
}

class _RoundSliderState extends State<RoundSlider> {
  double angle = 0;

  void _update(u) {
    setState(() {
      double testAngle = atan2(u.localPosition.dy, u.localPosition.dx);

      if (testAngle >= 0 && testAngle <= pi / 2) {
        setState(() {
          angle = testAngle;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onHorizontalDragUpdate: (update) {
          _update(update);
        },
        onVerticalDragUpdate: (update) {
          _update(update);
        },
        child: Column(children: <Widget>[
          Text(widget.title,textScaleFactor: widget.radius/60,),
          Container(
            padding: EdgeInsets.all(widget.radius * 0.20),
            width: widget.radius + widget.radius * 0.20,
            height: widget.radius + widget.radius * 0.20,
            decoration: BoxDecoration(border: Border.all()),
            child: CustomPaint(
                painter: RoundPainter(angle: angle, maxvalue: widget.maxvalue)),
          ),
        ]));
  }
}
Enter fullscreen mode Exit fullscreen mode


`

Class RoundPainter

The constructor takes the parameter angle in order to calculate the coordinates x,y of the selector and the parameter maxvalue to calculate the actual value selected.

Values like strokeWidth, textScaleFactor, etc...are calculated proportionally to width value of the component.

`

class RoundPainter extends CustomPainter {
  double angle;
  double maxvalue;
  Paint strokePaint = Paint()..style = PaintingStyle.stroke;

  Paint fillPaint = Paint()
    ..style = PaintingStyle.fill
    ..color = Colors.white;

  RoundPainter({this.angle, this.maxvalue});

  Offset offset = Offset(0, 0);

  @override
  void paint(Canvas canvas, Size size) {
    strokePaint.strokeWidth = size.width / 25;

    canvas.drawArc(Rect.fromCircle(center: offset, radius: size.width), 0,
        pi / 2, false, strokePaint);

    _drawSelector(canvas, size, angle);
    _drawValue(canvas, size, (maxvalue * angle / pi).round());
  }

  void _drawValue(Canvas canvas, Size size, int value) {
    TextSpan span = new TextSpan(
        style: new TextStyle(color: Colors.black), text: value.toString());
    TextPainter tp = TextPainter(
        text: span,
        textDirection: TextDirection.ltr,
        textAlign: TextAlign.left,
        textScaleFactor: size.width / 40);
    tp.layout(minWidth: 0);
    Offset newOffset = Offset(offset.dx, offset.dy);
    tp.paint(canvas, newOffset);
  }

  void _drawSelector(Canvas canvas, Size size, double angle) {
    strokePaint.strokeWidth = 1;
    double x = size.width * cos(angle);
    double y = size.height * sin(angle);
    canvas.drawCircle(Offset(x, y), size.width / 10, fillPaint);
    canvas.drawCircle(Offset(x, y), size.height / 10, strokePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
Enter fullscreen mode Exit fullscreen mode


`

All the code

The rest of the code...
`

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
 return   MaterialApp(
     home: Scaffold(
         appBar: AppBar(title: Text("Example")),
         body: Center(
             child: RoundSlider(
                 title: "Volume", radius: 90, maxvalue: 99))));
  }
}


class RoundSlider extends StatefulWidget {
  double radius;
  double maxvalue;
  String title;

  RoundSlider({this.radius, this.maxvalue, this.title});
  @override
  _RoundSliderState createState() => _RoundSliderState();
}

class _RoundSliderState extends State<RoundSlider> {
  double angle = 0;

  void _update(u) {
    setState(() {
      double testAngle = atan2(u.localPosition.dy, u.localPosition.dx);

      if (testAngle >= 0 && testAngle <= pi / 2) {
        setState(() {
          angle = testAngle;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onHorizontalDragUpdate: (update) {
          _update(update);
        },
        onVerticalDragUpdate: (update) {
          _update(update);
        },
        child: Column(children: <Widget>[
          Text(widget.title,textScaleFactor: widget.radius/60,),
          Container(
            padding: EdgeInsets.all(widget.radius * 0.20),
            width: widget.radius + widget.radius * 0.20,
            height: widget.radius + widget.radius * 0.20,
            decoration: BoxDecoration(border: Border.all()),
            child: CustomPaint(
                painter: RoundPainter(angle: angle, maxvalue: widget.maxvalue)),
          ),
        ]));
  }
}

class RoundPainter extends CustomPainter {
  double angle;
  double maxvalue;
  Paint strokePaint = Paint()..style = PaintingStyle.stroke;

  Paint fillPaint = Paint()
    ..style = PaintingStyle.fill
    ..color = Colors.white;

  RoundPainter({this.angle, this.maxvalue});

  Offset offset = Offset(0, 0);

  @override
  void paint(Canvas canvas, Size size) {
    strokePaint.strokeWidth = size.width / 25;

    canvas.drawArc(Rect.fromCircle(center: offset, radius: size.width), 0,
        pi / 2, false, strokePaint);

    _drawSelector(canvas, size, angle);
    _drawValue(canvas, size, (maxvalue * angle / pi).round());
  }

  void _drawValue(Canvas canvas, Size size, int value) {
    TextSpan span = new TextSpan(
        style: new TextStyle(color: Colors.black), text: value.toString());
    TextPainter tp = TextPainter(
        text: span,
        textDirection: TextDirection.ltr,
        textAlign: TextAlign.left,
        textScaleFactor: size.width / 40);
    tp.layout(minWidth: 0);
    Offset newOffset = Offset(offset.dx, offset.dy);
    tp.paint(canvas, newOffset);
  }

  void _drawSelector(Canvas canvas, Size size, double angle) {
    strokePaint.strokeWidth = 1;
    double x = size.width * cos(angle);
    double y = size.height * sin(angle);
    canvas.drawCircle(Offset(x, y), size.width / 10, fillPaint);
    canvas.drawCircle(Offset(x, y), size.height / 10, strokePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
Enter fullscreen mode Exit fullscreen mode


`

slider Article's
30 articles in total
Favicon
infinity slider
Favicon
Build A Stunning Animated Travel Image Slider Using Html, Css, And JavaScript!
Favicon
Slider in Flutter
Favicon
SLIDER ANIMATION HELP
Favicon
Making a slider puzzle in Java Script
Favicon
#LearnedToday: Slider in pure CSS
Favicon
Flutter - Triangular CAROUSEL Slider
Favicon
looking for a slider package for angular
Favicon
Creating a Slider using Next.js and CSS
Favicon
Create Dynamic Image Slider with PHP and MySQL
Favicon
A step-by-step guide to creating a beautiful slider with Swiper and React
Favicon
Animating using sliders in JavaFX and SceneBuilder
Favicon
Product Gallery Slider for WooCommerce
Favicon
What is a slider and why you should slider on your website?
Favicon
Kaydırıcı robot
Favicon
Basic JavaScript slider ready source
Favicon
Pure CSS Vertical Image Slider Using Only HTML & CSS
Favicon
How to make a simple slider component in React
Favicon
Responsive Image slider using Owl Carousel | HTML & CSS
Favicon
Simple Slider on a pure JavaScript
Favicon
Image Slideshow HTML CSS
Favicon
Ngx Slick Carousel In Angular Material Card with Custom Arrows
Favicon
How to make a Full Slider with javascript in 10 mins
Favicon
Let's build a slider from scratch in React Native
Favicon
Elegant & Beautiful Testimonial Sliders
Favicon
Choppy Slider: The Styles
Favicon
Flutter. A Quarter Round Slider.
Favicon
VueJS: Double range slider component
Favicon
Styling Range Sliders with CSS
Favicon
AWS – Using Multiple (Staging, UAT and Production) Accounts Under AWS Organization

Featured ones: