Flutter Lesson 8 : From Static UI to User Interaction

Flutter Lesson 8 : From Static UI to User Interaction

FlutterPulse

This article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Input Widgets & Buttons Explained with One Practical App

Until now, our Flutter apps were great at showing information — text, images, layouts. But real apps don't just display things. They listen to users and respond to actions.

In this lesson, we'll move from static screens to interactive Flutter apps. We'll let users type input, tap buttons, and instantly see results on the screen. No theory overload, just one clean, practical example with fully runnable Flutter code.

Input Widgets in Flutter: What They Are & Why They Matter

So far, everything we built in Flutter was one-way communication, the app showed something, and the user just looked at it. Input widgets change that. They allow two-way communication between the user and the app.

What are Input Widgets?

Input widgets are widgets that let users enter data or make a choice inside your app.

Common examples you'll see in real apps:

  • Typing a name or email
  • Entering a password
  • Searching for content
  • Writing a message or feedback

In Flutter, these inputs are also widgets, just like Text, Image, or Container.

Common Input Widgets in Flutter

For this lesson, we'll focus on the most important one:

  • TextField → lets the user type text

(We'll cover advanced ones like TextFormField, validation, checkboxes, and switches in later lessons.)

Why Input Widgets Are So Important

Think of input widgets as the ears of your app:

  • Without them, your app can't hear the user
  • With them, your app becomes interactive and useful

Examples where input widgets are essential:

  • Login & signup screens
  • Search bars
  • Chat applications
  • Forms and surveys

In the next section, we'll take our first input widget — TextField and see how Flutter actually reads what the user types, using a very simple and practical example.

TextField in Flutter: Letting Users Type

The most commonly used input widget in Flutter is TextField.
It's the widget that shows a text box and allows users to type something inside your app.

But here's an important question:

If a user types text, where does that text go?
How does Flutter remember it?

This is where TextEditingController comes in.

What is a TextField?

  • TextField displays an input box on the screen
  • Users can type letters, numbers, or symbols
  • By itself, TextField only shows UI, it does not store data in a variable automatically

So we need a way to control and read what the user types.

TextEditingController: The Brain Behind TextField

Think of TextEditingController as a notebook:

  • Whatever the user types is written in that notebook
  • We can read from it anytime
  • We can also clear or change the text programmatically

Key points:

  • One controller is usually linked to one TextField
  • The controller lives inside a StatefulWidget
  • We access user input using controller.text

Basic TextField Example

TextEditingController nameController = TextEditingController();

TextField(
controller: nameController,
decoration: InputDecoration(
labelText: "Enter your name",
),
)
  • controller connects the TextField to our code
  • labelText tells the user what to type
  • The typed value is available using nameController.text

Right now, the user can type but nothing happens yet. In the next section, we'll add buttons and see how a button press can read this input and trigger an action.

Buttons in Flutter: Triggering Actions

Now that the user can type something, we need a way for them to tell the app what to do next.
This is where buttons come in.

Buttons are how users trigger actions in an app:

  • Submit a form
  • Search for something
  • Save data
  • Confirm an action

Common Buttons in Flutter

Flutter provides multiple button widgets, but the most commonly used ones are:

  • ElevatedButton → main action button (we'll use this)
  • TextButton → low-priority actions
  • OutlinedButton → secondary actions

For this lesson, we'll focus on ElevatedButton, since it's what you'll use most often in real apps.

How a Button Works

A button has one important property:

  • onPressed

This is a function that runs when the user taps the button.

Example:

ElevatedButton(
onPressed: () {
print("Button pressed");
},
child: Text("Click Me"),
)
  • If onPressed is null, the button is disabled
  • If onPressed has a function, the button becomes clickable

Connecting Button with User Input

Now let's connect the button with the TextField we created earlier.

Basic idea:

  1. User types text into TextField
  2. Text is stored in TextEditingController
  3. User presses button
  4. Button reads controller.text
  5. App performs some action

But there's still one missing piece…

Even if we read the text, how do we update the UI to show something new?

That's exactly what we'll learn next using setState().

Connecting Input & Button Using setState()

At this point, our app can:

  • take input from the user (TextField)
  • detect a button tap (ElevatedButton)

But there's still a problem.

The app knows something changed, but the screen doesn't update automatically.

This is where setState() comes in.

What is setState()? (Simple Explanation)

Think of setState() as telling Flutter:

"Hey Flutter, some data has changed.
Please redraw the screen using the new values.

Without setState():

  • values may change in code
  • UI stays the same

With setState():

  • Flutter rebuilds the widget
  • updated data appears on screen instantly

How setState() Fits into Our Example

Here's the flow we want:

  1. User types their name
  2. User presses the button
  3. App reads the input
  4. App updates a message
  5. UI refreshes and shows the message

We'll store the message in a variable and update it using setState().

Small Logic Example

String greetingMessage = "";

void generateGreeting() {
setState(() {
greetingMessage = "Hello!";
});
}
  • greetingMessage holds what we want to display
  • setState() updates the value
  • Flutter rebuilds the screen automatically

Why setState() Is So Important

  • It's the simplest way to manage UI updates
  • Perfect for small apps and learning
  • Helps you understand how Flutter reacts to data changes

Now that we understand TextField, Button, and setState(), we're ready to combine everything into one complete, runnable Flutter app.

Full Practical Example: A Simple Greeting App

Now let's put everything together and build one small Flutter app that:

  • takes input from the user
  • reacts to a button press
  • updates the UI instantly

This single example will cover input widgets, buttons, and state updates — exactly how you'll use them in real apps.

What This App Does

  • User types their name
  • User taps a button
  • App displays a greeting message
  • If input is empty, it shows a helpful message instead

Complete Runnable Flutter Code

You can copy-paste this code and run it directly.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: GreetingApp(),
);
}
}

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

