Flutter Course: 11.4 TextField Widget

Flutter is an open-source UI software development kit (SDK) developed by Google, used for creating mobile, web, and desktop applications. In this course, we will look at the TextField widget, one of Flutter’s UI components. The TextField is a basic widget that allows users to input text. Let’s explore the basic usage of the TextField widget, its various features, and how to customize it in detail.

1. Basic Structure of TextField

The TextField widget is a basic input field used to receive user input. To use it, you can create a widget with the following basic structure:

TextField(
  decoration: InputDecoration(
    border: OutlineInputBorder(), // Border style for the input field
    labelText: 'Text to enter',   // Label text
    hintText: 'Enter here',   // Hint text
  ),
  onChanged: (text) {
    // Callback that is called when the text changes
    print('Entered text: $text');
  },
)

Here, the decoration property defines the appearance of the input field. The labelText defines the label for the input field, and the hintText serves as a placeholder in the input field. The onChanged property is a callback function that is called every time the user enters text.

2. Key Properties of the TextField Widget

The TextField widget has several important properties that allow for finer control over the widget’s behavior and appearance. The following are the most commonly used properties:

  • controller: Uses an instance of TextEditingController to keep track of the current state of the input field.
  • obscureText: Set to true to hide text for secure input like passwords.
  • keyboardType: Set the type of keyboard that pops up for an improved user experience.
  • maxLines: Set the maximum number of lines inputted.
  • onSubmitted: A callback that is called when the user completes and submits their input.

Here is how to use these properties:

TextField(
  controller: myController,
  obscureText: true,
  keyboardType: TextInputType.emailAddress, 
  maxLines: 1, 
  onSubmitted: (value) {
    print('User entered value: $value');
  },
)

3. Using TextEditingController

You can use the TextEditingController to manage data and state related to the input field. This allows you to get or set the value in the input field. Here is an example of using the TextEditingController:

class MyTextFieldWidget extends StatefulWidget {
  @override
  _MyTextFieldWidgetState createState() => _MyTextFieldWidgetState();
}

class _MyTextFieldWidgetState extends State {
  TextEditingController myController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          controller: myController,
          decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Enter your email',
          ),
        ),
        ElevatedButton(
          onPressed: () {
            print('Entered email: ${myController.text}');
          },
          child: Text('Submit'),
        ),
      ],
    );
  }

  @override
  void dispose() {
    // Release the controller on widget removal to prevent memory leaks.
    myController.dispose();
    super.dispose();
  }
}

4. Different Types of TextField

Now let’s learn about the various types of TextField. In addition to the basic input field, there are multiple types of input fields you can customize.

4.1. Password Input Field

To create a password input field, set the obscureText property to true. Here is an example of a password input field:

TextField(
  obscureText: true,
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    labelText: 'Enter your password',
  ),
)

4.2. Email Address Input Field

When accepting email input, set the keyboardType to TextInputType.emailAddress to display a dedicated keyboard for emails:

TextField(
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    labelText: 'Enter your email',
  ),
)

4.3. Multi-line Input Field

To support the input of multiple lines of text, set the maxLines property:

TextField(
  maxLines: 5,
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    labelText: 'Enter content here',
  ),
)

5. Styling the TextField

You can style the input field to make it more beautiful and intuitive using various properties. Let’s use the properties of InputDecoration?

  • fillColor: Sets the background color of the input field.
  • focusedBorder: Sets the border style when the input field is focused.
  • enabledBorder: Sets the border style when the input field is active.
  • errorText: Sets the text to display in case of input errors.

An example is as follows:

TextField(
  decoration: InputDecoration(
    fillColor: Colors.lightBlueAccent,
    filled: true,
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Colors.green, width: 2.0),
    ),
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Colors.blue, width: 2.0),
    ),
    errorText: 'Invalid input',
  ),
)

6. Validation and Verification of TextField

You can add a simple validation logic to check the validity of the text entered by the user. For example, you can perform basic validation for email format:

String? validateEmail(String? value) {
  if (value == null || value.isEmpty) {
    return 'Please enter an email';
  }
  String pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
  RegExp regex = RegExp(pattern);
  if (!regex.hasMatch(value)) {
    return 'Invalid email format';
  }
  return null;
}

TextField(
  decoration: InputDecoration(
    errorText: validateEmail(myController.text),
  ),
)

7. TextField and TextFormField

To handle input field validation and state management more efficiently, you can use the TextFormField widget. The TextFormField is used with the Form widget, providing better validation and state management:

