Ad

Flutter Stacked GestureDetector And Slider Problem

- 1 answer

I have a stack with a GestureDetector to transform an icon to a button and a circolar slider around it.

Stack(
 alignment: Alignment.center,
 children: <Widget>[
  BulbSlider(),
  Positioned(
   top: 25,
   child: GestureDetector(
    onTap: () {
     debugPrint('pressed');
     Vibrate.feedback(FeedbackType.selection);
    },
    child: Icon(
     Icons.play_circle_fill_rounded,
     color: kOrange,
     size: 250,
    ),
   ),
  ),
 ],
),

screenshot

This is the screenshot. My problem here is that the slider can't be used if I try to drag the handle but it work if click on the track of the slider. There are also a problem with the button that the GestureDetectoris triggered also if I click between the slider and the button(so outside of the icon).

I've tried also to invert the two widget so I'm having the slider on top of the GestureDetector but in this case the slider works good but the GestureDetector is not detecting any tap.

Here the code:

Stack(
 alignment: Alignment.center,
 children: <Widget>[
  Positioned(
   top: 25,
   child: GestureDetector(
    onTap: () {
     debugPrint('pressed');
     Vibrate.feedback(FeedbackType.selection);
    },
    child: Icon(
     Icons.play_circle_fill_rounded,
     color: kOrange,
     size: 250,
    ),
   ),
  ),
  BulbSlider(),
 ],
),

if it can help I put here the code of the slider:

import 'package:flutter/material.dart';
import 'package:sleek_circular_slider/sleek_circular_slider.dart';
import '/const/colors.dart';

class BulbSlider extends StatefulWidget {
  const BulbSlider({Key? key}) : super(key: key);
  @override
  _State createState() => _State();
}

class _State extends State<BulbSlider> {
  double? myValue;
  String valore = '';
  @override
  void initState() {
    super.initState();
    myValue = 0;
    valore = '1';
  }

  otherMethod(String rounded) {
    debugPrint("rounded: " + rounded);
    valore = rounded;
  }

  @override
  Widget build(BuildContext context) {
    final slider = SleekCircularSlider(
      min: 1,
      max: 360,
      initialValue: 1,
      appearance: CircularSliderAppearance(
        size: 300,
        startAngle: 140,
        angleRange: 260,
        animationEnabled: true,
        customColors: CustomSliderColors(
          hideShadow: true,
          trackColor: kCards,
          dotColor: kWhite,
          progressBarColor: kOrange,
        ),
        customWidths: CustomSliderWidths(
          shadowWidth: 30,
          trackWidth: 8,
          progressBarWidth: 8,
          handlerSize: 10,
        ),
        infoProperties: InfoProperties(
          mainLabelStyle: TextStyle(
              color: kWhite, fontSize: 20, fontWeight: FontWeight.w700),
          //topLabelStyle:
          //    TextStyle(color: kWhite, fontSize: 20, fontWeight: FontWeight.w700),
          //topLabelText: 'Seconds',
          modifier: (double value) {
            final sec = (value.toInt()) / 100;

            return ''; // '$sec s';
          },
        ),
      ),
      onChange: (double weight) {
        setState(() {
          String newValue = weight.ceil().toInt().toString();
          debugPrint(newValue);
          otherMethod(newValue);
        });
      },
    );
    return Container(
      child: Column(
        children: <Widget>[
          Center(child: slider),
          Text(valore),
        ],
      ),
    );
  }
}

Have you any idea how to solve it? thanks

Ad

Answer

You can clip the effective area of gesture detection as follows:

Material(
  // You can check the effective area of inkwell
  // color: Colors.deepOrangeAccent,
  borderRadius: BorderRadius.circular(250 / 2),
  child: InkWell(
    onTap: () {},
    borderRadius: BorderRadius.circular(250 / 2),
    child: const Icon(Icons.play_circle_fill_rounded,
      color: kOrange,
      size: 250,
    ),
  ),
)

Or simply set customBorder as follows:

InkWell(
  customBorder: const CircleBorder(),
  onTap: () {
    print('Hello there!');
  },
  borderRadius: BorderRadius.circular(250 / 2),
  child: const Icon(
    Icons.play_circle_fill_rounded,
    color: kOrange,
    size: 250,
  ),
)

In your case,

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

const kCards  = Colors.red;
const kOrange = Colors.orange;
const kWhite  = Colors.white;

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        alignment: Alignment.center,
        children: <Widget>[
          const BulbSlider(),
          Positioned(
            top: 25,
            child: Material(
              // You can check the effective area of the inkwell
              // color: kOrange,
              borderRadius: BorderRadius.circular(250 / 2),
              child: InkWell(
                onTap: () {
                  print('Hello there!');
                },
                borderRadius: BorderRadius.circular(250 / 2),
                child: const Icon(
                  Icons.play_circle_fill_rounded,
                  color: kOrange,
                  size: 250,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class BulbSlider extends StatefulWidget {
  const BulbSlider({Key? key}) : super(key: key);
  @override
  _State createState() => _State();
}

class _State extends State<BulbSlider> {
  double? myValue;
  String valore = '';
  @override
  void initState() {
    super.initState();
    myValue = 0;
    valore = '1';
  }

  otherMethod(String rounded) {
    debugPrint("rounded: " + rounded);
    valore = rounded;
  }

  @override
  Widget build(BuildContext context) {
    final slider = SleekCircularSlider(
      min: 1,
      max: 360,
      initialValue: 1,
      appearance: CircularSliderAppearance(
        size: 300,
        startAngle: 140,
        angleRange: 260,
        animationEnabled: true,
        customColors: CustomSliderColors(
          hideShadow: true,
          trackColor: kCards,
          dotColor: kWhite,
          progressBarColor: kOrange,
        ),
        customWidths: CustomSliderWidths(
          shadowWidth: 30,
          trackWidth: 8,
          progressBarWidth: 8,
          handlerSize: 10,
        ),
        infoProperties: InfoProperties(
          mainLabelStyle: const TextStyle(
              color: kWhite, fontSize: 20, fontWeight: FontWeight.w700),
          //topLabelStyle:
          //    TextStyle(color: kWhite, fontSize: 20, fontWeight: FontWeight.w700),
          //topLabelText: 'Seconds',
          modifier: (double value) {
            // final sec = (value.toInt()) / 100;
            return ''; // '$sec s';
          },
        ),
      ),
      onChange: (double weight) {
        setState(() {
          String newValue = weight.ceil().toInt().toString();
          debugPrint(newValue);
          otherMethod(newValue);
        });
      },
    );
    return Column(
      children: <Widget>[
        Center(child: slider),
        Text(valore),
      ],
    );
  }
}

Source - FlutterBeads.

Ad
source: stackoverflow.com
Ad