Mervin Hemaraju
Mervin Hemaraju

Reputation: 2117

Flutter ListView in AlertDialog overlaps with Dialog Title

I have a simple ListView in my alert dialog. It allows a user to make selection and once selected, the list tile color changes.

The weird issue that I am having is for the selected tiles, when I scroll, it overlaps with the title of the dialog:

enter image description here enter image description here

But for the other unselected tiles, it just goes under the title as desired.

My code is as below:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mauritius_emergency_services/core/models/service.dart';
import 'package:mauritius_emergency_services/core/providers/services.dart';
import 'package:mauritius_emergency_services/core/providers/settings.dart';

class EmergencyButtonDialog extends ConsumerWidget {
  const EmergencyButtonDialog({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final settings = ref.watch(settingsProvider);
    final uiState = ref.watch(servicesProvider).when(
          data: (services) => ServiceListView(
            services: services,
            selectedService: settings.emergencyButtonAction,
            onServiceSelected: (service) {
              ref
                  .read(settingsProvider.notifier)
                  .updateEmergencyButtonAction(service);
            },
          ),
          loading: () => const CircularProgressIndicator(),
          error: (error, stack) => const Text("Error occurred"),
        );

    return AlertDialog(
      title: const Text("Choose Emergency Action"),
      contentPadding: EdgeInsets.zero, // Remove default padding
      content: SizedBox(
        width: double.maxFinite,
        height: 300,
        child: uiState,
      ),
    );
  }
}

class ServiceListView extends StatelessWidget {
  final List<Service> services;
  final Service selectedService;
  final Function(Service) onServiceSelected;

  const ServiceListView({
    super.key,
    required this.services,
    required this.selectedService,
    required this.onServiceSelected,
  });

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: services
          .map(
            (service) => ListTile(
              selected: service.identifier == selectedService.identifier,
              selectedColor: Theme.of(context).colorScheme.onTertiary,
              selectedTileColor: Theme.of(context).colorScheme.tertiary,
              title: Text(service.name),
              subtitle: Text(service.mainContact.toString()),
              trailing: service.identifier == selectedService.identifier
                  ? Icon(
                      Icons.check_circle,
                      color: Theme.of(context).colorScheme.onTertiary,
                    )
                  : null,
              onTap: () {
                onServiceSelected(service);
              },
            ),
          )
          .toList(),
    );
  }
}

And this is how i launch my dialog:

showDialog<String>(
              context: context,
              builder: (BuildContext context) => LanguageDialog(),
            );

Anyone know why this is happening ?

Upvotes: 1

Views: 88

Answers (2)

Ramji
Ramji

Reputation: 183

Solution for this is to remove the title padding of AlertDialog then surrounding the Text Widget of title property of AlertDialog by Container Widget , then giving Container the same color and height as that of AlertDialog title and finally changing clipBehavior propery of AlertDialog to Clip.hardEdge.

Full Code : -

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Box(),
    );
  }
}

class Box extends StatefulWidget {
  const Box({super.key});

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  var selectedIndex = List<List>.generate(
      10, (i) => List<dynamic>.generate(10, (index) => false, growable: false),
      growable: false);

  Widget dialog() {
    return Center(
        child: ListView(children: [
      for (int i = 0; i < 5; i++) ...[
        StatefulBuilder(builder: (context, StateSetter setState) {
          return AlertDialog(
            clipBehavior: Clip.hardEdge,
            contentPadding: EdgeInsets.zero,
            titlePadding: EdgeInsets.zero,
            title: Container(
              width: double.infinity,
              height: 75,
              decoration: BoxDecoration(
                  color: Theme.of(context).colorScheme.surfaceContainerHigh,
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(25),
                    topRight: Radius.circular(25),
                  )),
              alignment: Alignment.center,
              child: Text("Choose Emergency Action"),
            ),
            content: SizedBox(
              width: double.maxFinite,
              height: 300,
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    for (int j = 0; j < 10; j++) ...[
                      ListTile(
                        selected: selectedIndex[i][j],
                        title: Text(
                          'Item : - $j',
                        ),
                        contentPadding: EdgeInsets.all(10),
                        selectedTileColor: Colors.purple[400],
                        onTap: () {
                          setState(() {
                            selectedIndex[i][j] = !selectedIndex[i][j];
                          });
                        },
                      ),
                    ]
                  ],
                ),
              ),
            ),
          );
        })
      ]
    ]));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: GestureDetector(
          onTap: () {
            showDialog<String>(
              context: context,
              builder: (BuildContext context) => dialog(),
            );
          },
          child: Text('open dialog')),
    ));
  }
}

Output: -

Upvotes: 2

petey
petey

Reputation: 17140

Your title text is too large.

You can reduce the text size:

title: const Text("Choose Emergency Action",
                    style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.normal)),

Or the text length:

title: const Text("Choose Action"),

Upvotes: 0

Related Questions