Buttons, Slider

The button family by rank (Elevated primary, Text flat, Outlined middle, Icon compact, FAB floating) and Slider, the widget that teaches Flutter's controlled-widget law: no setState, no movement.

11 min read · 9 cards · 2 checks

Read in: English · हिन्दी · ગુજરાતી


Theory

Six tickets, one thumb

Group bookings arrive: up to 6 tickets per student. A TextField accepting "six" and "6six" is the old pain; the natural control is a slider the thumb drags from 1 to 6.

You wire Slider with its min and max, run it, drag: and the thumb snaps straight back to 1 every time. Not broken: Flutter is teaching you its single most important interaction law, and this lesson is built around learning it properly: right after the button family gets its ranks.

Theory

The button family, by rank

All buttons share the same heart (onPressed + child, null disables): what differs is visual rank:

  • ElevatedButton: raised, filled: THE primary action (Book)
  • OutlinedButton: bordered: middle-rank actions (Add to wishlist)
  • TextButton: flat text: secondary, low-noise (Cancel, Skip)
  • IconButton: icon-only, compact: toolbars (share, favourite)
  • FloatingActionButton: the round floating one, living in Scaffold's own floatingActionButton: slot: one per screen, its defining action

Rank = visual loudness = importance: one Elevated per region, quiet Texts beside it.

Practical

The quantity slider, done right

class _BookingState extends State<BookingScreen> {
  double tickets = 1;                    // the STATE owns the value

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Tickets: ${tickets.toInt()}'),
        Slider(
          value: tickets,                // slider DISPLAYS the state
          min: 1,
          max: 6,
          divisions: 5,                  // discrete stops: 1,2,3,4,5,6
          label: '${tickets.toInt()}',   // bubble at the thumb
          onChanged: (v) {
            setState(() { tickets = v; });   // no setState = snap-back
          },
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            TextButton(onPressed: () {}, child: const Text('Cancel')),
            ElevatedButton(
              onPressed: () { /* book tickets.toInt() seats */ },
              child: const Text('Book'),
            ),
          ],
        ),
      ],
    );
  }
}

Theory

The controlled-widget law

Why did the naked slider snap back? Because a Flutter Slider does not own its position. Read the listing's loop:

  • value: tickets : the slider DISPLAYS whatever the state variable holds
  • dragging fires onChanged(v) with the CANDIDATE value: continuously, throughout the drag
  • your handler setStates the variable : build reruns : the slider now displays the new value

Skip the setState and the variable never changes, so every rebuild repaints the thumb at the old value: snap-back. The widget is a view of state, never the keeper of it: and Checkbox, Radio and Switch, waiting in the next lessons, obey the identical law.

Quiz

A Slider has correct min, max and value, and onChanged: (v) { tickets = v; } WITHOUT setState. What does the user experience?

  1. The slider works: the variable is being updated after all
  2. The thumb snaps back on every drag: the variable changes but no rebuild repaints the slider with it
  3. A compile error: onChanged must call setState
  4. The slider moves but the Text label lags one drag behind
Show the answer

The thumb snaps back on every drag: the variable changes but no rebuild repaints the slider with it

The variable DOES change (option A's grain of truth): but the screen only repaints on rebuild, and only setState schedules one: so the slider keeps being rebuilt from... nothing, since no rebuild happens: it repaints at the old position on the next frame of the drag gesture, snapping back. This is the controlled-widget law in one bug: widgets display state; setState publishes changes. Option C: the compiler cannot know your intent: this is a logic bug, the worst kind. Option D describes a subtler staleness that other mistakes cause: this one is total.

Think first

Rank the screen's buttons

The booking screen wants: Book (the point of the screen), Cancel, a heart icon to wishlist, and a screen-wide New Booking action visible over the whole event list. Assign each its button variant with the ranking reason, then tap.

Show the answer

Book: ElevatedButton: the one loud primary per region. Cancel: TextButton: present but quiet, never competing with Book (the listing places them exactly so). Wishlist heart: IconButton: compact, recognisable, toolbar-grade. New Booking over the list: FloatingActionButton in the Scaffold slot: THE screen action by Material convention (think WhatsApp's compose button). The principle: visual loudness should match importance: 2 Elevated buttons side by side is a shouting match, and exams reward saying so.

Watch out

Slider and button slips

Slider value is a double: displaying it raw shows 3.0 tickets: .toInt() for humans (the listing does, twice).

divisions off by one: stops = divisions + 1: range 1 to 6 needs divisions: 5: the fencepost again.

onChanged fires DURING the drag: continuously, not once at release: heavy work there stutters the gesture (the TextWatcher lesson's rule, third appearance).

Two FABs: the Scaffold slot takes one; a second floating action is a design smell, not a parameter.

Theory

One law, four widgets ahead

Frame the controlled-widget law once and keep it lit: value from state, change through onChanged + setState, widget never keeps its own score. The next lesson's Checkbox and Radio are this law verbatim (with Radio adding a clever twist on exclusivity that BCA404's GroupBox veterans will want to compare), and Unit 5's Switch is it again. Learn the loop here, collect the marks 3 more times.

Summary

Key takeaways

  • Button ranks: ElevatedButton primary, OutlinedButton middle, TextButton quiet, IconButton compact, FAB in Scaffold's slot for THE screen action.
  • All share onPressed (null = disabled) + child; loudness should match importance.
  • Slider(value, min, max, divisions, label, onChanged): value is a double the STATE owns.
  • Controlled-widget law: the widget displays state; onChanged + setState publish changes; without setState the thumb snaps back.
  • divisions + 1 = stops; label bubbles at the thumb; onChanged fires continuously during drag.
  • The same law governs Checkbox, Radio and Switch next.
  • Memory hook: widgets show the score, setState writes it.

Study this properly

This page is the lesson to read. In Gri-Learn the same topic is a graded deck: the self-checks are scored and your weak topics are tracked. Free to start.

Start this topic

Already have an account? Sign in

More from Flutter basic widgets

Gri-Learn · syllabus-mapped B.C.A. lessons in English, Hindi and Gujarati

Buttons, Slider · Mobile Application Development - 2 (option B) · Gri-Learn