0% found this document useful (0 votes)
11 views46 pages

Flutter Quiz App Learning Guide

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views46 pages

Flutter Quiz App Learning Guide

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

COMPLETE_FLUTTER_LEARNING_GUIDE.

md 2025-11-20

Complete Flutter Learning Guide: Quiz App Project


1. Quick Project Summary
This is a Flutter quiz app with three screens. Users start on a welcome screen, answer 6 multiple-choice
questions one at a time, and then see results with a summary of correct/incorrect answers. The app tracks
selected answers and shows a scrollable summary at the end with correct answers highlighted.
Main screens: StartScreen, QuestionsScreen, ResultsScreen
Key packages: google_fonts: ^6.3.2
Main files:
lib/[Link] - Entry point
lib/[Link] - Main state management widget
lib/start_screen.dart - Welcome screen
lib/questions_screen.dart - Quiz questions display
lib/results_screen.dart - Results display
lib/data/[Link] - Quiz questions data
lib/models/quiz_questions.dart - QuizQuestion class
lib/answer_button.dart - Custom button widget
lib/questions_summary/ - Summary-related widgets

2. Learning Objectives
. Understand the difference between StatelessWidget and StatefulWidget and when to use
each
. Understand setState() and how it triggers UI rebuilds
. Use conditional rendering to switch screens
. Pass callback functions between widgets
. Create custom widgets for reusable UI
. Use Lists and Maps for data
. Use [Link]() and the spread operator (...) to build widget lists
. Structure data with classes and methods
. Use Google Fonts and asset images
. Implement scrolling widgets (SingleChildScrollView)
. Work with Row, Column, Expanded, and SizedBox for layouts
. Use Container with decorations (gradients, borders, colors)
3. Concept Map
. Dart Basics → Classes, Lists, Maps
Appears in: lib/models/quiz_questions.dart, lib/data/[Link],
lib/results_screen.dart

. Widgets (StatelessWidget) → Building UI without changing data

1 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Appears in: lib/start_screen.dart, lib/answer_button.dart,


lib/results_screen.dart, lib/questions_summary/

. StatefulWidget & State → Managing changing data


Appears in: lib/[Link] (lines 9-79), lib/questions_screen.dart (lines 7-67)
. setState() → Updating UI when data changes
Appears in: lib/[Link] (lines 23, 32, 39), lib/questions_screen.dart (line 28)
. Conditional Rendering → Showing different screens based on state
Appears in: lib/[Link] (lines 47-60)
. Callback Functions → Passing functions as parameters
Appears in: lib/start_screen.dart (line 7), lib/questions_screen.dart (line 13),
lib/[Link] (line 51)

. Widget Composition → Building complex UIs from simple widgets


Throughout: Custom widgets like AnswerButton, QuestionIdentifier, etc.
. Layout Widgets → Arranging widgets (Column, Row, Expanded, SizedBox)
Throughout: lib/start_screen.dart, lib/questions_screen.dart,
lib/questions_summary/

. Lists & Map Operations → Transforming data into widgets


Appears in: lib/questions_screen.dart (line 55),
lib/questions_summary/questions_summary.dart (line 15),
lib/results_screen.dart (line 32)
. Styling & Theming → Colors, fonts, decorations
Throughout: BoxDecoration, GoogleFonts, [Link]
. Assets & Images → Loading images from project
Appears in: lib/start_screen.dart (line 15), [Link] (line 63)
. Scrollable Content → Making content scrollable
Appears in: lib/questions_summary/questions_summary.dart (line 13)
4. Progressive Lessons
Lesson 1: Understanding Widgets (StatelessWidget)
Explanation: A StatelessWidget is like a snapshot — it never changes once created. Use it for UI that
doesn't depend on changing data.

2 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Why it matters: Flutter uses widgets for everything. Stateless widgets are simple, predictable, and
performant for static UI.
Code from project:

// lib/start_screen.dart, lines 4-47


class StartScreen extends StatelessWidget { // This widget can't change
const StartScreen([Link], {[Link]}); // Constructor receives
a function

final void Function() startQuiz; // Stores a callback function

@override
Widget build(context) { // build() method builds the UI
return Center( // Centers its child widget
child: Column( // Arranges children vertically
mainAxisSize: [Link], // Column takes minimum space
needed
children: [ // List of child widgets
[Link]( // Displays image from assets folder
'assets/images/[Link]',
width: 300, // Sets image width
color: const [Link](150, 255, 255, 255), // Tints
image (opacity 150/255)
),
const SizedBox(height: 80), // Adds 80 pixels of vertical space
Text( // Displays text
'Learn Flutter the fun way!',
style: [Link]( // Uses Google Fonts package
color: const [Link](255, 237, 223, 252), // Text
color (ARGB format)
fontSize: 24, // Font size
),
),
const SizedBox(height: 30), // More spacing
[Link]( // Button with icon and label
onPressed: startQuiz, // Calls the callback when pressed
style: [Link](
foregroundColor: [Link], // Text/icon color
),
icon: const Icon(Icons.arrow_right_alt), // Icon widget
label: const Text('Start Quiz'), // Button text
)
],
),
);
}
}

Minimal example:
3 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
const Text('Hello Flutter!'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
print('Button pressed!');
},
child: const Text('Click Me'),
),
],
),
),
),
);
}
}

Practice exercises:
. Easy: Create a StatelessWidget that displays your name and age.
Expected: Text showing "Name: [Your Name], Age: [Your Age]"
Hint: Use Text widget with string interpolation: 'Name: $name'
. Moderate: Create a StatelessWidget with three buttons in a Column.
Expected: Three buttons stacked vertically
Hint: Each button needs an onPressed callback (can be empty: () {})
. Challenging: Create a reusable Card widget that takes a title and description as parameters.
Expected: A card with title and description that can be reused
Hint: Add final String title; and final String description; to your widget class
Quick quiz:
4 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Q1: Can a StatelessWidget change its appearance after it's built?


Q2: What method must every widget implement?

Lesson 2: StatefulWidget and State Management


Explanation: A StatefulWidget can change. It has a companion State class that holds data that can
change, and when that data changes, the UI rebuilds. Like a thermostat with a temperature that can
change.
Why it matters: Most real apps need to respond to user input and update the UI. StatefulWidgets enable
this.
Code from project:

// lib/[Link], lines 9-79


class Quiz extends StatefulWidget { // Widget that can change
const Quiz({[Link]});

@override
State<Quiz> createState() { // Creates the State object
return _QuizState(); // Returns a new State instance
}
}

