Create Real Estate App UI Design in Flutter | devhubspot
Flutter
UI
Flutter app UI design
real estate
real estate app flutter
Hi, in this video I will teach you how to design a real estate app in Flutter and then walk you through the steps step by step.
Create a Flutter App
If everything is properly set up, then to create a project we can simply run the following command in our desired local directory:
flutter create newsapp
After we've set up the project, we can navigate inside the project directory and execute the following command in the terminal to run the project in either an available emulator or an actual device:
flutter run
First, we need to make some simple configurations to the default boilerplate code in the main.dart file. We'll remove some default code and add the following code
import 'package:estateapp/screens/welcome.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Estate App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: WelcomeScreen(),
);
}
}
Before Starting the code create a constants folder and create colors.dart file inner constants folder and add the following code :
import 'package:flutter/material.dart';
const Color white = Colors.white;
const Color black = Colors.black;
const Color red = Colors.red;
const Color darkBlue = Color.fromRGBO(19, 26, 44, 1.0);
const Color lightBlue = Color.fromRGBO(19, 26, 44, 0.7);
After creating a model folder and create house.dart file inner model folder and add the following code :
class House {
String imageUrl = "";
String address;
String description;
double price;
int bedRooms;
int bathRooms;
double sqFeet;
int garages;
int time;
List<String> moreImagesUrl;
bool isFav;
House(
{required this.imageUrl,
required this.address,
required this.description,
required this.price,
required this.bedRooms,
required this.bathRooms,
required this.sqFeet,
required this.garages,
required this.time,
required this.moreImagesUrl,
required this.isFav});
}
After creating a data folder and create data.dart file inner data folder and add the following code :
import 'package:estateapp/model/house.dart'; final _house1 = House( imageUrl: 'assets/images/house1.jpeg', address: 'Janison, MI 49428,SF', description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', price: 200.00, bedRooms: 4, bathRooms: 2, garages: 2, sqFeet: 1.416, time: 20, isFav: false, moreImagesUrl: [ 'assets/images/house1.jpeg', 'assets/images/indoor1.jpg', 'assets/images/indoor2.jpg', 'assets/images/indoor3.jpg', 'assets/images/indoor4.jpg', 'assets/images/indoor5.jpg', ]); final _house2 = House( imageUrl: 'assets/images/house2.jpeg', address: '351, Rockwood Dr,SF', description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', price: 140.00, bedRooms: 4, bathRooms: 2, garages: 1, sqFeet: 1.416, time: 30, isFav: false, moreImagesUrl: [ 'assets/images/house2.jpeg', 'assets/images/indoor1.jpg', 'assets/images/indoor2.jpg', 'assets/images/indoor3.jpg', 'assets/images/indoor4.jpg', 'assets/images/indoor5.jpg', ]); final _house3 = House( imageUrl: 'assets/images/house2.jpeg', address: '354, Hendrywood Dr,SF', description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', price: 210.00, bedRooms: 5, bathRooms: 3, garages: 1, sqFeet: 1.700, time: 30, isFav: false, moreImagesUrl: [ 'assets/images/house3.jpeg', 'assets/images/indoor1.jpg', 'assets/images/indoor2.jpg', 'assets/images/indoor3.jpg', 'assets/images/indoor4.jpg', 'assets/images/indoor5.jpg', ]); final _house4 = House( imageUrl: 'assets/images/house4.png', address: 'Manison, MI 49526,SF', description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', price: 170.00, bedRooms: 2, bathRooms: 1, garages: 1, sqFeet: 1.210, time: 30, isFav: false, moreImagesUrl: [ 'assets/images/house4.png', 'assets/images/indoor1.jpg', 'assets/images/indoor2.jpg', 'assets/images/indoor3.jpg', 'assets/images/indoor4.jpg', 'assets/images/indoor5.jpg', ]); final _house5 = House( imageUrl: 'assets/images/house5.jpeg', address: 'BackStreet, MI 49526,SF', description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', price: 150.00, bedRooms: 3, bathRooms: 1, garages: 1, sqFeet: 1.42, time: 240, isFav: false, moreImagesUrl: [ 'assets/images/house5.jpeg', 'assets/images/indoor1.jpg', 'assets/images/indoor2.jpg', 'assets/images/indoor3.jpg', 'assets/images/indoor4.jpg', 'assets/images/indoor5.jpg', ]); final List<House> houseList = [ _house2, _house1, _house3, _house4, _house5, ]; List<String> categoryList = [ '< \$220.00', 'For Sale', '3-4 bed room', 'Garages', 'Modular kitchen' ];
After Create Welcome.dart
stateful widget file in the screens folder like screens/welcome.dart, then inside of it with the following code:
import 'package:estateapp/constants/colors.dart'; import 'package:estateapp/screens/home/home.dart'; import 'package:flutter/material.dart'; class WelcomeScreen extends StatefulWidget { const WelcomeScreen({super.key}); @override State<WelcomeScreen> createState() => _WelcomeScreenState(); } class _WelcomeScreenState extends State<WelcomeScreen> { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: lightBlue, body: Padding( padding: const EdgeInsets.all(30.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(), CircleAvatar( radius: 50, backgroundColor: white, child: Image.asset('assets/images/villa.png'), ), const SizedBox(height: 30), const Center( child: Text("Welcome to Estate App", style: TextStyle( color: white, fontSize: 20, fontWeight: FontWeight.bold)), ), const SizedBox(height: 10), const Center( child: Text("Find your home with us", style: TextStyle(color: white, fontSize: 15)), ), const Spacer(), Padding( padding: const EdgeInsets.only(bottom: 20), child: GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen())); }, child: ElevatedButton( onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen())); }, child: const Text("Get Stated", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: darkBlue)), style: ElevatedButton.styleFrom( backgroundColor: white, padding: const EdgeInsets.symmetric( horizontal: 100, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30))), ), ), ) ], ), ), ); } }
After Create home.dart
stateful widget file in the screens folder like screens/home/home.dart, then inside of it with the following code:
import 'package:estateapp/screens/home/components/app_bar.dart';
import 'package:estateapp/screens/home/components/categories.dart';
import 'package:estateapp/screens/home/components/housecard.dart';
import 'package:estateapp/screens/home/components/search.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const AppbarHome(),
const SearchField(),
SizedBox(
height: MediaQuery.of(context).size.height * 0.01,
),
Categories(),
HouseCard()
],
),
);
}
}
Before adding code home.dart create files on the components folder path screens/home/components/
app_bar.dart
import 'package:estateapp/constants/colors.dart';
import 'package:flutter/material.dart';
class AppbarHome extends StatelessWidget {
final TextStyle textStyle = const TextStyle(
fontSize: 16.0, fontWeight: FontWeight.bold, color: darkBlue);
const AppbarHome({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 10, top: 60),
padding: const EdgeInsets.symmetric(horizontal: 30 / 1.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Hello!"),
Text(
"Devhubspot",
style: textStyle,
)
],
),
Container(
height: 50.0,
width: 50.0,
decoration: BoxDecoration(
color: white, borderRadius: BorderRadius.circular(25.0)),
child: const Icon(
Icons.person,
color: darkBlue,
size: 25.0,
),
)
],
),
);
}
}
categories.dart
import 'package:estateapp/constants/colors.dart';
import 'package:estateapp/data/data.dart';
import 'package:flutter/material.dart';
class Categories extends StatefulWidget {
const Categories({super.key});
@override
State<Categories> createState() => _CategoriesState();
}
class _CategoriesState extends State<Categories> {
int selectedIndex = 0;
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.only(left: 30.0, top: 15.0, bottom: 30),
child: Container(
height: size.height * 0.05,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: categoryList.length,
itemBuilder: (context, index) {
return buildCategory(context, index);
},
),
),
);
}
Widget buildCategory(BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
decoration: BoxDecoration(
color: selectedIndex == index ? darkBlue : black.withOpacity(0.1),
borderRadius: BorderRadius.circular(20)),
child: Center(
child: Text(
categoryList[index],
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedIndex == index ? white : black),
),
),
),
),
);
}
}
housecard.dart
import 'package:estateapp/constants/colors.dart';
import 'package:estateapp/data/data.dart';
import 'package:estateapp/model/house.dart';
import 'package:estateapp/screens/detail/detail.dart';
import 'package:flutter/material.dart';
class HouseCard extends StatefulWidget {
const HouseCard({super.key});
@override
State<HouseCard> createState() => _HouseCardState();
}
class _HouseCardState extends State<HouseCard> {
@override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: houseList.length,
itemBuilder: (context, index) {
return buildHouse(context, index);
},
));
}
Widget buildHouse(BuildContext context, int index) {
Size size = MediaQuery.of(context).size;
House house = houseList[index];
return GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => DetailScreen(house: house)));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 15.0),
child: Container(
height: 250,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image(
image: AssetImage(house.imageUrl),
fit: BoxFit.cover,
width: size.width,
height: 180),
),
Positioned(
right: 15.0,
top: 15.0,
child: Container(
decoration: BoxDecoration(
color: white,
borderRadius: BorderRadius.circular(15),
),
child: IconButton(
icon: house.isFav
? Icon(Icons.favorite_rounded, color: red)
: Icon(Icons.favorite_border_rounded, color: black),
onPressed: () {
setState(() {
house.isFav = !house.isFav;
});
},
),
),
)
],
),
Row(
children: [
Text(
'\$${house.price.toStringAsFixed(3)}',
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(width: 10),
Expanded(
child: Text(
house.address,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 15, color: black.withOpacity(0.4)),
),
)
],
),
Row(
children: [
Text(
'${house.bedRooms} bedrooms / ',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
Text(
'${house.bathRooms} bathrooms / ',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
Text(
'${house.sqFeet} sqft',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
],
),
],
),
),
),
);
}
}
search.dart
import 'package:estateapp/constants/colors.dart';
import 'package:flutter/material.dart';
class SearchField extends StatelessWidget {
const SearchField({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 30 / 1.5),
child: Material(
elevation: 2.0,
borderRadius: const BorderRadius.all(Radius.circular(30.0)),
child: TextFormField(
style: const TextStyle(color: black, fontSize: 16.0),
cursorColor: Colors.grey.shade300,
decoration: const InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 32.0, vertical: 14.0),
suffixIcon: Material(
elevation: 0,
borderRadius: BorderRadius.all(Radius.circular(30.0)),
child: Icon(
Icons.search,
color: Colors.black45,
),
),
border: InputBorder.none,
hintText: "Search for House..."),
),
),
);
}
}
After Create detail.dart
stateful widget file in the screens folder like screens/detail.dart, then inside of it with the following code:
import 'package:estateapp/model/house.dart';
import 'package:estateapp/screens/detail/components/appbar.dart';
import 'package:estateapp/screens/detail/components/carousel_images.dart';
import 'package:estateapp/screens/detail/components/house_detail.dart';
import 'package:flutter/material.dart';
class DetailScreen extends StatefulWidget {
final House house;
const DetailScreen({super.key, required this.house});
@override
State<DetailScreen> createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Stack(
children: [
CarouselImages(widget.house.moreImagesUrl),
AppBarDetail()
],
),
HouseDetail(widget.house)
],
),
),
);
}
}
Before adding code details.dart create files on the components folder path screens/details/components/
appbar.dart
import 'package:estateapp/constants/colors.dart';
import 'package:flutter/material.dart';
class AppBarDetail extends StatelessWidget {
const AppBarDetail({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.only(left: 30, right: 30, top: 30),
child: Container(
height: size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(
color: darkBlue,
border: Border.all(color: darkBlue),
borderRadius: BorderRadius.circular(15)),
child: const Icon(Icons.chevron_left_rounded, color: white),
),
),
Container(
height: 50,
width: 50,
decoration: BoxDecoration(
color: darkBlue, borderRadius: BorderRadius.circular(15)),
child: Icon(
Icons.favorite_border_rounded,
color: white,
),
)
],
),
),
);
}
}
carousel_images.dart
import 'package:flutter/material.dart';
import 'package:flutter_image_slideshow/flutter_image_slideshow.dart';
class CarouselImages extends StatefulWidget {
final List<String> imagesListUrl;
CarouselImages(this.imagesListUrl);
@override
State<CarouselImages> createState() => _CarouselImagesState();
}
class _CarouselImagesState extends State<CarouselImages> {
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
debugPrint(widget.imagesListUrl.length.toString());
List<AssetImage> imageWidgets =
widget.imagesListUrl.take(6).map((imageurl) {
return AssetImage(imageurl);
}).toList();
return Container(
height: size.height * 0.35,
child: ImageSlideshow(
indicatorColor: Colors.black,
onPageChanged: (value) {
debugPrint('Page changed: $value');
},
// autoPlayInterval: 3000,
isLoop: true,
children: [
Container(
height: 200,
child: ListView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: widget.imagesListUrl.length,
itemBuilder: (context, index) {
return Image.asset(
widget.imagesListUrl[index],
fit: BoxFit.cover,
);
},
),
)
]
// [
// Image.asset(
// 'images/sample_image_1.jpg',
// fit: BoxFit.cover,
// ),
// Image.asset(
// 'images/sample_image_2.jpg',
// fit: BoxFit.cover,
// ),
// Image.asset(
// 'images/sample_image_3.jpg',
// fit: BoxFit.cover,
// ),
// ],
),
);
// Image.asset(widget.imagesListUrl.first));
}
}
house_detail.dart
import 'package:estateapp/constants/colors.dart';
import 'package:estateapp/model/house.dart';
import 'package:flutter/material.dart';
class HouseDetail extends StatefulWidget {
final House house;
HouseDetail(this.house);
@override
State<HouseDetail> createState() => _HouseDetailState();
}
class _HouseDetailState extends State<HouseDetail> {
@override
Widget build(BuildContext context) {
return Expanded(
child: ListView(
physics: BouncingScrollPhysics(),
shrinkWrap: true,
children: [
Padding(
padding: EdgeInsets.only(bottom: 30, left: 30, right: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'\$${widget.house.price.toStringAsFixed(3)}',
style:
TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
SizedBox(
height: 5,
),
Text(
widget.house.address,
style: TextStyle(
fontSize: 15,
color: black.withOpacity(0.4),
fontWeight: FontWeight.w600),
)
],
),
Text(
'${widget.house.time} hours ago',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
)
],
),
),
Padding(
padding: EdgeInsets.only(left: 30.0, bottom: 30.0),
child: Text(
"House Infomation",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
Padding(
padding: EdgeInsets.only(left: 30, right: 30, bottom: 120),
child: Text(
widget.house.description,
style: TextStyle(color: black.withOpacity(0.4), height: 2.0),
textAlign: TextAlign.justify,
),
)
],
),
);
}
}
Output:
Flutter
UI
Flutter app UI design
real estate
real estate app flutter