Flutter - How to scroll Container over another - flutter

I'm begginning Flutter and I'm searching to scroll ListView over a Container like below

You can use DraggableScrollableSheet
DraggableScrollableSheet(
builder: (context, scrollController) {
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: [],
),
);
},
)
You can follow the doc example
A complete widget
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
openDraggable(context) {
showModalBottomSheet(
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(22),
topRight: Radius.circular(22),
)),
context: context,
builder: (context) => DraggableScrollableSheet(
maxChildSize: 1,
initialChildSize: .4,
expand: false,
builder: (context, scrollController) {
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: [
for (int i = 0; i < 32; i++)
ListTile(
title: Text("item"),
),
],
),
);
},
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
openDraggable(context);
},
child: Text("open"),
)
],
),
),
);
}
}

Don't use DraggableScrollableSheet. instead of that widget use the sliver widget, this widget is amazing,
you can use this article and this

CustomScrollView(
slivers: <Widget>[
// appbar of search page
SliverAppBar(
// icon in top left
leading: _icon(context),
// backgroun of appbar
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
// style of app bar
pinned: true,
floating: true,
snap: true,
expandedHeight: 130,
// obtional filter for product
flexibleSpace: FlexibleSpaceBar(
background: Padding(
padding: const EdgeInsets.only(top: 80.0),
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(8.0),
padding: const EdgeInsets.symmetric(horizontal: 10.0),
decoration: BoxDecoration(
borderRadius: borderRadius_30,
color: Theme.of(context).primaryColorLight),
child: TextField(
onChanged: (value) {
// you can sort data for user in this section
},
style: TextStyle(
color: Theme.of(context).textSelectionColor,
),
decoration: InputDecoration(
border: InputBorder.none,
// styel of labeltext in textfield
labelStyle: TextStyle(
color: Colors.cyan,
),
labelText: Strings.search,
),
),
),
),
),
),
// body
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return SearchBody(index);
},
childCount: fakeData.length,
),
// number of object
)
],
),
You can use the sliver package, something like this.

Related

How to Create This Tab View in Flutter with SyncFusion? What is the Name of the Widget?

I am trying to create this kind of tab view but I am so confused what the name of the widget is in Flutter and SyncFusion. I want to create this chart with 2 tab, the first tab is voltage chart and the second one is current chart. Thank you.
Here's the picture:
Here's my current code:
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: const SideMenu(),
body: FutureBuilder(
future: getData2(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Loading();
} else if (snapshot.hasError) {
return Text(snapshot.hasError.toString());
} else {
final themeChange = Provider.of<DarkThemeProvider>(context);
return SafeArea(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (Responsive.isDesktop(context))
const Expanded(
child: SideMenu(),
),
Expanded(
flex: 5,
child: SingleChildScrollView(
primary: false,
padding: const EdgeInsets.all(defaultPadding),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(defaultPadding),
child: const Header(),
),
const SizedBox(height: defaultPadding),
Container(
decoration: BoxDecoration(
color: themeChange.darkTheme
? secondaryColor
: quarterColor,
borderRadius:
const BorderRadius.all(Radius.circular(10)),
),
padding: const EdgeInsets.all(defaultPadding),
child: DefaultTabController(
length: 2,
child: Column(
children: [
SizedBox(
height: 40.0,
child: TabBar(
controller: _tabController,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
color: Colors.yellow,
width: 3.0,
),
),
indicatorPadding:
const EdgeInsets.all(2.0),
tabs: const [
Text(
'Voltages Chart',
),
Text(
'Currents Chart',
),
],
),
),
],
),
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
ListView.builder(
itemCount: 100,
itemBuilder: (context, int index) {
return const DwpVoltageCharts();
},
),
ListView.builder(
itemCount: 100,
itemBuilder: (context, int index) {
return const DwpCurrentCharts();
},
),
],
),
),
const SizedBox(height: defaultPadding),
Container(
padding: const EdgeInsets.all(defaultPadding),
decoration: BoxDecoration(
color: themeChange.darkTheme
? secondaryColor
: quarterColor,
borderRadius:
const BorderRadius.all(Radius.circular(10)),
),
child: const Center(
child: PowerChart(),
),
),
],
),
),
)
],
),
);
}
}),
);
}
}
Please this is my currents code and I don't know how to make it works because I am really new about it. Thank You.
You can achieve your requirement using the DefaultTabController, TabBar and TabBarView widgets available in the flutter framework. We have created a simple sample in which we have achieved your requirement to switch between two tabs to view the voltage and current chart and attached the sample below for reference.
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/i407342-45112383

Flutter: Keyboard causing a renderflex overflow error

