Flutter Slider Not Moving or Updating

Viewed 17312

I'm learning Flutter (and coding in general) and I can't seem to find the issue with my latest project. When I run in simulator the slider forms just fine, click the thumb and the label shows, but the thumb won't move on the track at all, and thus never calls the onChanged event.

import 'resources.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class ItemDetail extends StatefulWidget {
  final Item item;

  ItemDetail({Key key, @required this.item}) : super(key: key);

  @override
  _ItemDetailState createState() => new _ItemDetailState(item: item);
}

class _ItemDetailState extends State<ItemDetail> {
  Item item;

  _ItemDetailState({Key key, @required this.item});

  @override
  Widget build(BuildContext context) {
    double margin = ((item.listPrice - item.stdUnitCost)/item.listPrice)*100;
    return new Scaffold(
      appBar: AppBar(
        title: new Text('Item Detail'),
      ),
      body: new Column(
        children: <Widget>[
          new Padding(padding: EdgeInsets.symmetric(vertical: 20.0)),
          new Text(item.itemCode),
          new Text(item.itemDescription),
          new Text(item.itemExtendedDescription),
          new Divider(height: 40.0,),
          new Text('List Price: \$${item.listPrice}'),
          new Text('Cost: \$${item.stdUnitCost}'),
          item.itemType=='N'
              ? new Text('Non-Stock (${item.itemType})')
              : new Text('Stock Item (${item.itemType})'),
          new Text('Available: ${item.stockAvailable}'),
          new Padding(padding: EdgeInsets.symmetric(vertical: 10.0)),
          new Slider(
            value: margin,
            divisions: 20,
            min: 0.0,
            max: 100.0,
            label: margin.round().toString(),
            onChanged: (double value) {
              setState(() {
                margin = value;
              });
            },
          )
        ],
      ),
    );
  }
}
6 Answers

Problem: In the above example, margin is not a state variable. It is a local variable inside a build method.

Fix: Move this as an instance variable.

Reason: Widgets will get rebuild only when there is a change in its state.

Code:

class _ItemDetailState extends State<ItemDetail> {
  Item item;
  var margin;

  _ItemDetailState({Key key, @required this.item}) {
    this.margin = ((item.listPrice - item.stdUnitCost)/item.listPrice)*100;
  }

  @override
  Widget build(BuildContext context) {
    //same as now
  }
}

For others coming here, I had a slightly different reason that the slider wasn't updating. I had the value set to a constant. Make sure that value is a variable.

This:

Slider(
  value: _myValue,
  ...
  onChanged: (newValue) => {
    setState(() => _myValue = newValue)
  },
),

Not this:

Slider(
  value: 0, //                     <-- problem
  ...
  onChanged: (newValue) => {
    setState(() => _myValue = newValue)
  },
),

I got this issue when I put the variable inside the build function

@override
Widget build(BuildContext context) {

int brightness = 85;

return Scaffold(
...

Moved the variable outside the function and got it solved

int brightness = 85;

@override
Widget build(BuildContext context) {

return Scaffold(
...

because each time when state is changed, this build method is called and sets the variable back to the assigned value

This might help! (I USED STATEFULBUILDER TO UPDATE THE VALUE)

               double _value = 20;

               StatefulBuilder(
                  builder: (context, state) => Center(
                    child: CupertinoSlider(
                      value: _value,
                      min: 0.0,
                      max: 100.0,
                      onChanged: (val) {
                        state(() {
                          _value = val;
                        });
                      },
                    ),
                  ),
                )

I think the variable margin does not have scope from where the UI is building. When you debug, you can see changes in variable but it is not rendering. I tried it in following way and able to update the UI value.

    class _MyHomePageState extends State<MyHomePage> {

     double margin=0;

     Widget getSlider(BuildContext context)
      {

        return Slider(
      value:margin.toDouble(),
      onChanged: (newRating){

        setState(() {
          margin = newRating;
        });

      },
      min: 0,
      max: 100,
      divisions: 5,
    );
   } // getslider method closed
     // @0verride Widget build method
    // under children widgets , simply call the getSlider method to place the slider
 } //class

I was having an issue when giving the Slider(value: tasksDetails.taskImportance.toDouble(), etc)

I used Slider((_currentImportance ?? tasksDetails.taskImportance).toDouble(), etc)

and could then move the slider. I have no idea why this now works. Can only guess something to do with Denish's reason above 'Reason: Widgets will get rebuild only when there is a change in its state'. The selected slider value was in both cases was save correctly.

Related