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,
),
),
);
},
),
);
},
),
),
),
],
)
],
),
),
),
],
),
),
);
}
}
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),
)
...