I'm trying to display a message to the user unless there is a renderflex overflow error of 212px at the bottom. Actually, I use a separate widget to display the message, and every time I try to type with my phone, I get an error. I tried several solutions but none of them worked for me.
I would appreciate it if someone took a look. Thanks in advance!
Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Passation chat',
style: TextStyle(color: Colors.black),
),
centerTitle: true,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Messages'),
Container(
height: 590,
child: SingleChildScrollView(
physics: ScrollPhysics(), reverse: true, child: ShowMessages()),
),
Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.blue, width: 0.2))),
child: TextField(
controller: msgController,
decoration: InputDecoration(hintText: 'Enter Message'),
),
),
),
IconButton(
onPressed: () {
if (msgController.text.isNotEmpty) {
storeMessage.collection('Messages').doc().set({
"msg": msgController.text.trim(),
"user": logInUser!.email.toString(),
"time": DateTime.now()
});
msgController.clear();
FocusManager.instance.primaryFocus?.unfocus();
}
},
icon: Icon(
Icons.send,
color: Colors.blueAccent,
))
],
),
],
),
);
}
}
class ShowMessages extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('Messages')
.orderBy('time')
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
QueryDocumentSnapshot x = snapshot.data!.docs[index];
return ListTile(
title: Column(
crossAxisAlignment: logInUser!.email == x['user']
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
children: [
Container(
child: Column(children: [
Text(x['msg']),
SizedBox(
height: 5,
),
Text(
x['user'],
style: TextStyle(fontSize: 10),
)
]),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
color: logInUser!.email == x['user']
? Colors.blue.withOpacity(0.2)
: Colors.amber.withOpacity(0.1),
borderRadius: BorderRadius.circular(15)),
),
],
),
);
},
shrinkWrap: true,
primary: true,
physics: ScrollPhysics(),
);
},
);
}
}
Screenshots from the app:
Make SingleChildScrollView the first widget of Scaffold body.
Fixed it by wrapping the Column widget by a SingleChildScrollView. Thanks mates!

How to scroll with NestedScrollView to use stack Circle Avatar over SliverAppBar?

I am dealing with a Flutter project recently and I have such a problem.
See photo 1: here's my code: the photo and text should be between the TabBar widget and the red background like in design (blue).
Here you can see my actual code:
class Main
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
PortfolioSliverAppBar(_pages[_tabController.index].item1),
SliverPersistentHeader(
delegate: SliverPersistentHeaderDelegateImpl(
tabBar: TabBar(
padding: EdgeInsets.only(top: 15.0),
labelColor: Colors.black,
indicatorColor: Colors.black,
indicator: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(18)),
color: Colors.blue),
controller: _tabController,
tabs: _pages
.map<Tab>((Tuple3 page) => Tab(text: page.item1))
.toList(),
),
),
),
];
},
body: Container(
margin: EdgeInsets.only(top: 20.0),
child: TabBarView(
controller: _tabController,
children: _pages.map<Widget>((Tuple3 page) => page.item2).toList(),
),
),
class Silver
class SliverPersistentHeaderDelegateImpl extends SliverPersistentHeaderDelegate {
final TabBar tabBar;
final Color color;
const SliverPersistentHeaderDelegateImpl({
Color color = Colors.transparent,
#required this.tabBar,
}) : this.color = color;
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: color,
child: tabBar,
);
}
See photo 2: here's the given design:
my view
the actual UI
Thanks a lot!
Please refer to below code
class NestedScrollWithTabs extends StatefulWidget {
const NestedScrollWithTabs({Key key}) : super(key: key);
#override
_NestedScrollWithTabsState createState() => _NestedScrollWithTabsState();
}
class _NestedScrollWithTabsState extends State<NestedScrollWithTabs>
with TickerProviderStateMixin {
var animation;
var controller;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: DefaultTabController(
length: 2,
child: NestedScrollView(
physics: NeverScrollableScrollPhysics(),
headerSliverBuilder: (headerCtx, innnerBoxIsScrolled) {
if (innnerBoxIsScrolled) {
/* Animation */
controller = AnimationController(
vsync: this,
duration: Duration(
seconds: 1,
),
);
animation = Tween(
begin: 0.0,
end: 1.0,
).animate(controller);
/* Animation */
controller.forward();
}
return <Widget>[
SliverAppBar(
expandedHeight: ScreenUtil().setHeight(185.0),
floating: false,
pinned: true,
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
titleSpacing: 0.0,
centerTitle: true,
elevation: 0.0,
leadingWidth: 0.0,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
if (innnerBoxIsScrolled != null &&
innnerBoxIsScrolled == true)
FadeTransition(
opacity: animation,
child: Text(
"Title",
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),
],
),
flexibleSpace: FlexibleSpaceBar(
background: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Image.network(
"https://images.pexels.com/photos/10181294/pexels-photo-10181294.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" ??
"",
fit: BoxFit.fitWidth,
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
filterQuality: FilterQuality.low,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Container(
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
color: Colors.grey,
);
},
errorBuilder: (context, error, stackTrace) {
return SizedBox(
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
child: Container(
width: ScreenUtil().screenWidth,
),
);
},
),
Positioned(
top: ScreenUtil().setHeight(92.0),
// left: ScreenUtil().setWidth(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: Colors.transparent,
radius: 30.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(
45.0,
),
child: Image.network(
"https://images.pexels.com/photos/10181294/pexels-photo-10181294.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" ??
"",
fit: BoxFit.fill,
height: ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
filterQuality: FilterQuality.low,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null)
return child;
return Container(
height:
ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
color: Colors.grey,
);
},
errorBuilder:
(context, error, stackTrace) {
return SizedBox(
height:
ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
child: Container(
width: ScreenUtil().screenWidth,
),
);
},
),
),
),
Text("Name"),
Text("Place"),
],
),
),
],
),
],
),
),
),
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
headerCtx),
sliver: SliverPersistentHeader(
delegate: SliverAppBarDelegate(TabBar(
labelColor: Colors.blue,
unselectedLabelColor: Colors.black,
labelStyle: TextStyle(
fontSize: 15.0,
),
unselectedLabelStyle: TextStyle(
fontSize: 15.0,
),
labelPadding: EdgeInsets.zero,
indicatorColor: Colors.blue,
indicatorPadding: EdgeInsets.zero,
physics: NeverScrollableScrollPhysics(),
tabs: [
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
],
)),
pinned: false,
),
),
];
},
body: TabBarView(
children: [
/* Tab 1 */
Container(
color: Colors.white,
child: ListView.builder(
itemCount: 100,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Text("Index value: $index"),
);
},
),
),
/* Tab 2 */
Container(
color: Colors.white,
child: ListView.builder(
itemCount: 10,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Text("Index value of Tab 2: $index"),
);
},
),
),
],
),
),
),
),
);
}
}
class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
SliverAppBarDelegate(this.tabBars);
final TabBar tabBars;
#override
double get minExtent => 60.0;
#override
double get maxExtent => 60.0;
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
// shinkOffsetPerValue.value = shrinkOffset;
return new Container(
color: Colors.white,
child: Column(
children: [
tabBars,
],
),
);
}
#override
bool shouldRebuild(SliverAppBarDelegate oldDelegate) {
return false;
}
}

