Search code examples
flutterlistdartflutter-cupertino

how to build a IOS style list with listview builder in Flutter?


I was wondering how to build a Cupertino list like that, with a listView.builder I did it with the CupertinoFormSection, but when i add the listView.builder inside the form, the list does not show. So, right now i put the CupertinoFormSection after the listView, but the result is not what I want.

desired UI

This is my code:

body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: Container(
      child: ListView.builder(
        itemCount: entries.length,
        itemBuilder: (context, i) {
          return GestureDetector(
            onTap: () {
              setState(() async {
                index = i;
                if (i == 0){
                  await context.setLocale(Locale('en','US'));
                }
                else if (i == 1){
                  await context.setLocale(Locale('fr','FR'));
                }
                else {
                  await context.setLocale(Locale('it','IT'));
                }
              });
            },
            child: CupertinoFormSection(
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children:[
                      Text(entries[i]),
                      index == i
                          ? Icon(Icons.check_outlined, color: Colors.blue,)
                          : Icon(null),
                    ],
                  ),
                ),
              ],
            ),
          );
        },
      ),

This is the output:

enter image description here


Solution

  • What you're looking for is the standard widgets CupertinoFormSection and the CupertinoFormRow. They are made specific for this kind of UI.

    Check it out (also the live demo on DartPad).

    Screenshot

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return const CupertinoApp(
          title: 'Flutter Demo',
          home: MyHomePage(),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class Item {
      final String prefix;
      final String? helper;
      const Item({required this.prefix, this.helper});
    }
    
    const items = [
      Item(prefix: 'Italiano', helper: 'Italiano'),
      Item(prefix: 'English (US)', helper: 'Inglese (USA)'),
      Item(prefix: 'Español (EE. UU.)', helper: 'Spagnolo (USA)'),
      Item(prefix: 'Italiano (Italia)', helper: 'Italiano (Italia)'),
      Item(prefix: 'Italiano (Svizzera)', helper: 'Italiano (Svizzera)'),
      Item(prefix: 'English', helper: 'Inglese'),
    ];
    
    class _MyHomePageState extends State<MyHomePage> {
      var _selectedIndex = 0;
      @override
      Widget build(BuildContext context) {
        return CupertinoPageScaffold(
          child: Container(
            color: const Color.fromARGB(255, 242, 242, 247),
            child: Center(
              child: Container(
                width: 250,
                padding: const EdgeInsets.symmetric(vertical: 16),
                child: SingleChildScrollView(
                  child: CupertinoFormSection.insetGrouped(
                    children: [
                      ...List.generate(
                        items.length,
                        (index) => GestureDetector(
                          onTap: () => setState(() => _selectedIndex = index),
                          child: buildCupertinoFormRow(
                            items[index].prefix,
                            items[index].helper,
                            selected: _selectedIndex == index,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        );
      }
    
      Widget buildCupertinoFormRow(
        String prefix,
        String? helper, {
        bool selected = false,
      }) {
        return CupertinoFormRow(
          prefix: Text(prefix),
          helper: helper != null
              ? Text(
                  helper,
                  style: Theme.of(context).textTheme.bodySmall,
                )
              : null,
          child: selected
              ? const Icon(
                  CupertinoIcons.check_mark,
                  color: Color.fromARGB(255, 45, 118, 234),
                  size: 20,
                )
              : Container(),
        );
      }
    }