class _QuizState extends State<Quiz> { // Private State class (underscore


= private)
List<String> selectedAnswers = []; // Mutable data - list of user
answers
var activeScreen = 'start-screen'; // Mutable data - current screen
identifier

void switchScreen() { // Method to change screens


setState(() { // setState() tells Flutter: "data changed, rebuild UI"
activeScreen = 'questions-screen'; // Update the screen identifier
});
}

void chooseAnswer(String answer) { // Method to handle answer selection


[Link](answer); // Add answer to list (mutates list)

if ([Link] == [Link]) { // Check if quiz is


complete
setState(() { // Update UI
activeScreen = 'results-screen'; // Switch to results screen
});
}
}

void restartQuiz() { // Method to reset quiz


setState(() {
selectedAnswers = []; // Clear the answers list

5 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

activeScreen = 'questions-screen'; // Go back to questions


});
}

@override
Widget build(context) { // Build method runs after setState()
Widget screenWidget = StartScreen(switchScreen); // Default screen

if (activeScreen == 'questions-screen') { // Conditional: check state


screenWidget = QuestionsScreen( // Build questions screen
onSelectAnswer: chooseAnswer, // Pass callback function
);
}

if (activeScreen == 'results-screen') { // Another condition


screenWidget = ResultsScreen( // Build results screen
chosenAnswers: selectedAnswers, // Pass data to screen
onRestart: restartQuiz, // Pass callback
);
}

return MaterialApp(
home: Scaffold(
body: Container(
decoration: const BoxDecoration( // Decorates container
gradient: LinearGradient( // Gradient background
colors: [
[Link](255, 78, 13, 151), // Start color
[Link](255, 107, 15, 168), // End color
],
begin: [Link], // Gradient start point
end: [Link], // Gradient end point
),
),
child: screenWidget, // Display the current screen
),
),
);
}
}

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const CounterApp());
}

class CounterApp extends StatefulWidget {


const CounterApp({[Link]});

6 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

@override
State<CounterApp> createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {


int counter = 0; // This is the state data

void incrementCounter() {
setState(() { // Must wrap changes in setState()
counter++; // Increment the counter
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
Text('Counter: $counter'), // Display state
ElevatedButton(
onPressed: incrementCounter, // Call method when pressed
child: const Text('Increment'),
),
],
),
),
),
);
}
}

Practice exercises:
. Easy: Create a StatefulWidget with a counter that goes from 0 to 5.
Expected: Button that increments counter displayed on screen
Hint: Use setState(() { counter++; }) inside button's onPressed
. Moderate: Create a toggle button that switches between "ON" and "OFF".
Expected: Button that toggles between two states
Hint: Use a bool isOn = false; and toggle it with !isOn in setState
. Challenging: Create a list that adds items when a button is pressed.
Expected: List of items that grows when button is clicked
Hint: Use List<String> items = []; and [Link]('Item $i'); in setState
Quick quiz:
7 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Q1: Why do you need to wrap state changes in setState()?


Q2: What happens if you modify a variable outside of setState()?

Lesson 3: Passing Functions as Callbacks


Explanation: In Flutter, widgets communicate up the tree by passing functions (callbacks). The parent
gives the child a function to call, like giving someone a remote to notify you.
Why it matters: Child widgets can notify parents without direct references, keeping widgets reusable and
testable.
Code from project:

// lib/start_screen.dart, lines 4-7


class StartScreen extends StatelessWidget {
const StartScreen([Link], {[Link]}); // Receives function as
parameter

final void Function() startQuiz; // Type: function that takes no


params, returns void

// lib/[Link], line 47
Widget screenWidget = StartScreen(switchScreen); // Pass function
reference

// lib/start_screen.dart, line 37
onPressed: startQuiz, // Call the function when button is pressed

// lib/questions_screen.dart, lines 13 and 25


final void Function(String answer) onSelectAnswer; // Function that takes
String

void answerQuestion(String selectedAnswer) {


[Link](selectedAnswer); // Call parent's function with
answer
}

Minimal example:

import 'package:flutter/[Link]';

void main() {

8 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

runApp(const MyApp());
}

class MyApp extends StatefulWidget {


const MyApp({[Link]});

@override
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


String message = 'No button pressed yet';

void handleButtonPress() { // Function in parent


setState(() {
message = 'Button was pressed!';
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
Text(message),
const SizedBox(height: 20),
CustomButton(
onPress: handleButtonPress, // Pass function to child
),
],
),
),
),
);
}
}

class CustomButton extends StatelessWidget {


const CustomButton({[Link], required [Link]});

final void Function() onPress; // Receive function from parent

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPress, // Call function when pressed
child: const Text('Press Me'),
);
}
}

9 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Practice exercises:
. Easy: Create a child widget that calls a parent function to update a text message.
Expected: Button in child widget changes text in parent
Hint: Pass void Function(String) and call it with different messages
. Moderate: Create a parent with a counter and a child button that increments it.
Expected: Counter displayed in parent, button in child increments it
Hint: Pass void Function() callback from parent to child
. Challenging: Create a form with multiple input fields that all report back to parent.
Expected: Multiple text fields that update parent's state when changed
Hint: Each field needs its own callback or use a single callback with an identifier
Quick quiz:
Q1: Why use callbacks instead of direct state access?
Q2: What's the type signature for a function that takes an int and returns nothing?

Lesson 4: Lists, Maps, and Data Models


Explanation: Lists store ordered items; Maps store key-value pairs. Classes model data with properties and
methods. Together, they structure app data.
Why it matters: Apps work with structured data. Lists, Maps, and classes help organize and manipulate it.
Code from project:

// lib/models/quiz_questions.dart, lines 1-12


class QuizQuestion { // Custom class to represent a quiz question
const QuizQuestion([Link], [Link]); // Constructor with
positional params

final String text; // Immutable property: question text


final List<String> answers; // Immutable property: list of answer
options

List<String> getShuffledAnswers() { // Method: returns shuffled answers


final shuffledList = [Link](answers); // Create copy of answers list
[Link](); // Shuffle the copy (mutates it)
return shuffledList; // Return shuffled list
}
}

// lib/data/[Link], lines 3-54


const questions = [ // Const list of QuizQuestion objects
10 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

QuizQuestion( // Create QuizQuestion instance


'What are the main building blocks of Flutter UIs?', // First param:
text
[ // Second param: list of answers
'Widgets',
'Components',
'Blocks',
'Functions',
],
),
QuizQuestion('How are Flutter UIs built?', [ // Another question
'By combining widgets in code',
// ... more answers
]),
// ... more questions
];

