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
SliverAppBarwhen 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
SliverAppBarto 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. TheFlexibleSpaceBarin 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
IconButtonfor navigation purposes. In our example, we use anIconButtonwith an arrow icon to simulate a back button. TheonPressedcallback 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
SliverChildListDelegateto include multiple widgets such as theExpandableTextwidget, 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
ExpandableTextwidget. Thetextparameter provides the content to display, andmaxLinessets the maximum number of lines to show when the text is in its collapsed state. - State Management: The
_isExpandedboolean state determines whether the text is fully expanded or collapsed. When_isExpandedistrue, the text will display all its content; whenfalse, it will only display up tomaxLineslines. - GestureDetector: This widget detects user interactions, such as taps. In
ExpandableText, we useGestureDetectorto wrap the “More”/”Less” text at the bottom. When tapped, it toggles the_isExpandedstate 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.horizontalto 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.networkwidget 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
SliverAppBarandSliverList. - 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
ExpandableTextwidget 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
ExpandableTextis aStatefulWidgetto manage expanded/collapsed state.textandmaxLinesare the widget’s properties._isExpandedtracks whether the text is expanded or collapsed._toggleExpandtoggles_isExpandedand callssetStateto rebuild the widget.
UI Components
Textwidget:- Displays the text with a maximum number of lines based on
_isExpanded. - If
_isExpandedistrue,maxLinesisnull(all lines shown). - If
_isExpandedisfalse,maxLinesiswidget.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
CustomScrollAppBarPagewidget combines aSliverAppBarand aSliverListto create a scrollable view with a collapsible app bar and expandable text. - The
ExpandableTextwidget allows users to expand and collapse long descriptions, making the UI more interactive and user-friendly. - The horizontal
ListView.builderprovides a scrolling list of images below the description.