enter image description here

enter image description here

class _AppointmentListViewState extends State<AppointmentListView> {
  int numOfInitialAppointmentsLoaded = 2;
  int numOfAppointmentsToFetch = 2;

  @override
  Widget build(BuildContext context) {
    List appointmentData = [
      ...widget.appointmentList.map(
          (appointmentData) => AppointmentModal(appointment: appointmentData))
    ];

    int totalNumberOfAppointments = appointmentData.length;

    void loadMoreAppointments() {
      if (numOfInitialAppointmentsLoaded >= totalNumberOfAppointments) {
        // may need to add a msg to the user
      } else {
        setState(() {
          if (totalNumberOfAppointments - numOfInitialAppointmentsLoaded <
              numOfAppointmentsToFetch) {
            numOfInitialAppointmentsLoaded +=
                totalNumberOfAppointments - numOfInitialAppointmentsLoaded;
          } else {
            numOfInitialAppointmentsLoaded += numOfAppointmentsToFetch;
          }
        });
      }
    }

    return Column(
      children: [
        SizedBox(
          height: MediaQuery.of(context).size.height / 1.5,
          child: ListView.builder(
              // shrinkWrap: true,
              itemCount: numOfInitialAppointmentsLoaded,
              itemBuilder: (BuildContext context, int index) {
                return appointmentData[index];
              }),
        ),
        TextButton(
            style: TextButton.styleFrom(
              foregroundColor: cocoGypsy,
              textStyle:
                  const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
            onPressed: loadMoreAppointments,
            child: const Text("See more appointments"))
      ],
    );
  }
}

Currently I have a list of appointments and a text button that loads more appointments. The list is generated by the Listview builder and the button is always at the bottom of the screen. How can I make the button move dynamically with the list items so that it gets pushed down as more items are loaded?

I tried removing the sized box and just have my listview and button widgets wrapped in a column, but then my appointments weren't loading at all.

3

There are 3 answers

0
Munsif Ali On

you can try this

return Scaffold(
      body: ListView.builder(
        // shrinkWrap: true,
        itemCount: numOfInitialAppointmentsLoaded + 1,
        itemBuilder: (BuildContext context, int index) {
          if (index == numOfInitialAppointmentsLoaded)
            return TextButton(
              style: TextButton.styleFrom(
                foregroundColor: cocoGypsy,
                textStyle:
                    const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              onPressed: loadMoreAppointments,
              child: const Text("See more appointments"),
            );
          return appointmentData[index];
        },
      ),
    );

or you can try bottom navigation bar like this

 return Scaffold(
      body: ListView.builder(
          // shrinkWrap: true,
          itemCount: numOfInitialAppointmentsLoaded,
          itemBuilder: (BuildContext context, int index) {
            return appointmentData[index];
          }),
      bottomNavigationBar: TextButton(
        style: TextButton.styleFrom(
          foregroundColor: cocoGypsy,
          textStyle: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
        onPressed: loadMoreAppointments,
        child: const Text("See more appointments"),
      ),
    );
1
Dharam Budh On

Here you go. You can copy this source code & paste it into the main.dart file and run it. Don't forget to look at the attached output below the source code.

import "package:flutter/material.dart";

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const MainScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MainScreen extends StatelessWidget {
  const MainScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              ListView.builder(
                itemCount: 5, // try 15 here
                shrinkWrap: true,
                physics: const ScrollPhysics(),
                itemBuilder: (BuildContext context, int index) {
                  return Card(child: ListTile(title: Text("Index $index")));
                },
              ),
              ElevatedButton(
                onPressed: () {},
                child: const Text("Button"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Output: output

0
Chihiro On

I think you should use CustomScrollView

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const IndexScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class IndexScreen extends StatelessWidget {
  const IndexScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: CustomScrollView(
          slivers: [
            SliverList.builder(
              itemBuilder: (cxt, index) {
                return Card(child: ListTile(title: Text("Index $index")));
              },
              itemCount: 15,
            ),
            SliverToBoxAdapter(
              child: ElevatedButton(
                onPressed: () {},
                child: const Text("Button"),
              ),
            )
          ],
        ),
      ),
    );
  }
}