// lib/results_screen.dart, lines 13-26


List<Map<String, Object>> getSummaryData() { // Returns list of Maps
final List<Map<String, Object>> summary = []; // Initialize empty list

for (var i = 0; i < [Link]; i++) { // Loop through


indices
[Link]({ // Add Map to list
'question_index': i, // Map key 'question_index' -> value i
'question': questions[i].text, // Access question text
'correct_answer': questions[i].answers[0], // First answer is
correct
'user_answer': chosenAnswers[i], // User's selected answer
});
}

return summary; // Return the list of maps


}

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

// Data model class


class Person {
const Person([Link], [Link]);

final String name;


final int age;

11 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

String get description => '$name is $age years old';


}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

// List of Person objects


final List<Person> people = const [
Person('Alice', 25),
Person('Bob', 30),
Person('Charlie', 35),
];

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView( // Scrollable list
children: [Link]((person) { // Transform each Person to
Widget
return ListTile(
title: Text([Link]),
subtitle: Text('Age: ${[Link]}'),
);
}).toList(), // Convert iterable to List
),
),
);
}
}

Practice exercises:
. Easy: Create a Book class with title and author properties. Create a list of 3 books.
Expected: Class definition and list of Book instances
Hint: Use final String title; and final String author; in class
. Moderate: Create a method on a class that returns a formatted string.
Expected: Method like String getInfo() that returns "Title by Author"
Hint: Use string interpolation: '$title by $author'
. Challenging: Create a list of Maps, each containing person data, then display them in a ListView.
Expected: ListView showing people's names and ages from Maps
Hint: Use [Link]((person) => ListTile(...)).toList()
Quick quiz:
Q1: What's the difference between List and Map?
Q2: What does const mean when declaring a list?
12 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Lesson 5: Transforming Lists into Widgets ([Link]())


Explanation: [Link]() transforms each item into something else. In Flutter, you often map data to
widgets. The spread operator (...) unpacks a list into another list.
Why it matters: Dynamic UIs need to build widgets from data. map() and the spread operator make this
concise.
Code from project:

// lib/questions_screen.dart, lines 55-62


...[Link]().map((answer) { // Spread operator
+ map
return AnswerButton( // Transform each String answer into AnswerButton
widget
answerText: answer, // Pass the answer string
onTap: () { // Anonymous function (closure) as callback
answerQuestion(answer); // Call method with this specific answer
},
);
})

Explanation:
[Link]() returns List<String>
.map((answer) { ... }) transforms each String into an AnswerButton
... (spread) unpacks the list of AnswerButtons into the children list

// lib/questions_summary/questions_summary.dart, lines 15-17


children: [Link]((data) { // Transform each Map into SummaryItem
return SummaryItem(itemData: data); // Create widget from data
}).toList(), // Convert Iterable to List (required for children)

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

final List<String> fruits = ['Apple', 'Banana', 'Orange'];

@override
13 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Widget build(BuildContext context) {


return MaterialApp(
home: Scaffold(
body: Column(
children: [
const Text('My Fruits:'),
...[Link]((fruit) { // Spread operator + map
return ListTile(
title: Text(fruit),
leading: const Icon(Icons.fruit_grapes),
);
}),
// OR without spread (if not mixing with other widgets):
// children: [Link]((fruit) => Text(fruit)).toList(),
],
),
),
);
}
}

Practice exercises:
. Easy: Display a list of names as Text widgets using .map().
Expected: Column showing each name as separate Text widget
Hint: children: [Link]((name) => Text(name)).toList()
. Moderate: Create a list of numbers and display each as an ElevatedButton.
Expected: Buttons for each number
Hint: Use ...[Link]((num) => ElevatedButton(...))
. Challenging: Create a list of objects and map them to custom widgets with different colors.
Expected: Each object displayed in a colored container
Hint: Use index in map: [Link]().[Link]((entry) { ... [Link]
... })

Quick quiz:
Q1: What does the spread operator (...) do?
Q2: Why do you need .toList() sometimes but not always?

Lesson 6: Layout Widgets (Column, Row, Expanded, SizedBox)


Explanation: Layout widgets arrange children. Column stacks vertically, Row horizontally. Expanded fills
available space. SizedBox adds spacing or sets size.
Why it matters: Proper layout makes UIs look good and responsive across screen sizes.
Code from project:
14 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// lib/questions_screen.dart, lines 41-43


Column(
mainAxisAlignment: [Link], // Center vertically
crossAxisAlignment: [Link], // Stretch children
horizontally
children: [ // Children widgets

// lib/questions_summary/summary_item.dart, lines 18-51


Row( // Arrange horizontally
crossAxisAlignment: [Link], // Align at top
children: [
QuestionIdentifier(...), // First child
const SizedBox(width: 20), // Horizontal spacing
Expanded( // Takes remaining horizontal space
child: Column( // Nested column
crossAxisAlignment: [Link], // Left-align text
children: [
Text(...), // Question text
const SizedBox(height: 5), // Vertical spacing
Text(...), // User answer
const SizedBox(height: 3), // More spacing
Text(...), // Correct answer
],
),
),
],
)

// lib/start_screen.dart, line 13
mainAxisSize: [Link], // Column only takes minimum space needed

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
15 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

body: Center(
child: Column(
mainAxisAlignment: [Link], // Center
vertically
crossAxisAlignment: [Link], // Center
horizontally
children: [
const Text('First Item'),
const SizedBox(height: 20), // Add 20px spacing
Row(
mainAxisAlignment: [Link],
children: [
Container(
width: 50,
height: 50,
color: [Link],
),
const SizedBox(width: 10), // Horizontal spacing
Expanded( // Fills remaining space
child: Container(
height: 50,
color: [Link],
),
),
],
),
const SizedBox(height: 20),
const Text('Last Item'),
],
),
),
),
);
}
}

Practice exercises:
. Easy: Create a Column with three Text widgets and spacing between them.
Expected: Three text items with gaps
Hint: Use SizedBox(height: 10) between items
. Moderate: Create a Row with a small icon, text, and a button that fills remaining space.
Expected: Icon, text, and expanded button in a row
Hint: Use Expanded around the button widget
. Challenging: Create a responsive layout that works in both portrait and landscape.
Expected: Layout adapts to screen orientation
Hint: Use MediaQuery and conditional Row/Column based on orientation
16 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Quick quiz:
Q1: What's the difference between mainAxisAlignment and crossAxisAlignment?
Q2: When should you use Expanded?