How can I create the YouTube Modal Bottom Sheet with Flutter?

I want to have a modal bottom sheet that I can scroll through as normal without closing the modal bottom sheet. Then, when I'm at the top of my list, I want to be able to close the Modal Bottom Sheet with a scroll gesture.
I would like to add the YouTube style modal bottom sheet shown in the video to my app, but unfortunately I don't know how to do it.
This is the link to the video that shows what I mean: https://drive.google.com/file/d/1977Ptq4Sox6WKGQkiTbCH_zydn8Mu05o/view?usp=sharing
This is inside my Profile Screen:
#override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Container(
height: MediaQuery.of(context).size.height * 0.95,
margin: EdgeInsets.only(bottom: 5, left: 10, right: 10),
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 1.5),
borderRadius: BorderRadius.circular(25),
color: Colors.white,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(23),
child: DraggableScrollableSheet(
initialChildSize: 1,
minChildSize: 0.5,
maxChildSize: 1,
expand: false,
builder: (BuildContext context, ScrollController _scrollController) {
return SingleChildScrollView(
controller: _scrollController,
child: Column(
children: [
Container(
height: 590,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1.5, color:
Colors.black),
),
color: Colors.white,
),
child: Stack(
children: [
InteractiveViewer(
transformationController:
_zoomProfilePictureController,
minScale: 1,
maxScale: 3,
onInteractionEnd: (ScaleEndDetails endDetails) {
setState(() {
_zoomProfilePictureController.value =
Matrix4.identity();
});
},
child: Swiper(
physics: NeverScrollableScrollPhysics(),
itemBuilder:
(BuildContext context, int imageIndex) {
return Hero(
tag: "Profile",
child: CachedNetworkImage(
imageUrl: widget.user.imageUrl[imageIndex],
fit: BoxFit.cover,
useOldImageOnUrlChange: true,
placeholder: (context, url) => Center(
child: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation<Color>(
primaryColor.withOpacity(0.7),
),
),
),
errorWidget: (context, url, error) => Icon(
Icons.error_outline,
size: 30,
color: Colors.red,
),
),
);
},
itemCount: widget.user.imageUrl.length,
pagination: SwiperPagination(
alignment: Alignment.topCenter,
margin: EdgeInsets.all(0),
builder: DotSwiperPaginationBuilder(
color: Colors.white.withOpacity(0.7),
size: 8,
activeColor: widget.user.imageUrl.length > 1
? primaryColor
: Colors.transparent,
activeSize: 10,
),
),
control: widget.user.imageUrl.length > 1
? SwiperControl(
padding: const EdgeInsets.only(top: 250),
color: Colors.transparent,
disableColor: Colors.transparent,
size: 228,
)
: null,
loop: false,
),
),
This is how I call the BottomSheet:
ListTile(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (context) {
return ProfileInformationHomeScreen(
secondUser,
widget.currentUser,
);
},
),
it's DraggableScrollableSheet.
create a widget for bottomSheet.
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
child: DraggableScrollableSheet(
///* it will be always visible 95% of screen,
///* if we drag down at 50% it will close the sheet
initialChildSize: 0.95,
minChildSize: 0.5,
maxChildSize: .95,
expand: false,
builder: (BuildContext context, c) {
return Container(
color: Colors.white,
child: ListView(
controller: c,
children: [
/// your widgets
call a method to showModalBottomSheet.
_showBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => DestinationBottomSheetWidget(),
);
}
To close the buttomSheet you can drag or use a button inside DraggableScrollableSheet builder and use Navigator.of(context).pop().
I do like this and add item of ListView
/// heading
Padding(
padding: EdgeInsets.only(
left: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Icon(
Icons.close,
color: Colors.grey,
),
),
Text(
"Title",
textAlign: TextAlign.center,
),
///* this empty widget will handle the spaces
Icon(
Icons.close,
color: Colors.grey.withOpacity(0.0),
),
],
),
),
for more flutter doc youtube

Flutter custom bottom sheet

I have a ListView where I want to implement a nice way to delete list items using a bottom sheet with actions on. Initially I went down the path of simply calling showBottomSheet() in the onLongPress event handler for my list items, which would successfully open a bottom sheet with my action buttons on. However, this would automatically add a back button to the AppBar which is not what I want.
I then went down the route of trying out animations, such as SlideTransition and AnimatedPositioned:
class FoldersListWidget extends StatefulWidget {
#override
_FoldersListWidgetState createState() => _FoldersListWidgetState();
}
class _FoldersListWidgetState extends State<FoldersListWidget>
with SingleTickerProviderStateMixin {
double _bottomPosition = -70;
#override
Widget build(BuildContext context) {
return Stack(
children: [
FutureBuilder<List<FolderModel>>(
future: Provider.of<FoldersProvider>(context).getFolders(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
final folder = snapshot.data[i];
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
elevation: 1,
child: ListTile(
title: Text(folder.folderName),
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 50,
child: Consumer<FoldersProvider>(
builder:
(BuildContext context, value, Widget child) {
return value.deleteFolderMode
? CircularCheckBox(
value: false,
onChanged: (value) {},
)
: Icon(
Icons.folder,
color: Theme.of(context).accentColor,
);
},
),
),
],
),
subtitle: folder.numberOfLists != 1
? Text('${folder.numberOfLists} items')
: Text('${folder.numberOfLists} item'),
onTap: () {},
onLongPress: () {
Provider.of<FoldersProvider>(context, listen: false)
.toggleDeleteFolderMode(true); // removes fab from screen
setState(() {
_bottomPosition = 0;
});
},
),
);
},
);
},
),
AnimatedPositioned(
bottom: _bottomPosition,
duration: Duration(milliseconds: 100),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
child: Container(
height: 70,
width: MediaQuery.of(context).size.width,
color: Theme.of(context).colorScheme.surface,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: IconAboveTextButton(
icon: Icon(Icons.cancel),
text: 'Cancel',
textColour: Colors.black,
opacity: 0.65,
onTap: () => setState(() {
_bottomPosition = -70;
}),
),
),
VerticalDivider(
color: Colors.black26,
),
Expanded(
child: IconAboveTextButton(
icon: Icon(Icons.delete),
text: 'Delete',
textColour: Colors.black,
opacity: 0.65,
),
),
],
),
),
),
),
],
);
}
}
This slides the bottom Container on and off the screen but my issue is that it covers the last list item:
Could anyone suggest a better way of doing this or simply a way to adjust the height of the ListView so that when the Container slides up, the ListView also slides up.
Wrap ListView.builder inside a container and set its bottom padding as (70+16)
70 (height of bottom sheet), 16 (some default padding to make it look better if you like).
return Container(
padding: EdgetInset.ony(bottom: (70+16)),
child:ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
.....
.....