Form(
  child: Column(
    children: [
      TextFormField(
        decoration: InputDecoration(labelText: 'Enter your email'),
        validator: validateEmail,
      ),
      ElevatedButton(
        onPressed: () {
          // submit logic
        },
        child: Text('Submit'),
      ),
    ],
  ),
)

8. TextField and FocusNode

You can use a FocusNode to control focus on the input field. Controlling focus allows you to perform specific actions or manage input:

FocusNode myFocusNode = FocusNode();

@override
void initState() {
  super.initState();
  myFocusNode.addListener(() {
    print('Focus state changed: ${myFocusNode.hasFocus}');
  });
}

@override
Widget build(BuildContext context) {
  return TextField(
    focusNode: myFocusNode,
    decoration: InputDecoration(labelText: 'Test focus here'),
  );
}

9. Conclusion

In this tutorial, we took an in-depth look at the TextField widget in Flutter. The TextField is a very basic UI component that is essential in any app that requires user input. By utilizing various properties and features, we can provide a more intuitive and useful user experience.

While developing mobile and web applications using Flutter, you can enhance the user interface by leveraging the various uses of TextField. I hope this tutorial has been helpful for your Flutter development!

Flutter Course: 11.3 Applying flutter_animate

Flutter is a powerful framework for developing various multimedia applications. User interface (UI) animations play a crucial role in enhancing user experience and improving the overall quality of the app. In this tutorial, we will explore how to apply animations to Flutter applications using the flutter_animate package.

1. What is flutter_animate?

flutter_animate is a package that helps implement animations easily in Flutter. With this package, you can easily apply various animation effects and it provides features that reduce the complexity of animations, allowing developers to work more efficiently.

2. Installing the flutter_animate package

First, you need to include the flutter_animate package in your project. To do this, you should add the package in the pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  flutter_animate: ^2.0.0  # Enter the required version here.

After that, use the command below to install the package.

flutter pub get

3. Basic usage

After installing the package, let’s look at how to use flutter_animate through a simple example.

3.1 Basic animation effects

The following example code shows a simple Fade-In animation.

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Animate Example'),
      ),
      body: Center(
        child: Container(
          child: Text('This text uses a fade-in animation.')
              .animate()
              .fadeIn(duration: 1.seconds),
        ),
      ),
    );
  }
}

The above code shows the effect of text gradually appearing over 1 second. After calling the .animate() method, you can chain and apply the desired animation.

3.2 Applying various animations

The flutter_animate package supports various animations. Here are some animation techniques:

  • .fadeIn() – The element appears gradually.
  • .fadeOut() – The element disappears gradually.
  • .scale() – Changes the size of the element.
  • .slide() – Moves the element from one side of the screen to the other.
  • .rotate() – Rotates the element.

Here’s an example of using multiple animations together.

class AnimatedMultiEffect extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Multiple Animation Effects'),
      ),
      body: Center(
        child: Container(
          child: Text('Multiple animation effects are applied!')
              .animate()
              .fadeIn(duration: 1.seconds)
              .scale(begin: 0.5, end: 1.0)
              .slideX(begin: -1.0, end: 0.0)
              .rotate(begin: 0.0, end: 1.0)
              .start(delay: 300.milliseconds),
        ),
      ),
    );
  }
}

4. Customizing animations

You can adjust the properties of animations using flutter_animate. For example, you can specify the duration, starting point, and end point of the animation for finer adjustments. Below is how to customize an animation.

class CustomAnimationExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Animation Example'),
      ),
      body: Center(
        child: Container(
          child: Text('You can change the properties of the animation!')
              .animate()
              .fadeIn(duration: 2.seconds, curve: Curves.easeIn)
              .scale(begin: 0.0, end: 1.5, duration: 2.seconds)
              .start(),
        ),
      ),
    );
  }
}

In the above example, we added a Curves.easeIn curve to the fadeIn animation to make it appear smoothly. We also set the duration of the scale animation to control the flow of the animation.

5. Real-life examples of using animations

5.1 Adding animation to a button

To provide feedback on user interactions, you can apply animations to buttons, creating a more engaging UI. Below is an example of adding animation effects when clicking a button.

class AnimatedButton extends StatefulWidget {
  @override
  _AnimatedButtonState createState() => _AnimatedButtonState();
}

class _AnimatedButtonState extends State {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animated Button Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // Animation trigger
            setState(() {});
          },
          child: Text('Animation Button')
              .animate()
              .scale(begin: 1.0, end: 1.5)
              .fadeIn(duration: 0.5.seconds)
              .slideY(begin: -1.0, end: 0.0)
              .start(),
        ),
      ),
    );
  }
}

5.2 Applying animation to list items