Lesson 7: Styling with Colors, Fonts, and Decorations


Explanation: Flutter uses Color, TextStyle, and BoxDecoration to style widgets. Google Fonts
provides web fonts. Colors can be specified in multiple formats.
Why it matters: Visual design makes apps appealing and usable.
Code from project:

// lib/[Link], lines 65-73


decoration: const BoxDecoration( // Adds visual styling to container
gradient: LinearGradient( // Creates color gradient
colors: [ // List of colors in gradient
[Link](255, 78, 13, 151), // ARGB: Alpha, Red, Green, Blue
(0-255 each)
[Link](255, 107, 15, 168),
],
begin: [Link], // Where gradient starts
end: [Link], // Where gradient ends
),
),

// lib/start_screen.dart, lines 30-33


style: [Link]( // Use Google Fonts package
color: const [Link](255, 237, 223, 252), // Text color
fontSize: 24, // Size in logical pixels
),

// lib/answer_button.dart, lines 23-27


backgroundColor: const [Link](255, 33, 1, 95), // Button
background
foregroundColor: [Link], // Predefined color constant
shape: RoundedRectangleBorder( // Custom button shape
borderRadius: [Link](40), // Rounded corners
),

// lib/questions_summary/question_identifier.dart, lines 20-23


decoration: BoxDecoration(
color: isCorrectAnswer ? [Link] : [Link], // Conditional
color
17 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

borderRadius: [Link](100), // Circular (perfect circle)


),

Minimal example:

import 'package:flutter/[Link]';
import 'package:google_fonts/google_fonts.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [[Link], [Link]],
begin: [Link],
end: [Link],
),
),
child: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
Text(
'Styled Text',
style: [Link](
fontSize: 32,
color: [Link],
fontWeight: [Link],
),
),
const SizedBox(height: 20),
Container(
padding: const [Link](20),
decoration: BoxDecoration(
color: [Link],
borderRadius: [Link](10),
boxShadow: [
BoxShadow(
color: [Link](0.2),
blurRadius: 5,
offset: const Offset(0, 3),
),
],
18 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

),
child: const Text('Box with decoration'),
),
],
),
),
),
),
);
}
}

Practice exercises:
. Easy: Create a Container with a custom background color and rounded corners.
Expected: Colored container with rounded corners
Hint: Use BoxDecoration with color and borderRadius
. Moderate: Use Google Fonts to style different Text widgets with different fonts.
Expected: Multiple text widgets with different font families
Hint: Try [Link](), [Link](), etc.
. Challenging: Create a card with gradient background, shadow, and custom border.
Expected: Card with multiple styling properties
Hint: Combine BoxDecoration with gradient, boxShadow, and border
Quick quiz:
Q1: What does ARGB stand for in [Link]()?
Q2: How do you add shadows to a Container?

Lesson 8: Working with Assets (Images)


Explanation: Assets are files bundled with your app (images, fonts, data). Declare them in [Link]
and load them in code.
Why it matters: Images and other assets enhance the UI. Understanding asset management is essential.
Code from project:

// [Link], lines 62-63


assets:
- assets/images/[Link] // Declare image asset

// lib/start_screen.dart, lines 15-19


[Link]( // Load image from assets folder
19 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

'assets/images/[Link]', // Path relative to project root


width: 300, // Set width (height scales proportionally)
color: const [Link](150, 255, 255, 255), // Tint color (opacity
150/255)
),

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
// Load image from assets
[Link](
'assets/images/[Link]', // Make sure this file
exists!
width: 200,
),
const SizedBox(height: 20),
// Image with color tint
[Link](
'assets/images/[Link]',
width: 200,
color: [Link](0.5), // Blue tint at 50%
opacity
),
],
),
),
),
);
}
}

Practice exercises:
. Easy: Add an image to your project and display it.
20 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Expected: Image visible on screen


Hint: Don't forget to add the path in [Link] and run flutter pub get
. Moderate: Display an image with different sizes and opacity levels.
Expected: Multiple versions of same image with different styles
Hint: Use width, height, and color properties
. Challenging: Create an image gallery that displays multiple images in a scrollable grid.
Expected: GridView with multiple images
Hint: Use [Link]() with [Link]()
Quick quiz:
Q1: Where do you declare assets in a Flutter project?
Q2: What happens if you reference an asset that doesn't exist?

Lesson 9: Scrollable Content (SingleChildScrollView)


Explanation: SingleChildScrollView makes content scrollable when it exceeds screen size. Use it to
prevent overflow errors.
Why it matters: Content often exceeds screen space. Scrolling enables access to all content.
Code from project:

// lib/questions_summary/questions_summary.dart, lines 11-20


return SizedBox(
height: 400, // Fixed height container
child: SingleChildScrollView( // Makes content scrollable
child: Column( // Scrollable column
children: [Link]((data) {
return SummaryItem(itemData: data); // List of items
}).toList(),
),
),
);

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


const MyApp({[Link]});

21 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SingleChildScrollView( // Wraps scrollable content
child: Column(
children: [Link](50, (index) { // Generate 50 widgets
return ListTile(
title: Text('Item ${index + 1}'),
leading: const Icon([Link]),
);
}),
),
),
),
);
}
}

Practice exercises:
. Easy: Create a scrollable list of 20 Text widgets.
Expected: Vertical scrollable list
Hint: Wrap Column with SingleChildScrollView
. Moderate: Create a scrollable form with multiple input fields.
Expected: Form that scrolls when keyboard appears
Hint: Wrap your form widget with SingleChildScrollView
. Challenging: Create both horizontal and vertical scrollable sections.
Expected: Content that scrolls in both directions
Hint: Nest SingleChildScrollView widgets or use ListView with scrollDirection
Quick quiz:
Q1: When should you use SingleChildScrollView?
Q2: What's the difference between SingleChildScrollView and ListView?

Lesson 10: Conditional Rendering and State-Based UI


Explanation: Conditional rendering shows different UI based on state. Use if statements or ternary
operators to switch between widgets.
Why it matters: Apps need to show different screens/views based on user actions and state. Conditional
rendering enables this.
Code from project:
22 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// lib/[Link], lines 47-60


Widget screenWidget = StartScreen(switchScreen); // Default screen

if (activeScreen == 'questions-screen') { // Check state condition


screenWidget = QuestionsScreen( // Build different widget
onSelectAnswer: chooseAnswer,
);
}

