Build beautiful settings screens by using the settings_ui package
Most mobile applications require a settings screen. In this post, we are going to have a look at the settings_ui package which simplifies this process. This package makes it much easier to create good-looking settings screens for your Flutter applications. Whether you want to let users pick a language, manage their profile, or turn on dark mode, the settings_ui package can help you do all that without a lot of effort.
Installing
To get started with implementing, we need to install the settings_ui package into our project. The installation process is simple. Just execute the following command: flutter pub add settings_ui
.
Once the command is executed, make sure to check your pubspec.yaml
file for the added dependencies. You should see the settings_ui package included in the dependencies section, like this:
dependencies:
flutter:
sdk: flutter
settings_ui: ^2.0.2
Creating a Settings screen
Designing a settings screen using the settings_ui package is quite easy. The package has a SettingsList
widget. This widget can hold different sections of settings, and each section can contain various types of settings, see the code down below:
import 'package:flutter/material.dart';
import 'package:settings_ui/settings_ui.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SettingsScreen(),
);
}
}
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Settings', textAlign: TextAlign.center),
),
body: SettingsList(
sections: [
SettingsSection(
title: Text('General', style: TextStyle(color: Colors.black)),
tiles: <SettingsTile>[
SettingsTile(
leading: Icon(Icons.language),
title: Text('Language'),
),
SettingsTile.navigation(
leading: Icon(Icons.person),
title: Text('Profile'),
),
SettingsTile.switchTile(
leading: Icon(Icons.dark_mode),
title: Text('Dark mode'),
initialValue: false,
onToggle: (bool value) {},
),
],
),
],
),
);
}
}
In this code snippet, we created two widgets: MyApp
and the SettingsScreen
. The MyApp
widget sets up our application and the SettingsScreen
widget is where we create our settings page.
Inside the SettingsScreen
widget, we have a Scaffold
widget to create our page layout. On the body property of the Scaffold
widget, we have a SettingsList
. Inside the SettingsList
we created one section by providing the SettingsSection
inside the sections
property. Inside this section, we added one of each available tiles: SettingsTile
, SettingsTile.navigation
and SettingsTile.switchTile
with their required properties.
Within the SettingsScreen
widget, a Scaffold
widget helps structure the page layout. The body of the Scaffold
contains a SettingsList
widget. Within this SettingsList
widget, we created a section by providing a SettingsSection
widget into the sections
property. Inside this section, we added one of each available settings tile: SettingsTile
, SettingsTile.navigation
and SettingsTile.switchTile
with their required properties.
When we build the application we will end up with the following settings screen:

Changing style
To change the style of our settings screen we can set the platform
property of the SettingsList
widget:
SettingsList(
platform: DevicePlatform.iOS,
sections: [
SettingsSection( ... ),
],
),
In this code snippet, we set the platfrom
property to DevicePlatform.iOS
, to change the overall style of our SettingsList
:

As of now the settings_ui package only has different styling for iOS. The other platform all have the same style.
Adding Functionality to the settings
Now that we have built the layout of our settings screen, we can move on to add the functionality. The first code snippet below is the complete implementation of the functionality, however, underneath this code snippet, we will go over every setting implementation individually:
import 'package:flutter/material.dart';
import 'package:settings_ui/settings_ui.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SettingsScreen(),
);
}
}
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _darkMode = false;
String _language = 'English';
List<String> _languages = <String>['English', 'German', 'Spanish'];
final GlobalKey _dropdownButtonKey = GlobalKey();
void _openDropdown() {
_dropdownButtonKey.currentContext?.visitChildElements((element) {
if (element.widget is Semantics) element.visitChildElements((element) {
if (element.widget is Actions) element.visitChildElements(
(element) => Actions.invoke(element, ActivateIntent())
);
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Settings', textAlign: TextAlign.center),
),
body: SettingsList(
sections: [
SettingsSection(
title: Text('General', style: TextStyle(color: Colors.black)),
tiles: <SettingsTile>[
SettingsTile(
leading: Icon(Icons.language),
title: Text('Language'),
onPressed: (_) => _openDropdown(),
trailing: DropdownButton(
key: _dropdownButtonKey,
value: _language,
onChanged: (String? value) => setState(
() => _language = value!,
),
items: _languages
.map<DropdownMenuItem<String>>(
(String value) => DropdownMenuItem(
value: value,
child: Text(value),
),
)
.toList(),
),
),
SettingsTile.navigation(
leading: Icon(Icons.person),
title: Text('Profile'),
onPressed: (context) => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
),
),
SettingsTile.switchTile(
leading: Icon(Icons.dark_mode),
title: Text('Dark mode'),
onToggle: (bool value) => setState(() => _darkMode = value),
initialValue: _darkMode,
),
],
),
],
),
);
}
}
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
);
}
}
1. SettingsTile
The regular SettingsTile
offers a lot of customization, in this example, we will be creating a language selector.
To start off we have to make some changes inside our _SettingsScreenState
state:
class _SettingsScreenState extends State {
String _language = 'English';
List _languages = ['English', 'German', 'Spanish'];
final GlobalKey _dropdownButtonKey = GlobalKey();
void _openDropdown() {
_dropdownButtonKey.currentContext?.visitChildElements((element) {
if (element.widget is Semantics) element.visitChildElements((element) {
if (element.widget is Actions) element.visitChildElements(
(element) => Actions.invoke(element, ActivateIntent())
);
});
});
}
@override
Widget build(BuildContext context) { ... }
}
In this code snippet, we added three variables: _language
, _languages
and _dropdownButtonKey
. The _language
variable hold the currently selected language, the _languages
variable holds a list of all the available languages and _dropdownButtonKey
variable is needed for the _openDropdown
function.
The _openDropdown
function is used to open the DropdownMenuItem
widget when tapping the SettingTile
. The DropdownMenuItem
widget will be used to make the languages selectable.
SettingsTile(
leading: Icon(Icons.language),
title: Text('Language'),
onPressed: (_) => _openDropdown(),
trailing: DropdownButton(
key: _dropdownButtonKey,
value: _language,
onChanged: (String? value) => setState(
() => _language = value!,
),
items: _languages
.map<DropdownMenuItem<String>>(
(String value) => DropdownMenuItem(
value: value,
child: Text(value),
),
)
.toList(),
),
),
In this code snippet, we updated the SettingsTile
widget with the onPressed
and trailing
properties. The onPressed
property calls the openDropdown
function when the setting is tapped. The trailing
property takes a Widget
and will be displayed at the end of the setting. In this case, we added the DropDownButton
widget which holds a list of the available languages in its items
property. When another language is selected we change the value of the _language
variable calling setState
inside the onChanged
property.

2. SettingsTile.navigation
The SettingsTile.navigation
can be used to navigate to different screens. In this case, we will navigate to a profile screen.
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
);
}
}
In this code snippet, we create the ProfileScreen
widget. This is a simple widget that serves as our profile screen. It returns a Scaffold
widget with an AppBar
widget that has the title "Profile".
SettingsTile.navigation(
leading: Icon(Icons.person),
title: Text('Profile'),
onPressed: (context) => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
),
),
In this code snippet, we updated the SettingsTile.navigation
widget with the onPressed
property. Now when we tap the profile setting we will navigate to the ProfileScreen
using Navigator.of(context).push
.

3. SettingsTile.switch
To create a simple switch you can use the SettingsTile.switch
widget. In this case, we used the widget to create a dark mode switch.
class _SettingsScreenState extends State<SettingsScreen> {
bool _darkMode = false;
@override
Widget build(BuildContext context) { ... }
}
In this code snippet, we added a _darkMode
variable with the default value of false
to our _SettingsScreenState
state.
SettingsTile.switchTile(
leading: Icon(Icons.dark_mode),
title: Text('Dark mode'),
onToggle: (bool value) => setState(() => _darkMode = value),
initialValue: _darkMode,
),
In this code snippet, we added the onToggle
and initialValue
properties. The onToggle
property changes our _darkMode
variable by using the setState
function when the setting is tapped. The initialValue
is set to the _darkMode
variable which means that the initial value will be false
.

Conclusion
In this post, we have explored the settings_ui package, a helpful tool for designing good-looking settings screens in Flutter applications. It is designed to be simple, so you can spend more time improving how the application works and how users enjoy it. It is a great choice for making mobile applications more interesting and user-friendly.