@override
State<GreetingApp> createState() => _GreetingAppState();
}

class _GreetingAppState extends State<GreetingApp> {
final TextEditingController nameController = TextEditingController();
String greetingMessage = "";

void generateGreeting() {
setState(() {
if (nameController.text.isEmpty) {
greetingMessage = "Please enter your name";
} else {
greetingMessage = "Hello, ${nameController.text}! 👋";
}
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Input Widgets & Buttons"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: "Enter your name",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: generateGreeting,
child: const Text("Generate Greeting"),
),
const SizedBox(height: 20),
Text(
greetingMessage,
style: const TextStyle(fontSize: 20),
textAlign: TextAlign.center,
),
],
),
),
);
}
}

What's Happening Behind the Scenes

  • TextField collects user input
  • TextEditingController stores the typed text
  • ElevatedButton triggers an action
  • setState() updates the message
  • Flutter rebuilds the UI automatically
Code Output

Breaking Down the Code

Let's now understand what we just built — slowly and clearly, without assuming any prior knowledge.

1. Starting the App

void main() {
runApp(const MyApp());
}
  • Every Flutter app starts here
  • runApp() tells Flutter which widget to show first
  • MyApp is our root widget

2. MaterialApp: App Foundation

return const MaterialApp(
debugShowCheckedModeBanner: false,
home: GreetingApp(),
);
  • MaterialApp provides: themes, navigation, basic app behavior
  • home is the first screen users see
  • GreetingApp is where all our logic lives

3. Why StatefulWidget?

class GreetingApp extends StatefulWidget
  • Our app changes when the user interacts
  • The greeting message updates
  • That means we need state
  • StatefulWidget allows UI to change dynamically

4. Controller & State Variables

final TextEditingController nameController = TextEditingController();
String greetingMessage = "";
  • nameController stores what the user types
  • greetingMessage stores what we want to show on screen
  • When greetingMessage changes, the UI should update

5. Button Logic

void generateGreeting() {
setState(() {
if (nameController.text.isEmpty) {
greetingMessage = "Please enter your name";
} else {
greetingMessage = "Hello, ${nameController.text}! 👋";
}
});
}
  • Button calls this function
  • We read the user input using nameController.text
  • setState() updates the UI
  • Flutter redraws the screen automatically

6. Building the UI

TextField(
controller: nameController,
)
  • User types text here
  • Controller stores it
ElevatedButton(
onPressed: generateGreeting,
)
  • Button triggers logic
Text(greetingMessage)
  • Shows the result
  • Updates automatically when state changes

Why This Pattern Matters

This same pattern is used everywhere in Flutter:

  • Forms
  • Login screens
  • Search features
  • Chat input boxes

Common Beginner Mistakes

Before we close, here are a few small but important mistakes beginners often make when working with input and buttons:

  • Using StatelessWidget when the UI needs to change
  • Forgetting to wrap updates inside setState()
  • Creating TextEditingController inside build()
  • Leaving onPressed as null and wondering why the button doesn't work
  • Not handling empty user input

Avoiding these will save you hours of confusion early on.

Lesson Summary

In this lesson, we took our first real step toward interactive Flutter apps.

You learned how to:

  • take input from users using TextField
  • read that input using TextEditingController
  • trigger actions with buttons
  • update the UI using setState()

With just these basics, you can already build:

  • simple forms
  • search inputs
  • login screens
  • and interactive app features

Do comment and share with others to support us and check our previous lessons here:

List: Flutter Lessons | Curated by YogiCode | Medium

Flutter Lessons · 7 stories on Medium

medium.com

Report Page