Search code examples
flutterdartflutter-image-picker

Pass user selected photo to other pages within the app - Flutter


I am new to Flutter and need some assistance. I am using the ImagePicker to allow the user to select the image they want to use for a specific event (on the "Add New Event Page"), however, I don't know how to pass that selected image to other pages ("Upcoming Event Tile" and "Home Page") and have it appear when that specific event is viewed. I don't have a database setup yet, just a local model page. How do I do this? Here is the code (I apologize in advance for the sloppy code...I am still learning):

Add New Event Page (USER SELECTS IMAGE FROM THIS PAGE):

import 'dart:io';
import 'package:evnt_app/pages/choose_icon_page.dart';
import 'package:evnt_app/pages/navigation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import '../data/evnt_data.dart';

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

  @override
  State<AddNewEventPage> createState() => _AddNewEventPageState();
}

class _AddNewEventPageState extends State<AddNewEventPage> {
  /////////////////////////////////////////////////      Controller Methods      /////////////////////////////////////////////////

  // Clear Controllers
  void clearControllers() {
    eventNameController.clear();
    eventDateController.clear();
    eventTimeController.clear();
    eventLocationController.clear();
  }

  // Support Dialog Box - Text Controller
  final eventNameController = TextEditingController();
  final eventDateController = TextEditingController();
  final eventTimeController = TextEditingController();
  final eventLocationController = TextEditingController();

  ///////////////////////////////////////////////////    "Add" Button Method   /////////////////////////////////////////////////////

  // "Add New Event" Save Button Method
  void saveNewEvent() {
    Provider.of<EvntData>(context, listen: false).addEvent(
      eventNameController.text,
      eventDateController.text,
      eventTimeController.text,
      eventLocationController.text,
    );

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const Navigation(),
      ),
    );
  }