if (activeScreen == 'results-screen') { // Another condition


screenWidget = ResultsScreen(
chosenAnswers: selectedAnswers,
onRestart: restartQuiz,
);
}

return MaterialApp(
// ...
child: screenWidget, // Display the widget based on condition
);

Minimal example:

import 'package:flutter/[Link]';

void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {


const MyApp({[Link]});

@override
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


bool showDetails = false; // State variable

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: [Link],
children: [
// Conditional rendering with ternary operator
showDetails
? const Text('Details are visible!')
: const Text('Click to show details'),
23 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

const SizedBox(height: 20),


ElevatedButton(
onPressed: () {
setState(() {
showDetails = !showDetails; // Toggle state
});
},
child: Text(showDetails ? 'Hide' : 'Show'),
),
],
),
),
),
);
}
}

Practice exercises:
. Easy: Show different text based on a boolean state.
Expected: Text changes when button is pressed
Hint: Use ternary operator: condition ? widget1 : widget2
. Moderate: Create a login/logout button that shows different UI for each state.
Expected: Different widgets shown based on login status
Hint: Use if statements or ternary operators
. Challenging: Create a multi-step form that shows different steps based on completion state.
Expected: Form that progresses through steps
Hint: Use a step counter and conditionally render different form sections
Quick quiz:
Q1: What's the difference between using if statements and ternary operators for conditional
rendering?
Q2: When should you use conditional rendering?

5. Code Walkthrough & Inline Improvements


Current Code Analysis
File: lib/[Link]
BEFORE (Current Code):

class _QuizState extends State<Quiz> {


List<String> selectedAnswers = [];

24 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

var activeScreen = 'start-screen';


// ...
}

AFTER (Improved):

class _QuizState extends State<Quiz> {


List<String> selectedAnswers = [];
String activeScreen = 'start-screen'; // Better: explicit type instead
of 'var'

// Consider using enum for better type safety:


// enum Screen { start, questions, results }
// Screen activeScreen = [Link];

// ...
}

Improvements:
. Line 20: Use explicit String type instead of var
. Better approach: Use an enum for screen states (see suggestion above)
. Lines 49, 55: Multiple if statements could be replaced with if-else or switch
Suggested refactor:

// Better pattern for screen management


Widget _buildCurrentScreen() {
switch (activeScreen) {
case 'questions-screen':
return QuestionsScreen(onSelectAnswer: chooseAnswer);
case 'results-screen':
return ResultsScreen(
chosenAnswers: selectedAnswers,
onRestart: restartQuiz,
);
case 'start-screen':
default:
return StartScreen(switchScreen);
}
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(

25 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

colors: [
[Link](255, 78, 13, 151),
[Link](255, 107, 15, 168),
],
begin: [Link],
end: [Link],
),
),
child: _buildCurrentScreen(), // Cleaner
),
),
);
}

File: lib/questions_screen.dart
Issue: No bounds checking for currentQuestionIndex
Risk: If user somehow skips questions, could cause RangeError
Fix:

@override
Widget build(BuildContext context) {
// Safety check
if (currentQuestionIndex >= [Link]) {
return const Center(child: Text('No more questions'));
}

final currentQuestion = questions[currentQuestionIndex];


// ... rest of code
}

File: lib/results_screen.dart
Issue: Line 46 - Missing const keyword

