Reader Stacks

Flutter UI Building Blocks: Sliders, Drawers, Tab Bars, and Image Borders

A handful of common Flutter widgets — Slider, Drawer, TabBar, and rounded image borders — covered together since they all show up in nearly every real app's navigation and settings screens.

Flutter UI Building Blocks: Sliders, Drawers, Tab Bars, and Image Borders

These Flutter widgets show up in nearly every real app's navigation, settings, and media screens — covering them together makes sense since they're commonly combined on the same screens rather than used in isolation.

A custom Slider

double _volume = 50;

Slider(
    value: _volume,
    min: 0,
    max: 100,
    divisions: 10,
    label: _volume.round().toString(),
    activeColor: Colors.blue,
    onChanged: (value) {
        setState(() {
            _volume = value;
        });
    },
)

divisions makes the slider snap to discrete steps instead of moving continuously — omitting it gives a smooth, continuous drag.

A Drawer (side navigation menu)

Scaffold(
    appBar: AppBar(title: Text('My App')),
    drawer: Drawer(
        child: ListView(
            padding: EdgeInsets.zero,
            children: [
                DrawerHeader(
                    decoration: BoxDecoration(color: Colors.blue),
                    child: Text('Menu', style: TextStyle(color: Colors.white, fontSize: 24)),
                ),
                ListTile(
                    leading: Icon(Icons.home),
                    title: Text('Home'),
                    onTap: () => Navigator.pop(context),
                ),
                ListTile(
                    leading: Icon(Icons.settings),
                    title: Text('Settings'),
                    onTap: () => Navigator.pop(context),
                ),
            ],
        ),
    ),
    body: Center(child: Text('Swipe from the left edge, or tap the menu icon')),
)

A Drawer attached to Scaffold.drawer is automatically wired to the hamburger icon Flutter adds to the AppBar, and to a left-edge swipe gesture — no manual gesture detection needed.

A bottom tab bar

int _currentIndex = 0;
final _pages = [HomePage(), SearchPage(), ProfilePage()];

Scaffold(
    body: _pages[_currentIndex],
    bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) => setState(() => _currentIndex = index),
        items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
            BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
        ],
    ),
)

A top tab bar

DefaultTabController(
    length: 3,
    child: Scaffold(
        appBar: AppBar(
            bottom: TabBar(
                tabs: [Tab(text: 'Latest'), Tab(text: 'Popular'), Tab(text: 'Saved')],
            ),
        ),
        body: TabBarView(
            children: [LatestTab(), PopularTab(), SavedTab()],
        ),
    ),
)

Unlike the bottom tab bar, a top TabBar needs a DefaultTabController wrapping the whole Scaffold — it's what synchronizes the visible tab in the AppBar with which page shows in the TabBarView below it.

Rounded border radius on an image

ClipRRect(
    borderRadius: BorderRadius.circular(16),
    child: Image.network(
        'https://example.com/photo.jpg',
        fit: BoxFit.cover,
    ),
)

Image itself has no border-radius property — ClipRRect wrapping it is the standard way to round an image's corners in Flutter, clipping anything drawn inside it to the specified rounded rectangle shape.

Adding a border to a container or any widget

Container(
    decoration: BoxDecoration(
        border: Border.all(color: Colors.grey, width: 1.5),
        borderRadius: BorderRadius.circular(8),
    ),
    padding: EdgeInsets.all(12),
    child: Text('Bordered box'),
)

A border on just one side

Container(
    decoration: BoxDecoration(
        border: Border(bottom: BorderSide(color: Colors.grey, width: 1)),
    ),
    child: ListTile(title: Text('List item with a bottom divider')),
)

Border(bottom: ...) (rather than Border.all()) applies a border to only the specified side — a common pattern for list dividers without needing a separate Divider widget between every item.