// Pick Image Method
  File? image;

  Future pickImage(ImageSource source) async {
    try {
      final image = await ImagePicker().pickImage(source: source);
      if (image == null) return;

      final imageTemporary = File(image.path);
      setState(() => this.image = imageTemporary);
    } on PlatformException catch (e) {
      print('Failed to pick image: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,

      // App Bar
      appBar: AppBar(
        leading: IconButton(
            onPressed: () {
              Navigator.of(context).push(
                MaterialPageRoute(
                  builder: (context) => const Navigation(),
                ),
              );
            },
            icon: const Icon(
              Icons.close,
              size: 30,
            )),
        elevation: 0,
        backgroundColor: Colors.red.shade400,
        title: Text(
          'Add Event Details',
          style: GoogleFonts.poppins(fontSize: 20, fontWeight: FontWeight.bold),
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.only(left: 20.0, right: 20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Choose Event Photo Icon
            Padding(
              padding: const EdgeInsets.only(top: 25.0, bottom: 25.0),
              child: Column(
                children: [
                  // Image Placeholder
                  image != null
                      ? ClipOval(
                          child: Image.file(image!,
                              width: 125, height: 125, fit: BoxFit.cover),
                        )
                      : Image.asset(
                          'lib/assets/images/event-default.png',
                          width: 125,
                          height: 125,
                        ),

                  const SizedBox(height: 25.0),

                  // Select Image From Gallery
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      // Add Photo From Gallery Button
                      Container(
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(50),
                            color: Colors.red.shade400),
                        child: IconButton(
                          onPressed: () => pickImage(ImageSource.gallery),
                          icon: const Icon(
                            Icons.add_photo_alternate_rounded,
                            color: Colors.white,
                            size: 30.0,
                          ),
                        ),
                      ),

                      const SizedBox(width: 20.0),

                      // Add Photo From Camera
                      Container(
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(50.0),
                            color: Colors.red.shade400),
                        child: IconButton(
                          onPressed: () => pickImage(ImageSource.camera),
                          icon: const Icon(
                            Icons.add_a_photo_outlined,
                            color: Colors.white,
                            size: 30.0,
                          ),
                        ),
                      ),

                      const SizedBox(width: 20.0),

                      // Add Icon from Icons List
                      Container(
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(50.0),
                            color: Colors.red.shade400),
                        child: IconButton(
                          onPressed: () => Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => const ChooseIconPage(),
                            ),
                          ),
                          icon: const Icon(
                            Icons.apps,
                            color: Colors.white,
                            size: 30.0,
                          ),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            // Event Title Header
            Row(
              children: [
                Text(
                  'Event Name',
                  style: GoogleFonts.poppins(
                      fontSize: 16,
                      fontWeight: FontWeight.w600,
                      color: Colors.red.shade400),
                ),
              ],
            ),
            // Event Name Text Field
            TextField(
              controller: eventNameController,
              decoration: InputDecoration(
                hintText: "Enter Event Name",
                hintStyle: GoogleFonts.poppins(
                    fontSize: 18, fontWeight: FontWeight.w500),
              ),
              style: GoogleFonts.poppins(
                  fontSize: 18, fontWeight: FontWeight.w500),
            ),

            const SizedBox(height: 25.0),

            // Event Date Header
            Text(
              'Date',
              style: GoogleFonts.poppins(
                  fontSize: 16,
                  fontWeight: FontWeight.w600,
                  color: Colors.red.shade400),
            ),
            // Event Date
            TextField(
              controller: eventDateController,
              decoration: InputDecoration(
                hintText: "Enter Date",
                hintStyle: GoogleFonts.poppins(
                    fontSize: 18, fontWeight: FontWeight.w500),
              ),
              style: GoogleFonts.poppins(
                  fontSize: 18, fontWeight: FontWeight.w500),
            ),

            const SizedBox(height: 25.0),

            // Event Time Header
            Text(
              'Time',
              style: GoogleFonts.poppins(
                  fontSize: 16,
                  fontWeight: FontWeight.w600,
                  color: Colors.red.shade400),
            ),
            // Event Time
            TextField(
              controller: eventTimeController,
              decoration: InputDecoration(
                hintText: "Enter Time",
                hintStyle: GoogleFonts.poppins(
                    fontSize: 18, fontWeight: FontWeight.w500),
              ),
              style: GoogleFonts.poppins(
                  fontSize: 18, fontWeight: FontWeight.w500),
            ),

            const SizedBox(height: 25.0),

            // Event Location Header
            Text(
              'Location',
              style: GoogleFonts.poppins(
                  fontSize: 16,
                  fontWeight: FontWeight.w600,
                  color: Colors.red.shade400),
            ),
            // Event Location
            TextField(
              controller: eventLocationController,
              decoration: InputDecoration(
                hintText: "Enter Location",
                hintStyle: GoogleFonts.poppins(
                    fontSize: 18, fontWeight: FontWeight.w500),
              ),
              style: GoogleFonts.poppins(
                  fontSize: 18, fontWeight: FontWeight.w500),
            ),

            const SizedBox(height: 50.0),

            // Add Event Button
            Column(
              children: [
                Center(
                  child: Container(
                    width: 150,
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(50.0),
                        color: Colors.red.shade400),
                    child: MaterialButton(
                      shape: const RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(
                          Radius.circular(50.0),
                        ),
                      ),
                      minWidth: 150.0,
                      height: 50.0,
                      onPressed: saveNewEvent,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text(
                            'Add',
                            style: GoogleFonts.poppins(
                                fontSize: 18,
                                fontWeight: FontWeight.w600,
                                color: Colors.white),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 25.0),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Upcoming Event Tile (I WANT THE IMAGE TO APPEAR ON THIS TILE)

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../models/upcoming_event_model.dart';

class UpcomingEventTile extends StatelessWidget {
  final UpcomingEvent upcomingEvents;

  void Function()? onTap;

  UpcomingEventTile({super.key, required this.upcomingEvents, this.onTap});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        GestureDetector(
          onTap: onTap,
          child: Container(
            padding: const EdgeInsets.only(top: 20.0, bottom: 20.0),
            width: 400,
            decoration: BoxDecoration(
              color: Colors.grey.shade100,
              borderRadius: BorderRadius.circular(15.0),
            ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                // Icon & Description Column
                Padding(
                  padding: const EdgeInsets.only(left: 20.0),
                  child: Column(
                    children: [
                      /////// USER SELECTED IMAGE HERE
                      Row(
                        children: [
                          const SizedBox(width: 20),
                          // Event Description
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                upcomingEvents.upcomingEventName,
                                style: GoogleFonts.poppins(
                                    fontSize: 15, fontWeight: FontWeight.w600),
                              ),
                              const SizedBox(
                                height: 5.0,
                              ),
                              Text(
                                upcomingEvents.upcomingEventDate,
                                style: GoogleFonts.poppins(
                                    fontSize: 13,
                                    fontWeight: FontWeight.w600,
                                    color: Colors.red.shade400),
                              ),
                              Text(
                                upcomingEvents.upcomingEventLocation,
                                style: GoogleFonts.poppins(
                                    fontSize: 13,
                                    fontWeight: FontWeight.w600,
                                    color: Colors.grey.shade600),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
                // Arrow Icon
                Column(
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(right: 20.0),
                      child: Icon(Icons.keyboard_arrow_right_rounded,
                          size: 35, color: Colors.red.shade400),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

Home Page (THE UPCOMING EVENT TILE IS RETRIEVED ON THIS PAGE):

import 'dart:io';

import 'package:evnt_app/models/upcoming_event_model.dart';
import 'package:evnt_app/pages/individual_past_event_page.dart';
import 'package:evnt_app/pages/individual_upcoming_event_page.dart';
import 'package:evnt_app/tiles/past_event_tile.dart';
import 'package:evnt_app/tiles/upcoming_event_tile.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import '../data/evnt_data.dart';
import '../models/past_event_model.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    // Curved Main Tile
    return Consumer<EvntData>(
      builder: (context, value, child) => Scaffold(
        backgroundColor: Colors.grey.shade300,
        body: Column(
          children: [
            Container(
              margin: const EdgeInsets.only(top: 100),
              height: 612,
              decoration: const BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(50.0),
                  topRight: Radius.circular(50.0),
                ),
              ),
              child: Padding(
                padding: const EdgeInsets.only(top: 20.0),
                child: Column(
                  children: [
                    //////////////////////////////// PAST EVENTS SECTION ////////////////////////////////
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        // Header
                        Text(
                          'Past Events',
                          style: GoogleFonts.poppins(
                              fontSize: 20, fontWeight: FontWeight.bold),
                        ),
                      ],
                    ),

                    // Past Events Icons List
                    Container(
                      height: 175,
                      child: Expanded(
                        child: ListView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: value.pastEvents.length,
                          itemBuilder: (context, index) {
                            PastEvent individualPastEvent =
                                value.pastEvents[index];
                            return Padding(
                              padding: const EdgeInsets.only(bottom: 10),
                              child: PastEventTile(
                                pastEvents: individualPastEvent,
                                onTap: () {
                                  Navigator.of(context).push(
                                    MaterialPageRoute(
                                      builder: (context) =>
                                          IndividualPastEventPage(
                                        pastEvents: individualPastEvent,
                                      ),
                                    ),
                                  );
                                },
                              ),
                            );
                          },
                        ),
                      ),
                    ),

                    //////////////////////////////// UPCOMING EVENTS SECTION ////////////////////////////////
                    Column(
                      children: [
                        // Header
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Padding(
                              padding: const EdgeInsets.all(10.0),
                              child: Text(
                                'Upcoming Events',
                                style: GoogleFonts.poppins(
                                    fontSize: 20,
                                    fontWeight: FontWeight.bold,
                                    color: Colors.red.shade400),
                              ),
                            )
                          ],
                        ),
                        const SizedBox(height: 10.0),
                        // Upcoming Events Icons List
                        Container(
                          height: 325,
                          child: Expanded(
                            child: ListView.builder(
                              scrollDirection: Axis.vertical,
                              itemCount: value.upcomingEvents.length,
                              itemBuilder: (context, index) {
                                UpcomingEvent individualUpcomingEvent =
                                    value.upcomingEvents[index];
                                return Padding(
                                  padding: const EdgeInsets.only(bottom: 10),
                                  child: UpcomingEventTile(
                                    upcomingEvents: individualUpcomingEvent,
                                    onTap: () {
                                      Navigator.of(context).push(
                                        MaterialPageRoute(
                                          builder: (context) =>
                                              IndividualUpcomingEventPage(
                                            upcomingEvents:
                                                individualUpcomingEvent,
                                          ),
                                        ),
                                      );
                                    },
                                  ),
                                );
                              },
                            ),
                          ),
                        ),
                      ],
                    )
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}


Solution

  • If you write code without using an external package, you can use

    InheritedWidget.

    test.dart (using InheritedWidget)

    import 'package:flutter/material.dart';
    
    class TestWidget extends InheritedWidget {
      String data;
    
      TestWidget({
        Key key,
        @required Widget child,
      }) : super(key: key, child: child);
    
      @override
      bool updateShouldNotify(covariant TestWidget oldWidget) {
        return data != oldWidget.data;
      }
    
      static TestWidget of(BuildContext context) {
        return (context.dependOnInheritedWidgetOfExactType<TestWidget>());
      }
    }
    

    And wrap your MyApp Widget(Root Widget) TestWidget in main.dart

    main.dart

    runApp(TestWidget(child: MyApp()));

    Now you can save 'image path' in New Event Page.

    New Event Page

      @override
      Widget build(BuildContext context) {
    
        // you have to write code in build method
        final info = TestWidget.of(context);
        info.data = image;  //String
    

    And then, go to UpcomingEventTile and use it.

    UpcomingEventTile

      @override
      Widget build(BuildContext context) {
    
        final info = TestWidget.of(context);
         ...
          ClipOval(
              child: Image.file(info.data,
              width: 125, height: 125, fit: BoxFit.cover),
          )
          ...