Applying animations to list items can provide users with a more dynamic UI. For example, you can add a fade-in effect every time a new item is added to the list.

class AnimatedListExample extends StatelessWidget {
  final List items = ["Item 1", "Item 2", "Item 3"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animated List Example'),
      ),
      body: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return Container(
            padding: EdgeInsets.all(8.0),
            child: Text(items[index])
                .animate()
                .fadeIn(duration: 0.5.seconds)
                .start(),
          );
        },
      ),
    );
  }
}

6. Optimization and performance

Animations can make the UI more attractive, but applying too many animations can lead to performance degradation. Therefore, it is important to follow the optimization guidelines below.

  • Minimize the number of animations to help users focus.
  • Remove unnecessary animations to improve performance.
  • Analyze animation performance in debug mode to identify problem areas.
  • Adjust the size and duration of animations to maintain optimal performance.

7. Conclusion

In this tutorial, we explored how to apply animations to Flutter applications using the flutter_animate package. Animations can enhance user experience and create a more attractive UI. Be sure to actively utilize animations in your future projects!

If you want more detailed information, please visit here. If you have any questions or needs, feel free to leave a comment. Thank you!

Flutter Course: 11.2 Layout Composition

Flutter is a powerful framework that allows you to easily create attractive User Interfaces (UI). In this lesson 11.2, we will delve deeply into the layout composition in Flutter. Layout composition is a crucial process for effectively placing complex UI elements. In this process, we will utilize various widgets and the layout system provided by Flutter.

1. Fundamental Concepts of Layout

Layout refers to the topic of how UI elements are arranged on the screen. Flutter uses widgets to compose layouts. Everything in Flutter is made up of widgets, and these widgets combine to form complex UIs. The layout system primarily uses containers, so the properties of the container determine the position of the UI.

1.1. Concept of Widgets

In Flutter, widgets are the components of the UI, and each widget has its own properties and layout. Flutter’s widgets are broadly categorized into StatelessWidget and StatefulWidget. StatelessWidget does not have a state and is used to create unchanging UIs. Conversely, StatefulWidget has a state and changes the UI according to state changes.

1.2. Parent-Child Relationship

Widgets have a parent-child relationship. A parent widget can include child widgets, enabling layout composition. For example, the Column widget can arrange multiple child widgets vertically.

2. Layout Widgets in Flutter

Flutter provides various layout widgets. In this section, we will look at the key layout widgets that are commonly used.

2.1. Container

The Container widget is the most basic widget and allows you to encapsulate other widgets to adjust size, padding, margins, etc. You can apply additional styles such as background color and borders using the Container.

Container(
  width: 200,
  height: 100,
  color: Colors.blue,
  padding: EdgeInsets.all(10),
  child: Text('Hello, Flutter!'),
)

2.2. Row

The Row widget arranges child widgets horizontally. You can define alignment methods using the mainAxisAlignment and crossAxisAlignment properties.

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Icon(Icons.star),
    Icon(Icons.star),
    Icon(Icons.star),
  ],
)

2.3. Column

The Column widget lists child widgets vertically. Similarly, you can adjust arrangements through mainAxisAlignment and crossAxisAlignment.

Column(
  mainAxisAlignment: MainAxisAlignment.start,
  children: [
    Text('Item 1'),
    Text('Item 2'),
    Text('Item 3'),
  ],
)

2.4. Stack

The Stack widget stacks multiple widgets on top of each other. You can adjust the position of each child widget using the Positioned widget.

Stack(
  children: [
    Container(color: Colors.red, width: 100, height: 100),
    Positioned(
      left: 20,
      top: 20,
      child: Container(color: Colors.blue, width: 50, height: 50),
    ),
  ],
)

2.5. ListView

The ListView widget creates a scrollable list. It is very useful for easily listing multiple items.

ListView(
  children: [
    ListTile(title: Text('Item 1')),
    ListTile(title: Text('Item 2')),
    ListTile(title: Text('Item 3')),
  ],
)

3. Layout Properties

We will learn about the main properties that can be used when configuring layout widgets.

3.1. Padding

You can use the Padding widget to add padding to a widget, setting space around child widgets.

Padding(
  padding: EdgeInsets.all(16.0),
  child: Text('Hello, Flutter!'),
)

3.2. Margin

Margins can be set as properties of the Container widget. This property expands the space around the child widget.

Container(
  margin: EdgeInsets.all(20),
  child: Text('Hello with Margin!'),
)

4. Composing Complex Layouts

Now, let’s create more complex layouts from simple widget compositions. We will combine multiple widgets to form a more realistic UI.

4.1. Creating a Card Layout

