Problème de couleur de fond et débordement sur ListView

Salut à tous,

Je suis confronté à un problème assez bizarre. J’ai un écran avec un titre, une zone de recherche, une ListView et un pied de page.
J’ai attribué une couleur de fond aux Tile de la ListView, mais ceux-ci « débordent » sur les widgets avant et après cette ListView. Le plus étrange est qu’ils sont vides, on ne voit que le fond.
La solution la plus simple serait de ne pas mettre de fond, mais cela me turlupine quand même.
Voici le code de la page et 2 illustrations. Quand l’écran s’affiche, tout parait correct (sauf le pied de page qui est recouvert), mais en scrollant vers le bas, on se rend compte que le TextField et le titre sont recouvert.
C’est ici un exemple du code, ce n’est pas le définitif :wink:

import 'package:flutter/material.dart';
import 'package:myapp/data/model/customer.dart';
import 'package:myapp/ui/components/main_app_bar.dart';

abstract class ICustomersViewModel extends ChangeNotifier {
  List<Customer> get customersList;
  Future<List<Customer>> loadCustomersList();
}

class CustomersScreen extends StatefulWidget {
  final ICustomersViewModel viewModel;
  const CustomersScreen(this.viewModel, {super.key});

  @override
  State<CustomersScreen> createState() => _CustomersScreenState();
}

class _CustomersScreenState extends State<CustomersScreen> {
  @override
  void initState() {
    super.initState();
    widget.viewModel.loadCustomersList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const MainAppBar(title: "Clients"),
      body: SafeArea(
        child: Column(
          children: [
            const Text("Haut de page"),
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: TextField(
                decoration: InputDecoration(
                  hintText: "Rechercher un client",
                ),
              ),
            ),
            Expanded(
              child: ListenableBuilder(
                  listenable: widget.viewModel,
                  builder: (context, _) {
                    if (widget.viewModel.customersList.isEmpty) {
                      return const Center(
                        child: CircularProgressIndicator(),
                      );
                    }
                    return ListView.separated(
                        itemBuilder: _customerCellBuilder,
                        separatorBuilder: (_, index) => const Divider(),
                        itemCount: widget.viewModel.customersList.length);
                  }),
            ),
            const SizedBox(
                height: 50, child: Center(child: Text("Bas de page"))),
          ],
        ),
      ),
    );
  }

  Widget _customerCellBuilder(BuildContext context, int index) {
    final customer = widget.viewModel.customersList[index];
    return ListTile(
      title: Text("ITEM $index"),
      trailing: Text(
        customer.number.toString(),
      ),
      tileColor: const Color.fromARGB(255, 174, 76, 76),
      titleTextStyle: const TextStyle(
        color: Colors.black,
        fontSize: 20,
      ),
    );
  }
}

Si vous avez une idée, je suis preneur.

Merciiii

Hello Frédéric,

Je pense que c’est ton ListenableBuilder qui te fait ce rendu. Je passerai plutôt sur un animatedBuilder dans lequel je placerai mon ListView.

J’y ai pensé et j’ai testé, le problème est totalement identique :frowning:

Je viens de me rappeler que j’avais eu un problème similaire il y a quelques temps. Tu peux utiliser une nestedScrollView avec un headerSliverBuilder. J’avais enlevé l’appbar qui ne me servait pas.

Voici le code simplifié pour exemple :

Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: SafeArea(
        child: AnimatedBuilder(
            animation: widget._viewModel,
            builder: (context, child) {
              final fungusList = widget._viewModel.fungusList;
              return NestedScrollView(
                headerSliverBuilder:
                    (BuildContext context, bool innerBoxIsScrolled) {
                  return <Widget>[
                    SliverAppBar(
                      backgroundColor: Colors.white,
                      pinned: false,
                      floating: false,
                      snap: false,
                      expandedHeight: 80.0,
                      forceElevated: innerBoxIsScrolled,
                      flexibleSpace: Padding(
                        padding: const EdgeInsets.only(
                            top: 16.0, bottom: 8.0, left: 8.0, right: 8.0),
                        // Le widget Focus permet de surveiller le focus et forcer le setState à chaque changement.
                        // Lors de la navigation arrière, le focus est actif mais l'état n'est pas rafraichit.
                        child: Focus(
                          onFocusChange: (hasFocus) {
                            setState(() {});
                          },
                          child: TextField(
                            controller: _controller,
                            focusNode: focusNode,
                            maxLines: 1,
                            decoration: InputDecoration(
                                prefixIcon: const Icon(Icons.search),
                                suffixIcon: focusNode.hasFocus ||
                                        _controller.text.isNotEmpty
                                    ? IconButton(
                                        icon: const Icon(Icons.clear),
                                        onPressed: _clearTextField,
                                      )
                                    : null,
                                labelText: "Chercher un champignon",
                                isDense: true,
                                border: OutlineInputBorder(
                                  borderRadius: BorderRadius.circular(15),
                                )),
                            onChanged: (searchText) {
                              widget._viewModel
                                  .fungiSearch(searchText: searchText);
                            },
                          ),
                        ),
                      ),
                    ),
                  ];
                },
                body: (fungusList != null)
                    ? ListView.separated(
                        itemCount: fungusList.length,
                        itemBuilder: (BuildContext context, int index) {
                          return GestureDetector(
                              onTap: () => widget._viewModel.onFungusTouched(
                                  fungusId: fungusList[index].id),
                              child: DiscoverCellWidget(
                                  fungus: fungusList[index]));
                        },
                        separatorBuilder: (BuildContext context, int index) =>
                            const Divider(
                          thickness: 1.0,
                          indent: 15.0,
                          endIndent: 15.0,
                        ),
                      )
                    : const Center(child: CircularProgressIndicator()),
              );
            }),
      ),
      bottomNavigationBar: widget._bottomNavigationBarWidget,
    );
  }
1 « J'aime »

Ok merci je vais regarder dans ce sens.