Building a Native-Looking iOS App with Flutter

When building a mobile app, it’s essential to create a user interface that looks and feels native to the platform. For iOS apps, this means using a design system that incorporates elements such as navigation bars, tab bars, and action sheets. In this tutorial, we’ll explore how to build an iOS app that looks and feels native using Flutter.

Creating a Simple Page

To get started, let’s create a simple page that displays a title at the top and a “Hello” message in the center. We can use the CupertinoApp widget to create a basic iOS-style app.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoPageScaffold(
child: Center(
child: Text(‘Hello’),
),
),
);
}
}
“`

Adding Tabs

Next, let’s add three tabs to our app: Calls, Chats, and Settings. We can use the CupertinoTabScaffold widget to create a tab bar at the bottom of the screen.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return Center(
child: Text(‘Tab $index’),
);
},
);
},
),
);
}
}
“`

Adding a Navigation Bar

Now, let’s add a navigation bar to our app that hides when the user scrolls down. We can use the CupertinoSliverNavigationBar widget to create a navigation bar that hides when the user scrolls.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return CustomScrollView(
slivers: [
CupertinoSliverNavigationBar(
largeTitle: Text(‘Navigation Bar’),
),
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 100,
color: Colors.red,
),
Container(
height: 100,
color: Colors.blue,
),
],
),
),
],
);
},
);
},
),
);
}
}
“`

Adding a Loading Indicator

Next, let’s add a loading indicator to our app that displays when the user is waiting for data to load. We can use the CupertinoActivityIndicator widget to create a loading indicator.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return Center(
child: CupertinoActivityIndicator(),
);
},
);
},
),
);
}
}
“`

Enabling Search

Now, let’s enable search in our app. We can use the CupertinoSearchTextField widget to create a search field.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return CustomScrollView(
slivers: [
CupertinoSliverNavigationBar(
largeTitle: Text(‘Search’),
),
SliverList(
delegate: SliverChildListDelegate(
[
CupertinoSearchTextField(),
],
),
),
],
);
},
);
},
),
);
}
}
“`

Adding a Switch

Next, let’s add a switch to our app. We can use the CupertinoSwitch widget to create a switch.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return Center(
child: CupertinoSwitch(
value: true,
onChanged: (value) {},
),
);
},
);
},
),
);
}
}
“`

Showing an Action Sheet

Now, let’s show an action sheet in our app. We can use the CupertinoActionSheet widget to create an action sheet.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return Center(
child: CupertinoButton(
onPressed: () {
showCupertinoModalPopup(
context: context,
builder: (context) {
return CupertinoActionSheet(
actions: [
CupertinoActionSheetAction(
onPressed: () {},
child: Text(‘Action 1’),
),
CupertinoActionSheetAction(
onPressed: () {},
child: Text(‘Action 2’),
),
],
);
},
);
},
child: Text(‘Show Action Sheet’),
),
);
},
);
},
),
);
}
}
“`

Displaying an Alert Dialog

Next, let’s display an alert dialog in our app. We can use the CupertinoAlertDialog widget to create an alert dialog.

“`dart
import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.phone),
label: ‘Calls’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble),
label: ‘Chats’,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings),
label: ‘Settings’,
),
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return Center(
child: CupertinoButton(
onPressed: () {
showCupertinoDialog(
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text(‘Alert Dialog’),
content: Text(‘This is an alert dialog’),
actions: [

Leave a Reply

Your email address will not be published. Required fields are marked *