// BEFORE:
style: [Link](
color: [Link](255, 230, 200, 253), // Missing 'const'

// AFTER:
style: [Link](
color: const [Link](255, 230, 200, 253), // Add 'const'

Issue: Line 58 - Missing const on Icon

26 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// BEFORE:
icon: Icon([Link]),

// AFTER:
icon: const Icon([Link]),

Performance suggestion: The getSummaryData() method is called on every build. Consider memoizing:

late final List<Map<String, Object>> _summaryData;

@override
void initState() {
[Link]();
_summaryData = getSummaryData();
}

// Then use _summaryData instead of calling getSummaryData() in build

File: lib/answer_button.dart
Current code is good! This is a well-structured reusable widget.
Optional enhancement: Add disabled state

final bool isEnabled;

const AnswerButton({
[Link],
required [Link],
required [Link],
[Link] = true, // Add default parameter
});

// In build:
onPressed: isEnabled ? onTap : null, // Disable button

File: lib/data/[Link]
Good practice: Using const for immutable data.
Enhancement suggestion: Add question IDs for better tracking

class QuizQuestion {
const QuizQuestion([Link], [Link], [Link]); // Add ID
final String id;

27 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// ...
}

File: test/widget_test.dart
Issue: Test references MyApp which doesn't exist in this project.
Fix:

import 'package:flutter/[Link]';
import 'package:flutter_test/flutter_test.dart';
import 'package:adv_basics/[Link]';
import 'package:adv_basics/[Link]';

void main() {
testWidgets('Quiz app starts with start screen', (WidgetTester tester)
async {
await [Link](const Quiz()); // Use Quiz widget

// Verify start screen is shown


expect([Link]('Learn Flutter the fun way!'), findsOneWidget);
expect([Link]('Start Quiz'), findsOneWidget);
});
}

6. State & Data Flow Analysis


State Flow Diagram
[Link]
└──> Quiz (StatefulWidget) ← MAIN STATE HOLDER

├── State Variables:
│ ├── selectedAnswers: List<String> ← Tracks user answers
│ └── activeScreen: String ← Controls which screen is shown

├── State Methods:
│ ├── switchScreen() ← Changes activeScreen to 'questions-
screen'
│ ├── chooseAnswer(String) ← Adds answer, checks if quiz
complete
│ └── restartQuiz() ← Resets state

└── Child Widgets:
├── StartScreen(switchScreen) ← Receives callback, no state

├── QuestionsScreen(onSelectAnswer: chooseAnswer) ← HAS OWN
STATE
28 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

│ ├── State: currentQuestionIndex ← Tracks current question


│ └── Calls: [Link](answer) ← Notifies parent

└── ResultsScreen(chosenAnswers, onRestart) ← Receives data,
callback
└── Computes: getSummaryData() ← Transforms data for
display

Data Flow Explanation


. Initial State: App starts with activeScreen = 'start-screen' and empty selectedAnswers.
. Starting Quiz:
User clicks "Start Quiz" → calls switchScreen() callback
switchScreen() calls setState() → sets activeScreen = 'questions-screen'
[Link]() runs → creates QuestionsScreen

. Answering Questions:
QuestionsScreen maintains its own currentQuestionIndex
User selects answer → answerQuestion() called
Calls [Link](answer) → bubbles up to parent's chooseAnswer()
Parent's chooseAnswer() adds answer to selectedAnswers list
If all questions answered → setState() changes activeScreen = 'results-screen'
[Link]() increments currentQuestionIndex → shows next
question
. Showing Results:
[Link]() creates ResultsScreen with selectedAnswers list
[Link]() transforms list into list of Maps
Data flows down: Quiz → ResultsScreen → QuestionsSummary → SummaryItem
State Management Pattern Used
Pattern: Lifting State Up (Flutter's basic pattern)
Main state lives in parent (Quiz)
Child widgets receive callbacks to update parent
Child widgets can have their own local state (QuestionsScreen)
No external state management: This project doesn't use Provider, Bloc, Riverpod, etc.
Async Code Analysis
No async code found in this project. All operations are synchronous.
If you add async code in the future:

29 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// Good pattern for async operations


Future<void> loadQuestions() async {
try {
final questions = await fetchQuestionsFromAPI();
setState(() {
[Link] = questions;
});
} catch (error) {
// Handle error
print('Error loading questions: $error');
}
}

7. UI & Layout Debugging Checklist


Widget Tree for Main Screen
MaterialApp
└── Scaffold
└── Container (with gradient decoration)
└── screenWidget (changes based on state)

├── StartScreen
│ └── Center
│ └── Column
│ ├── [Link]
│ ├── SizedBox
│ ├── Text
│ ├── SizedBox
│ └── [Link]

├── QuestionsScreen
│ └── SizedBox
│ └── Container (with margin)
│ └── Column
│ ├── Text (question)
│ ├── SizedBox
│ └── ...AnswerButton widgets

└── ResultsScreen
└── SizedBox
└── Container (with margin)
└── Column
├── Text (score)
├── SizedBox
├── QuestionsSummary
│ └── SizedBox
│ └── SingleChildScrollView
│ └── Column

30 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

│ └── ...SummaryItem widgets


├── SizedBox
└── [Link]

Potential Layout Issues


. Fixed margins might cause overflow on small screens
Location: lib/questions_screen.dart line 40, lib/results_screen.dart line 39
Issue: [Link](40) might be too large for small devices
Fix:

// Use MediaQuery for responsive margins


margin: [Link]([Link](context).[Link] * 0.05),
// OR use safe area
margin: [Link]([Link](context).[Link] + 20),

. Fixed height in QuestionsSummary


Location: lib/questions_summary/questions_summary.dart line 12
Issue: height: 400 might not fit all content or waste space
Fix:

// Use Expanded or remove fixed height


Expanded(
child: SingleChildScrollView(
// ... rest of code
),
)

. Hard-coded widths
Location: lib/start_screen.dart line 17
Issue: width: 300 might not work on all screen sizes
Fix:

width: [Link](context).[Link] * 0.8, // 80% of screen


width
// OR
constraints: const BoxConstraints(maxWidth: 300),

. Missing SafeArea
Issue: Content might go under notches/status bars
Fix: Wrap main content in SafeArea widget
31 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

return MaterialApp(
home: Scaffold(
body: SafeArea( // Add this
child: Container(
// ... rest of code
),
),
),
);

Accessibility Improvements
. Add semantic labels:

// For buttons
Semantics(
label: 'Start Quiz Button',
child: [Link](...),
)

// For images
Semantics(
label: 'Quiz logo',
child: [Link](...),
)

. Support dynamic text scaling:

// Instead of fixed fontSize


fontSize: 24,

// Use Theme text styles that respect user preferences


style: [Link](context).[Link],

. Add accessibility for answer buttons:

// In AnswerButton widget
Semantics(
button: true,
label: 'Answer option: $answerText',
child: ElevatedButton(...),
)

Internationalization (i18n)
32 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Currently not implemented. To add:


. Add flutter_localizations to [Link]
. Create ARB files for translations
. Wrap app in Localizations widget
. Use [Link](context) instead of hard-coded strings

8. Testing & Debugging


Recommended Tests
Unit Test Example

// test/models/quiz_questions_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:adv_basics/models/quiz_questions.dart';

void main() {
group('QuizQuestion', () {
test('getShuffledAnswers returns all answers', () {
const question = QuizQuestion('Test?', ['A', 'B', 'C', 'D']);
final shuffled = [Link]();

expect([Link], 4);
expect([Link]('A'), true);
expect([Link]('B'), true);
expect([Link]('C'), true);
expect([Link]('D'), true);
});

test('getShuffledAnswers returns different order', () {


const question = QuizQuestion('Test?', ['A', 'B']);
// Note: There's a 50% chance this test fails, but it's unlikely
// after multiple shuffles
final results = <String>[];
for (int i = 0; i < 10; i++) {
[Link]([Link]().join(','));
}
expect([Link]().length, greaterThan(1)); // At least 2
different orders
});
});
}

Widget Test Example

// test/widget/quiz_test.dart
import 'package:flutter/[Link]';

33 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

import 'package:flutter_test/flutter_test.dart';
import 'package:adv_basics/[Link]';
import 'package:adv_basics/[Link]';

void main() {
testWidgets('Quiz app shows start screen initially', (tester) async {
await [Link](const Quiz());

// Verify start screen elements are present


expect([Link]('Learn Flutter the fun way!'), findsOneWidget);
expect([Link]('Start Quiz'), findsOneWidget);
expect([Link](Image), findsOneWidget);
});

testWidgets('Tapping start quiz button navigates to questions screen',


(tester) async {
await [Link](const Quiz());

// Find and tap the start button


await [Link]([Link]('Start Quiz'));
await [Link](); // Trigger frame update

// Verify questions screen is shown


expect([Link](QuestionsScreen), findsOneWidget);
});

testWidgets('Answering all questions shows results screen', (tester)


async {
await [Link](const Quiz());

// Start quiz
await [Link]([Link]('Start Quiz'));
await [Link]();

// Answer all questions (assuming 6 questions)


for (int i = 0; i < 6; i++) {
// Tap first answer button
await [Link]([Link](ElevatedButton).first);
await [Link]();
}

// Verify results screen is shown


expect([Link]('out of'), findsOneWidget);
expect([Link]('Restart Quiz!'), findsOneWidget);
});

testWidgets('Restart quiz button resets the quiz', (tester) async {


await [Link](const Quiz());

// Complete quiz
await [Link]([Link]('Start Quiz'));
await [Link]();

for (int i = 0; i < 6; i++) {


34 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

await [Link]([Link](ElevatedButton).first);
await [Link]();
}

// Tap restart
await [Link]([Link]('Restart Quiz!'));
await [Link]();

// Verify back to questions screen


expect([Link](QuestionsScreen), findsOneWidget);
});
}

Debugging Tips
. Flutter DevTools:
Run flutter pub global activate devtools
Use flutter run and open DevTools
Inspect widget tree, check performance, view logs
. Print debugging:

void chooseAnswer(String answer) {


print('Answer chosen: $answer'); // See in console
print('Current answers: $selectedAnswers');

[Link](answer);
// ...
}

. Breakpoints:
Set breakpoints in VS Code/Android Studio
Inspect variables, step through code
Check call stack
. Common issues:
Overflow errors: Wrap in SingleChildScrollView or use Expanded
setState() errors: Make sure setState() is called from State class
Build context errors: Don't use BuildContext after async operations
Null errors: Use null safety (?, !, ??)

9. Performance & Best Practices


Performance Issues Found
. Recomputing summary data on every build
35 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Location: lib/results_screen.dart line 30


Issue: getSummaryData() is called in build() method
Fix: Convert to StatefulWidget and compute once

class ResultsScreen extends StatefulWidget {


// ... existing code
}

class _ResultsScreenState extends State<ResultsScreen> {


late final List<Map<String, Object>> summaryData;

@override
void initState() {
[Link]();
summaryData = _getSummaryData();
}

List<Map<String, Object>> _getSummaryData() {


// ... existing implementation
}
}

. Missing const constructors


Location: Multiple files
Issue: Widgets rebuilt unnecessarily
Fix: Add const where possible

// Add const to widgets that don't depend on runtime values


const SizedBox(height: 30),
const Text('Hello'),

. Image not cached


Location: lib/start_screen.dart line 15
Fix: [Link] already caches, but for network images use CachedNetworkImage
Optimizations to Apply
. Use const constructors:

// Current:
SizedBox(height: 30),

// Better:
const SizedBox(height: 30),

36 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

. Extract reusable widgets:


Current: Good (AnswerButton, QuestionIdentifier are already extracted)
Consider: Extracting the gradient Container decoration
. Keys for list items:

// When mapping lists, add keys for better performance


...[Link]().[Link]((entry) {
return SummaryItem(
key: ValueKey([Link]), // Add key
itemData: [Link],
);
})

. Memoization for expensive computations:

// If getSummaryData becomes expensive, cache it


late final _cachedSummary = getSummaryData();

Best Practices Checklist


✅ Separation of concerns: Data in data/, models in models/
✅ Reusable widgets: AnswerButton, QuestionIdentifier extracted
✅ Immutable data: Using final and const appropriately
⚠ Performance: Could optimize ResultsScreen computation
⚠ Type safety: Use explicit types instead of var
✅ Naming: Clear, descriptive names
⚠ Error handling: Could add more bounds checking

10. Security & Platform Notes


Security Analysis
No security concerns found in this project:
No API keys or secrets
No user authentication
No sensitive data storage
No network requests
Future Security Considerations
If you add features:
. API keys: Store in environment variables, not in code
37 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

// Use packages like flutter_dotenv


final apiKey = [Link]['API_KEY'];

. User data: Encrypt sensitive data if storing locally

// Use packages like flutter_secure_storage


final storage = FlutterSecureStorage();
await [Link](key: 'token', value: userToken);

. Input validation: Validate user inputs

if ([Link]) {
throw ArgumentError('Answer cannot be empty');
}

Platform-Specific Notes
Android: No special configurations needed
iOS: No special configurations needed
Web: Should work out of the box
Desktop: Should work, but test for appropriate sizing

11. Learning Plan & Schedule


2-Week Intensive Plan (60-90 min/day)
Week 1: Foundations
Day 1-2: Widgets & StatelessWidget
Read Lesson 1 completely
Build the minimal example
Complete all 3 practice exercises
Create your own stateless widget (e.g., profile card)
Checkpoint: Create 5 different StatelessWidgets
Day 3-4: StatefulWidget & setState
Read Lesson 2
Build counter app from example
Complete practice exercises
Build a toggle switch widget
Checkpoint: Create an interactive widget using setState()
Day 5-7: Callbacks & Data Flow
38 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Read Lesson 3
Understand parent-child communication
Complete practice exercises
Build a form where child widgets update parent
Checkpoint: Create a widget tree with 3 levels passing callbacks
Week 2: Advanced Concepts
Day 8-9: Lists, Maps, Classes
Read Lesson 4
Practice with Lists and Maps
Create your own data model class
Complete practice exercises
Checkpoint: Create a data model with methods
Day 10-11: List Operations & Widget Lists
Read Lesson 5
Practice with .map() and spread operator
Build a dynamic list of widgets
Checkpoint: Create a list that generates widgets from data
Day 12-13: Layout & Styling
Read Lessons 6 & 7
Practice with Column, Row, Expanded
Style widgets with colors and fonts
Complete practice exercises
Checkpoint: Create a styled, responsive layout
Day 14: Integration & Polish
Read remaining lessons (8-10)
Review all code improvements
Apply optimizations to the project
Write a simple test
Final Project: Build your own quiz app with different questions
4-Week Comfortable Plan (30-45 min/day)
Week 1:
Days 1-3: Widgets basics
Days 4-5: StatefulWidget basics
Days 6-7: Practice and review
Week 2:
Days 8-10: Callbacks and communication
Days 11-12: Data structures
39 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Days 13-14: Practice project


Week 3:
Days 15-17: List operations and dynamic UI
Days 18-19: Layout widgets
Days 20-21: Styling and assets
Week 4:
Days 22-24: Advanced topics (scrollable, conditional rendering)
Days 25-26: Testing and debugging
Days 27-28: Final project and optimizations
6-Week Relaxed Plan (20-30 min/day)
Stretch the 4-week plan with extra practice days and smaller milestones.
Suggested Mini-Projects
. Week 1: Counter App with increment/decrement/reset
. Week 2: Todo List (add/remove items)
. Week 3: Personal Info Card (styling practice)
. Week 4: Simple Quiz App (your own version)

12. Quick Reference & Cheat Sheet


Common Widgets
// Layout
Column(children: [...]) // Vertical arrangement
Row(children: [...]) // Horizontal arrangement
Expanded(child: widget) // Fills available space
SizedBox(width: 10, height: 10) // Spacing or sizing
Container(decoration: ...) // Styling container

// Display
Text('Hello') // Text widget
[Link]('path') // Load image
Icon([Link]) // Icon

// Input
ElevatedButton(onPressed: ...) // Primary button
OutlinedButton(onPressed: ...) // Outlined button
TextButton(onPressed: ...) // Text button

// Scrolling
SingleChildScrollView(...) // Scrollable content
ListView(...) // Scrollable list

40 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

StatefulWidget Pattern
class MyWidget extends StatefulWidget {
const MyWidget({[Link]});

@override
State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {


int counter = 0; // State variable

void increment() {
setState(() { // Must wrap in setState()
counter++;
});
}

@override
Widget build(BuildContext context) {
return Text('$counter');
}
}

Common Operations
// Lists
[Link](item) // Add item
[Link] // Get length
[Link]((item) => ...) // Transform
[Link]((item) => ...) // Filter
...list // Spread operator

// Maps
map['key'] // Get value
map['key'] = value // Set value
[Link]('key') // Check if key exists

// Classes
class MyClass {
final String name; // Immutable property
MyClass([Link]); // Constructor
}

Lifecycle Methods
@override
void initState() { // Called once when widget is created
41 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

[Link]();
}

@override
Widget build(BuildContext context) { // Called to build UI
return ...;
}

@override
void dispose() { // Called when widget is removed
// Cleanup
[Link]();
}

Flutter Commands
flutter run # Run app
flutter pub get # Install dependencies
flutter clean # Clean build files
flutter test # Run tests
flutter analyze # Check for errors
flutter doctor # Check Flutter setup

13. Glossary & External Resources


Glossary
Widget: Everything in Flutter UI is a widget
StatelessWidget: Widget that doesn't change after creation
StatefulWidget: Widget that can change and rebuild
State: Data that can change in a StatefulWidget
setState(): Method that tells Flutter to rebuild UI
BuildContext: Reference to widget's location in tree
Callback: Function passed to child widget
List: Ordered collection of items
Map: Collection of key-value pairs
Spread Operator (...): Unpacks list into another list
ARGB: Alpha, Red, Green, Blue color format
Asset: File bundled with app (images, fonts, etc.)
External Resources
. Official Flutter Docs - Widget Catalog
[Link]
Widget reference
42 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

. Official Flutter Docs - State Management


[Link]
State management overview
. Dart Language Tour
[Link]
Dart basics
. Flutter Layout Tutorial
[Link]
Layout widgets
. Google Fonts for Flutter
[Link]
Package documentation
. Flutter Widget of the Week (YouTube)
[Link]
Short widget tutorials
. Flutter Cookbook
[Link]
Common Flutter tasks
. Effective Dart Style Guide
[Link]
Coding conventions
. Flutter Testing Guide
[Link]
Testing best practices
. Flutter Performance Best Practices
[Link]
Performance optimization tips

14. Final Checklist & Next Steps


Final Checklist
Understand difference between StatelessWidget and StatefulWidget
Can use setState() to update UI
Can pass callbacks between widgets
43 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Can create custom reusable widgets


Can use Lists and Maps
Can transform lists into widgets with .map()
Can use layout widgets (Column, Row, Expanded)
Can style widgets (colors, fonts, decorations)
Can load and display images from assets
Can make content scrollable
Can conditionally render widgets
Understand state flow in the app
Next Steps to Level Up
Immediate Next Steps (Week 1-2):
. Apply code improvements from Section 5
Fix const keywords
Add type annotations
Optimize ResultsScreen
. Add features:
Timer for each question
Progress indicator showing question X of Y
Sound effects for correct/incorrect answers
Difficulty levels (Easy, Medium, Hard)
. Practice projects:
Build a calculator app
Build a weather app (mock data)
Build a notes app
Intermediate Steps (Week 3-4):
. Learn State Management:
Study Provider pattern
Refactor quiz app to use Provider
Compare with current approach
. Add animations:
Animate screen transitions
Add button press animations
Use AnimatedContainer
. Learn navigation:
Study Navigator and routes
Implement named routes
44 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Add back button handling


Advanced Steps (Month 2+):
. Backend integration:
Learn HTTP requests
Fetch questions from API
Save scores to database
. Advanced state management:
Learn Bloc pattern
Learn Riverpod
Compare different approaches
. Platform-specific features:
Learn platform channels
Access device features (camera, GPS)
Local storage with SharedPreferences
Recommended Small Projects
. Todo App (Week 2-3)
Practice: Lists, StatefulWidget, callbacks
Features: Add, remove, toggle completion
. Weather App (Week 3-4)
Practice: API calls, async/await, JSON parsing
Features: Display weather data, multiple cities
. Shopping Cart (Week 4-5)
Practice: Complex state, Provider/Bloc, calculations
Features: Add items, calculate total, checkout
. Chat App UI (Week 5-6)
Practice: ListView, custom widgets, styling
Features: Message bubbles, timestamps, user avatars
. Recipe App (Week 6-7)
Practice: Navigation, detail screens, images
Features: List of recipes, recipe details, favorites

Quiz Answers
Lesson 1 Answers
45 / 46
COMPLETE_FLUTTER_LEARNING_GUIDE.md 2025-11-20

Q1: No, a StatelessWidget cannot change after it's built


Q2: build(BuildContext context)
Lesson 2 Answers
Q1: setState() tells Flutter that data changed and UI needs to rebuild
Q2: The UI won't update - Flutter won't know the data changed
Lesson 3 Answers
Q1: Callbacks keep widgets reusable and maintainable by avoiding tight coupling
Q2: void Function(int)
Lesson 4 Answers
Q1: List is ordered collection; Map is key-value pairs
Q2: const makes the list immutable at compile-time
Lesson 5 Answers
Q1: Spread operator unpacks a list's elements into another list
Q2: When you need a List type (like for children parameter), you need .toList()
Lesson 6 Answers
Q1: mainAxisAlignment controls alignment along main axis; crossAxisAlignment controls
perpendicular axis
Q2: When you want a widget to fill remaining space in Row/Column
Lesson 7 Answers
Q1: Alpha, Red, Green, Blue - the four components of a color
Q2: Use boxShadow property in BoxDecoration
Lesson 8 Answers
Q1: In the assets section of [Link]
Q2: You'll get a runtime error when trying to load it
Lesson 9 Answers
Q1: When content might exceed screen size
Q2: SingleChildScrollView is for arbitrary content; ListView is optimized for lists
Lesson 10 Answers
Q1: if statements are more flexible for complex logic; ternary is concise for simple true/false
Q2: When you need to show different UI based on application state or user input
Would you like a 4-week daily study plan tailored to your available hours per day?
46 / 46

You might also like