Let’s create a simple layout displaying information using a card. We will combine various widgets to create a UI that includes all elements.

Card(
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Padding(
        padding: const EdgeInsets.all(16.0),
        child: Text('Title', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
      ),
      Padding(
        padding: const EdgeInsets.all(16.0),
        child: Text('This is a sample card in Flutter.', style: TextStyle(fontSize: 16)),
      ),
      ButtonBar(
        children: [
          TextButton(child: Text('EDIT'), onPressed: () {/*Edit logic*/}),
          TextButton(child: Text('DELETE'), onPressed: () {/*Delete logic*/}),
        ],
      ),
    ],
  ),
)

5. Composing Responsive Layouts

It is also essential to create responsive layouts to allow users to use the application on various screen sizes.

5.1. Using MediaQuery

In Flutter, you can use MediaQuery to dynamically detect the size of the screen. This allows you to apply designs suitable for various screen sizes.

final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;

5.2. LayoutBuilder

The LayoutBuilder widget receives specific constraints for the child widget. Through this, you can configure it to act differently based on the widget’s size.

LayoutBuilder(
  builder: (BuildContext context, BoxConstraints constraints) {
    return Container(
      width: constraints.maxWidth < 600 ? 100 : 200,
      height: 100,
      child: Text('Responsive Container'),
    );
  },
)

6. Conclusion

In this lesson, we learned about layout composition in Flutter. We saw how to create complex UIs using various widgets and how responsive design can enhance user experience. By understanding and utilizing the layout system, we can develop better applications.

Flutter Course, 10.2 Route and Screen Navigation

In this course, we will delve deeply into how to handle navigation between screens in Flutter and the concept of routes. Screen transitions are one of the essential features of mobile applications, providing users with a smooth experience. Therefore, it is crucial to understand how to use routes and navigation well.

1. What is a Route?

A route refers to the concept that signifies each screen of a mobile app. Flutter provides two types of routes: basic routes and named routes. Basic routes point to specific widgets, while named routes identify specific routes using strings.

2. Flutter’s Navigation Structure

Flutter’s navigation structure primarily uses a stack structure. Each time a user navigates to a new screen, the previous screen is added to the stack, and the new screen occupies the top position. When the user presses the back button, the top screen is removed, and the user returns to the previous screen.

2.1 Navigator Widget

The Navigator is a widget that manages routes, allowing multiple routes to be stacked and managed. This enables the implementation of various screen transition animations and effects.

3. Transitioning Screens Using Routes

There are two main ways to transition between screens using routes. The first is by using Navigator.push(), and the second is by using Navigator.pushNamed().

3.1 Navigator.push()

The Navigator.push() method adds a new screen to the current screen. Here’s how to use this method to transition to a new screen.

Navigator.push(context, MaterialPageRoute(builder: (context) => NewScreen()));

3.2 Navigator.pushNamed()

Using named routes has the advantage of making the code more concise. To use named routes, you must first define the routes in the routes property of MaterialApp.


MaterialApp(
    routes: {
        '/': (context) => HomeScreen(),
        '/new': (context) => NewScreen(),
    },
);

After this, transitioning between screens can be done as follows.

Navigator.pushNamed(context, '/new');

4. Screen Transition Animations

Flutter allows you to apply various animations during screen transitions. You can customize it using PageRouteBuilder. By using this method, you can finely tune the start and end of the transition animation and the widget during the transition.


Navigator.push(context, PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => NewScreen(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
        const begin = Offset(1.0, 0.0);
        const end = Offset.zero;
        const curve = Curves.easeInOut;

        var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
        var offsetAnimation = animation.drive(tween);

        return SlideTransition(
            position: offsetAnimation,
            child: child,
        );
    },
));

5. Passing Data Between Screens Using Routes

It is possible to pass data between screens through routes. To pass data to a new screen, you should provide the data as a parameter to the widget’s constructor when creating it.


class NewScreen extends StatelessWidget {
    final String data;

    NewScreen(this.data);

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: Text("New Screen")),
            body: Center(child: Text(data)),
        );
    }
}

Data can be passed as follows:

Navigator.push(context, MaterialPageRoute(builder: (context) => NewScreen("Hello, Flutter!")));

6. Returning Results Through Routes

After transitioning screens, you can return results to the previous screen. This allows you to take user input and act according to the result. The Navigator.pop() method can be used for this purpose.

Navigator.pop(context, "Returned Data");

7. Conclusion

In this course, we covered routes and screen navigation in Flutter. Using routes is essential for effectively managing transitions between screens and improving user experience. You can navigate screens in various ways and exchange data, so actively implement this in your actual app development.

