User Interface Design using Flutter

Exercise - 1: Flutter and Dart SDK
1b. Write a simple Dart program to understand the basic language.
// Source: kottesandeep.blogspot.com
// hello.dart
void main() {
  print('Hello, Dart!');

  // Variables
  String name = 'Alice';
  int age = 25;
  double height = 5.6;
  bool isStudent = true;

  // Lists
  List hobbies = ['reading', 'coding', 'hiking'];

   // Function call
  greetUser(name);

  // Control flow
  if (age >= 18) {
    print('$name is an adult.');
  } else {
    print('$name is a minor.');
  }

  // Loop
  print('Hobbies:');
  for (var hobby in hobbies) {
    print('- $hobby');
  }
}

// Function definition
void greetUser(String username) {
  print('Welcome, $username!');
}



Exercise - 2:
2. a) Explore various Flutter widgets (Text, Image, Container, etc.).
Text('Hello, World!',style: TextStyle(fontSize: 24, color: Colors.red),),
            
Image.file(File('asset/images/Screenshot.png'), width: 200, height: 200,),
Container(
   padding: EdgeInsets.all(16),
   color: Colors.green,
   child: Text('Inside a container'),
 )

2. b) Implement different layout structures using Row, Column, and Stack Widget.
mainAxisAlignment: MainAxisAlignment.center,
          children: < Widget >[
            Text('Username'),
            SizedBox(height: 20),
            Text('Password'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {},
              child: Text('Click Me'),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Icon(Icons.home, size: 40),
                Icon(Icons.search, size: 40),
                Icon(Icons.settings, size: 40),
              ],
            ),

            Stack(
              alignment: Alignment.center,
              children: [
                Container(
                  width: 200,
                  height: 200,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                ),
                Text(
                  'Center',
                  style: TextStyle(color: Colors.white, fontSize: 20),
                ),
              ],
            )


Exercise - 3:
3 a) Design a responsive UI that adapts to different screen sizes.
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Responsive UI Demo',
      home: ResponsiveUI(),  // <- This is your Scaffold-based widget
    );
  }
}

class ResponsiveUI extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(title: Text("Responsive UI")),
      body: LayoutBuilder(
        builder: (context, constraints) {
          if (constraints.maxWidth > 600) {
            // Tablet/Desktop Layout
            return Row(
              children: [
                Expanded(child: Container(color: Colors.blue, child: Center(child: Text("Sidebar")))),
                Expanded(flex: 2, child: Container(color: Colors.white, child: Center(child: Text("Main Content")))),
              ],
            );
          } else {
            // Mobile Layout
            return Column(
              children: [
                Container(height: 100, color: Colors.blue, child: Center(child: Text("Top Bar"))),
                Expanded(child: Container(color: Colors.white, child: Center(child: Text("Main Content")))),
              ],
            );
          }
        },
      ),
    );
  }
}


3 b) Implement media queries and breakpoints for responsiveness.
import 'package:flutter/material.dart';

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

// Root widget
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Media Query Breakpoints Demo',
      home: ResponsiveLayout(),
    );
  }
}

// Main responsive widget using breakpoints
class ResponsiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;

    if (screenWidth < 600) {
      // Small screen: Mobile
      return Scaffold(
        appBar: AppBar(title: Text("Mobile Layout")),
        body: Center(child: Text("This is a Mobile Layout", style: TextStyle(fontSize: 16))),
      );
    } else if (screenWidth >= 600 && screenWidth < 1200) {
      // Medium screen: Tablet
      return Scaffold(
        appBar: AppBar(title: Text("Tablet Layout")),
        body: Center(child: Text("This is a Tablet Layout", style: TextStyle(fontSize: 20))),
      );
    } else {
      // Large screen: Desktop
      return Scaffold(
        appBar: AppBar(title: Text("Desktop Layout")),
        body: Center(child: Text("This is a Desktop Layout", style: TextStyle(fontSize: 24))),
      );
    }
  }
}



Exercise - 4:
4 a) Set up navigation between different screens using Navigator.
import 'package:flutter/material.dart';

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

// Root widget
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Navigator Demo',
      home: FirstScreen(),
    );
  }
}

// First Screen
class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("First Screen")),
      body: Center(
        child: ElevatedButton(
          child: Text("Go to Second Screen"),
          onPressed: () {
            // Navigation using direct push
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondScreen()),
            );
          },
        ),
      ),
    );
  }
}

// Second Screen
class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Second Screen")),
      body: Center(
        child: ElevatedButton(
          child: Text("Back to First Screen"),
          onPressed: () {
            Navigator.pop(context); // Go back
          },
        ),
      ),
    );
  }
}

4 b) Implement navigation with named routes.
 import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Named Routes Demo',
      initialRoute: '/',
      routes: {
        '/': (context) => HomeScreen(),
        '/second': (context) => SecondScreen(),
      },
    );
  }
}

// Home Screen
class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home Screen")),
      body: Center(
        child: ElevatedButton(
          child: Text("Go to Second Screen"),
          onPressed: () {
            Navigator.pushNamed(context, '/second'); // Using named route
          },
        ),
      ),
    );
  }
}

// Second Screen
class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Second Screen")),
      body: Center(
        child: ElevatedButton(
          child: Text("Back to Home"),
          onPressed: () {
            Navigator.pop(context); // Go back
          },
        ),
      ),
    );
  }
}
 


Exercise - 5:
5 a) Learn about stateful and stateless widgets.
 1. Stateless Widget
	A StatelessWidget is immutable: once it is built, it cannot change its state during runtime.
	Used when the UI does not depend on dynamic data (e.g., labels, static layouts). 
 2. Stateful Widget
	A StatefulWidget can change during runtime using setState(). 

