In this article, we will create a custom scrollable app bar with a background image in Flutter. The app bar will shrink as the user scrolls up, and it will include a back button. Below the image, we will display some descriptive text with a “More” or “Less” button to show or hide additional text. Finally, we will add a section to display recent images in a horizontal list.
Prerequisites
Make sure you have Flutter installed on your machine. You can follow the official Flutter installation guide if you haven’t installed it yet.
Step-by-Step Implementation
Step 1: Create a New Flutter Project
Create a new Flutter project using the following command:
flutter create custom_scroll_app_bar
Navigate to the project directory:
cd custom_scroll_app_bar
Step 2: Update
pubspec.yaml
Ensure you have the necessary dependencies in your pubspec.yaml
file. For this example, we only need the default Flutter SDK:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
Run flutter pub get
to install the dependencies.
Step 3: Implement the Main App
Open the lib/main.dart
file and replace its contents with the following code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CustomScrollAppBarPage(),
);
}
}
class CustomScrollAppBarPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 300.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Custom Scroll App Bar'),
background: Image.network(
'https://via.placeholder.com/600x400',
fit: BoxFit.cover,
),
),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
// Handle back button press
},
),
),
SliverList(
delegate: SliverChildListDelegate(
[
Padding(
padding: const EdgeInsets.all(16.0),
child: ExpandableText(
text: 'Description text goes here. You can add multiple lines of text to describe something in detail. This is just an example of how you can structure your content below the app bar. ' * 5,
maxLines: 3,
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Recent Images',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
Container(
height: 200.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Image.network('https://via.placeholder.com/200x150'),
);
},
),
),
],
),
),
],
),
);
}
}
class ExpandableText extends StatefulWidget {
final String text;
final int maxLines;
const ExpandableText({required this.text, this.maxLines = 3});
@override
_ExpandableTextState createState() => _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText> {
bool _isExpanded = false;
void _toggleExpand() {
setState(() {
_isExpanded = !_isExpanded;
});
}
@override
Widget build(BuildContext context) {
final textWidget = Text(
widget.text,
maxLines: _isExpanded ? null : widget.maxLines,
overflow: _isExpanded ? TextOverflow.visible : TextOverflow.ellipsis,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
textWidget,
GestureDetector(
onTap: _toggleExpand,
child: Text(
_isExpanded ? 'Less' : 'More',
style: TextStyle(color: Colors.blue),
),
),
],
);
}
}
SliverAppBar
SliverAppBar
is a specialized app bar in Flutter that integrates seamlessly with a scrollable view, allowing for a flexible and dynamic header that can expand and collapse. This is particularly useful for creating rich, interactive user interfaces where the app bar can provide more content when fully expanded and streamline the view when collapsed.
- expandedHeight: This property determines the height of the
SliverAppBar
when it is fully expanded. In our example, it’s set to 300.0 pixels, which means the app bar will take up 300 pixels of vertical space when fully expanded. - FlexibleSpaceBar: This widget is used within the
SliverAppBar
to provide a flexible space that can change size as the app bar expands and collapses. It can include a title, a background image, and other widgets. TheFlexibleSpaceBar
in our example includes a title (Custom Scroll App Bar
) and a background image loaded from a network URL. - leading: This property allows you to add a widget at the leading edge of the app bar, typically an
IconButton
for navigation purposes. In our example, we use anIconButton
with an arrow icon to simulate a back button. TheonPressed
callback can be customized to handle the back button’s functionality.
SliverList
SliverList
is used to create a scrollable list of widgets within a CustomScrollView
. It efficiently renders only the visible items, which is particularly useful for long lists.
- SliverChildListDelegate: This delegate takes a list of widgets to display. It converts the list into a scrollable list of items. In our example, we use
SliverChildListDelegate
to include multiple widgets such as theExpandableText
widget, a text widget for the section title, and a horizontal list of recent images.
ExpandableText
ExpandableText
is a custom widget designed to display a block of text that can be expanded or collapsed based on user interaction. This is particularly useful for long descriptions where you want to save screen space and provide the user with control over how much content they see.
- text and maxLines: These are the main inputs for the
ExpandableText
widget. Thetext
parameter provides the content to display, andmaxLines
sets the maximum number of lines to show when the text is in its collapsed state. - State Management: The
_isExpanded
boolean state determines whether the text is fully expanded or collapsed. When_isExpanded
istrue
, the text will display all its content; whenfalse
, it will only display up tomaxLines
lines. - GestureDetector: This widget detects user interactions, such as taps. In
ExpandableText
, we useGestureDetector
to wrap the “More”/”Less” text at the bottom. When tapped, it toggles the_isExpanded
state and triggers a rebuild to update the UI accordingly.
ListView.builder
ListView.builder
is a powerful and efficient way to create scrollable lists of widgets in Flutter. It dynamically builds its children on demand, which is particularly useful for long lists.
- scrollDirection: In this example, it’s set to
Axis.horizontal
to create a horizontal scrolling list of recent images. - itemCount: This property specifies the number of items in the list. Here, it’s set to 10, indicating that the list will have 10 items.
- itemBuilder: This function is called to build each item in the list. It takes the current context and the index of the item to build. In our example, each item is a padded
Image.network
widget that displays an image loaded from a URL.
Full Code and Explanation
The complete implementation combines these elements to create a sophisticated user interface in Flutter. Here’s how everything fits together:
- CustomScrollView: This is the main container that allows for a scrollable area with multiple slivers, including
SliverAppBar
andSliverList
. - SliverAppBar: Provides an expandable and collapsible app bar with a background image and a title. It also includes a back button for navigation.
- SliverList: Contains the list of widgets to display below the app bar. This includes the
ExpandableText
widget for the description and a horizontal list of recent images. - ExpandableText: Manages its state to toggle between showing a limited number of lines and the full text, providing a “More”/”Less” button for user interaction.
- ListView.builder: Displays a horizontally scrollable list of recent images.
By using these components together, you can create a rich, interactive, and scrollable user interface in Flutter. Adjust the properties and content as needed to customize the appearance and behavior of your app.
class ExpandableText extends StatefulWidget {
final String text;
final int maxLines;
const ExpandableText({required this.text, this.maxLines = 3});
@override
_ExpandableTextState createState() => _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText> {
bool _isExpanded = false;
void _toggleExpand() {
setState(() {
_isExpanded = !_isExpanded;
});
}
@override
Widget build(BuildContext context) {
final textWidget = Text(
widget.text,
maxLines: _isExpanded ? null : widget.maxLines,
overflow: _isExpanded ? TextOverflow.visible : TextOverflow.ellipsis,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
textWidget,
GestureDetector(
onTap: _toggleExpand,
child: Text(
_isExpanded ? 'Less' : 'More',
style: TextStyle(color: Colors.blue),
),
),
],
);
}
}
Widget Structure
ExpandableText
is aStatefulWidget
to manage expanded/collapsed state.text
andmaxLines
are the widget’s properties._isExpanded
tracks whether the text is expanded or collapsed._toggleExpand
toggles_isExpanded
and callssetState
to rebuild the widget.
UI Components
Text
widget:- Displays the text with a maximum number of lines based on
_isExpanded
. - If
_isExpanded
istrue
,maxLines
isnull
(all lines shown). - If
_isExpanded
isfalse
,maxLines
iswidget.maxLines
(collapsed state).
- Displays the text with a maximum number of lines based on
GestureDetector
:- Detects taps on the “More”/”Less” text to toggle the expanded state.
- Changes its text based on
_isExpanded
.
Putting It All Together
- The
CustomScrollAppBarPage
widget combines aSliverAppBar
and aSliverList
to create a scrollable view with a collapsible app bar and expandable text. - The
ExpandableText
widget allows users to expand and collapse long descriptions, making the UI more interactive and user-friendly. - The horizontal
ListView.builder
provides a scrolling list of images below the description.