I hope this article helps you in your Flutter learning, and in the next course, we will discuss state management in Flutter. Thank you!

Flutter Course: 11.1 Creating and Configuring Projects

Hello! In this tutorial, we will explore in detail how to create and structure a project using Flutter. Flutter is a powerful framework developed by Google that allows you to build mobile, web, and desktop applications using a single codebase. We will now look at the process of creating and configuring a Flutter project step by step.

1. Installing Flutter

To use Flutter, you must first install the Flutter SDK. Follow the steps below to proceed with the installation:

  • Download the Flutter SDK: Visit the official Flutter website to download the SDK suitable for your operating system.
  • Set environment variables: Add the path of the downloaded Flutter SDK to your system’s environment variables.
  • Install dependencies: Use the Flutter Doctor command to install necessary dependencies. Enter the following command in the command line:
flutter doctor

This command checks for any issues with your Flutter installation. If any required packages are missing, you will be prompted to install them.

2. Creating a New Flutter Project

Once the Flutter SDK installation is complete, let’s create a new project. To create a new Flutter application, enter the following command:

flutter create project_name

Here, project_name is the name of the project, which you can change to your preferred name. Once the project is created, the following directory structure will be generated:

project_name/
  ├── android/
  ├── ios/
  ├── lib/
  ├── test/
  ├── web/
  ├── pubspec.yaml

The roles of each directory are as follows:

  • android/: Contains configuration files and code for the Android platform.
  • ios/: Contains configuration files and code for the iOS platform.
  • lib/: The directory where the main code of the Flutter application (Dart files) is located.
  • test/: Contains unit tests and integration test code.
  • web/: Contains files for the web platform.
  • pubspec.yaml: A file that defines the project’s metadata, dependencies, and more.

3. Understanding the pubspec.yaml File

Let’s take a closer look at the key file of the Flutter project, pubspec.yaml. This file contains information about the project and defines dependency management and various settings.

name: project_name
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:

  uses-material-design: true

Key Component Descriptions:

  • name: The name of the project.
  • description: Description of the project.
  • publish_to: A setting indicating that this project will not be published to pub.dev.
  • version: The version of the project.
  • environment: The version range of the Dart SDK being used.
  • dependencies: The main packages utilized in the project.
  • dev_dependencies: Packages needed only during development.
  • flutter: Settings related to Flutter. For instance, if uses-material-design is true, it allows the use of Material Design icons.

4. Structuring the Project

Now let’s talk about how to structure the project. Generally, a Flutter application is organized in the following way:

  • lib/: Contains the main application code.
  • screens/: Contains files that define the application’s screens.
  • widgets/: Contains reusable widgets.
  • models/: Contains data model classes.
  • services/: Contains service classes such as networking.

Maintaining this structure ensures that the code is organized and easy to manage. For example, consider a project with the following file structure:

lib/
  ├── main.dart
  ├── screens/
  │   ├── home_screen.dart
  │   └── settings_screen.dart
  ├── widgets/
  │   ├── custom_button.dart
  │   └── header.dart
  ├── models/
  │   ├── user.dart
  │   └── product.dart
  └── services/
      ├── api_service.dart
      └── auth_service.dart

5. Creating a Basic Hello World Application

Now let’s create a basic Hello World application. Open the lib/main.dart file and write the following:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello World',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello World App'),
        ),
        body: Center(
          child: Text('Hello, Flutter!'),
        ),
      ),
    );
  }
}

This code creates a simple application based on Flutter. The runApp function launches the MyApp widget to start the application. The Scaffold provides the basic UI framework. The AppBar and Center widgets are used to position the text in the center.

6. Running the Application

Now that the project is ready, let’s run it. Enter the following command in the command line:

flutter run

Executing the above command will launch the application on the connected device or emulator. When the app is run, the phrase “Hello, Flutter!” will be displayed in the center.

7. Debugging and Building

Identifying and fixing errors or bugs during application development is an important process. Flutter provides powerful debugging tools.

  • Hot Reload: A feature that allows you to apply changes immediately without refreshing the app after code changes.
  • Debug Mode: Use the debugging tools provided by Flutter to easily check variable values, stack traces, breakpoints, and more.

You can build the project using the following command:

flutter build apk

This command generates an APK file that can be run on Android. For iOS, use the appropriate command to perform the build in Xcode.

8. Conclusion

In this tutorial, we learned how to create and structure a Flutter project. Flutter is a powerful tool for quickly prototyping applications. By understanding and adjusting the project structure, you can efficiently proceed with application development. In the next tutorial, we will explore how to create richer UIs using various Flutter widgets.

References