StatelessWidget → UI never changes.

StatefulWidget → UI can change with setState().

5 b) Implement state management using set State and Provider.
//Add provider to pubspec.yaml:
//dependencies:
//  flutter:
//    sdk: flutter
//  provider: ^6.0.5


import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// State Class
class CounterModel with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // notifies all listening widgets
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterModel(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: CounterScreen());
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var counter = Provider.of<CounterModel>(context);

    return Scaffold(
      appBar: AppBar(title: Text("Provider Example")),
      body: Center(
        child: Text("Count: ${counter.count}", style: TextStyle(fontSize: 24)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}


Exercise - 6:
6 a) Create custom widgets for specific UI elements.
 
  import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Simple Avatar UI")),
        body: Center(
          child: CustomAvatar(
            imageUrl: "imageUrl",
            name: "Sandeep",
          ),
        ),
      ),
    );
  }
}

//  Custom Widget (Avatar)
class CustomAvatar extends StatelessWidget {
  final String imageUrl;
  final String name;

  CustomAvatar({required this.imageUrl, required this.name});

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        CircleAvatar(
          radius: 50,
          backgroundImage: NetworkImage(imageUrl),
        ),
        SizedBox(height: 10),
        Text(
          name,
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
      ],
    );
  }
}
   

6 b) Apply styling using themes and custom styles.
 
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Theming Example",

      // Global Theme
      theme: ThemeData(
        primarySwatch: Colors.teal,
        textTheme: TextTheme(
          bodyMedium: TextStyle(fontSize: 16, color: Colors.black87),
          titleLarge: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
      ),

      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Themes & Styles"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // Uses global theme (titleLarge)
            Text(
              "Welcome to Flutter!",
              style: Theme.of(context).textTheme.titleLarge,
            ),
            SizedBox(height: 20),

            // Custom Style applied locally
            Text(
              "This text has custom style",
              style: TextStyle(
                fontSize: 18,
                color: Colors.purple,
                fontWeight: FontWeight.w600,
                letterSpacing: 1.2,
              ),
            ),
            SizedBox(height: 20),

            // Widget with custom background styling
            Container(
              padding: EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.teal.shade100,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Text(
                "Styled Container",
                style: TextStyle(fontSize: 16, color: Colors.teal.shade900),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
     


Exercise - 7:
7 a) and b) Design a form with various input fields. Implement form validation and error handling
 
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Form Validation Example",
      home: FormScreen(),
    );
  }
}

class FormScreen extends StatelessWidget {
  final _formKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Form with Validation")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              // Name Field
              TextFormField(
                decoration: InputDecoration(labelText: "Name"),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return "Name is required";
                  }
                  return null;
                },
              ),

              // Email Field
              TextFormField(
                decoration: InputDecoration(labelText: "Email"),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return "Email is required";
                  }
                  if (!value.contains("@")) {
                    return "Enter a valid email";
                  }
                  return null;
                },
              ),

              // Password Field
              TextFormField(
                decoration: InputDecoration(labelText: "Password"),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.length < 6) {
                    return "Password must be at least 6 characters";
                  }
                  return null;
                },
              ),

              // Age Field
              TextFormField(
                decoration: InputDecoration(labelText: "Age"),
                keyboardType: TextInputType.number,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return "Age is required";
                  }
                  if (int.tryParse(value) == null) {
                    return "Enter a valid number";
                  }
                  return null;
                },
              ),

              SizedBox(height: 20),

              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text("Form Submitted Successfully!")),
                    );
                  }
                },
                child: Text("Submit"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}



Exercise - 8:
a) Add animations to UI elements using Flutter's animation framework.
       
     import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AnimationExample(),
    );
  }
}

class AnimationExample extends StatefulWidget {
  @override
  _AnimationExampleState createState() => _AnimationExampleState();
}

class _AnimationExampleState extends State
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation _animation;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      duration: Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true); // Repeat animation back and forth

    _animation = Tween(begin: 100, end: 200).animate(_controller);
  }

  @override
  void dispose() {
    _controller.dispose(); // free memory
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Basic Animation Example")),
      body: Center(
        child: AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            return Container(
              width: _animation.value,
              height: _animation.value,
              color: Colors.blue,
            );
          },
        ),
      ),
    );
  }
}

  • b) Experiment with different types of animations (fade, slide, etc.)
  •   
         import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: AnimationTypesDemo(),
        );
      }
    }
    
    class AnimationTypesDemo extends StatefulWidget {
      @override
      _AnimationTypesDemoState createState() => _AnimationTypesDemoState();
    }
    
    class _AnimationTypesDemoState extends State {
      bool _visible = true;
      bool _moved = false;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("Fade & Slide Animations")),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // Fade Animation
                AnimatedOpacity(
                  opacity: _visible ? 1.0 : 0.0,
                  duration: Duration(seconds: 2),
                  child: Container(width: 100, height: 100, color: Colors.green),
                ),
    
                SizedBox(height: 40),
    
                // Slide Animation
                AnimatedSlide(
                  offset: _moved ? Offset(1, 0) : Offset(0, 0),
                  duration: Duration(seconds: 1),
                  child: Container(width: 100, height: 100, color: Colors.orange),
                ),
    
                SizedBox(height: 40),
    
                ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _visible = !_visible;
                      _moved = !_moved;
                    });
                  },
                  child: Text("Animate!"),
                ),
              ],
            ),
          ),
        );
      }
    }