How to make a top tab bar with CupertinoSliverNavigationBar Flutter - flutter

I use CupertinoSliverNavigationBar, how can I add a tab bar below the title that is fixed to scroll?
My current code :
class SearchView extends StatefulWidget {
#override
_SearchViewState createState() => _SearchViewState();
}
class _SearchViewState extends State<SearchView> {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
CupertinoSliverNavigationBar(
backgroundColor: Colors.white,
border: Border.all(width: 0.0, color: const Color(0xFFFFFFFF)),
leading: Material(
child: GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Icon(
IconData(
0xe904,
fontFamily: 'icomoon',
),
color: Colors.black,
size: 25.0,
),
),
),
largeTitle: Text('Discover'),
)
];
},
body: Scaffold(
backgroundColor: Colors.white,
body: Container(),
),
),
);
}
}
Like on the attached picture :
Of course, if there is a solution that works without the Cupertino widgets, but that still respects the design, I'm interested.

You can use NeverScrollableScrollPhysics to ensure that the height of the CupertinoSliverNavigationBar remains fixed:
CupertinoPageScaffold(
child: CustomScrollView(
physics: const NeverScrollableScrollPhysics(), // add
slivers: [
CupertinoSliverNavigationBar(
middle: Text(
testNumber,
style: const TextStyle(
color: CupertinoColors.systemPink
),
),
largeTitle: const CircleAvatar(
backgroundColor: CupertinoColors.systemGreen,
child: Text("1"),
),
),
SliverFillRemaining(
child: PageView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
)
],
)
);

Related

Reduce space between Tabbar and Listtile

I want to reduce the space between Tabbar and listtile. I wrote them in two different files so i'll add both the codes. tried adding padding but no use.
main.dart
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.system,
home: DefaultTabController(
length: 4,
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverAppBar(
pinned: true,
floating: true,
systemOverlayStyle: SystemUiOverlayStyle.dark,
title: const Text(
"WhatsApp",
style: TextStyle(letterSpacing: 1.0),
),
backgroundColor: colour,
actions: [
MaterialButton(
minWidth: 1.0,
onPressed: () {},
child: const Icon(
Icons.search,
color: Colors.white,
)),
MaterialButton(
minWidth: 1.0,
onPressed: () {},
child: const Icon(
Icons.more_vert,
color: Colors.white,
))
],
bottom: const TabBar(
dragStartBehavior: DragStartBehavior.start,
indicatorColor: Colors.white,
tabs: [
Tab(
iconMargin: EdgeInsets.only(left: 1.0, right: 1.0),
icon: Icon(Icons.photo_camera),
),
Tab(child: Text("CHATS")),
Tab(child: Text("STATUS")),
Tab(child: Text("CALLS"))
]))
],
body: const TabBarView(
dragStartBehavior: DragStartBehavior.start,
children: [Camera(), Chats(), Status(), Calls()]),
),
));
}
}
chats.dart
class _ChatsState extends State<Chats> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 1.0),
child: ListView.separated(
itemBuilder: (context, index) => ListTile(
title: Text("Person $index"),
subtitle: Text("your message is this"),
trailing: Text("$hr:$mi $ti"),
leading: MaterialButton(
padding: EdgeInsets.all(1.0),
height: 1.0,
minWidth: 1.0,
elevation: 0,
onPressed: () {},
shape: CircleBorder(),
child: CircleAvatar(
radius: 25.0,
backgroundImage: AssetImage('assets/images/images.jfif'),
),
),
),
separatorBuilder: (context, index) {
return Divider();
},
itemCount: 50),
),
floatingActionButton: FloatingActionButton(
backgroundColor: colour,
onPressed: () {},
child: Icon(Icons.chat_rounded),
),
);
}
}
try padding: EdgeInsets.zero inside ListView.separated, not inside ListTile

Wrap ListView.separated filter chips in Flutter

I'm making a filter screen that uses Filter Chips, I'm trying to Wrap these Chips in multiple lines to avoid clipping/horizontal scrolling but I was unable to achieve that. I tried to put the Wrap() class in the return but they just pile on top of each other instead of being distributed evenly.
This is my current code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Screen1 extends StatefulWidget {
#override
_Screen1State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
var data = ['Chip 1', 'Chip 2', 'Chip 3', 'Chip 4', 'Chip 5'];
var selected = [];
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black87,
),
leading: IconButton(
icon: Icon(Icons.close),
),
centerTitle: true,
title: Text(
'Screen',
style: TextStyle(
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
backgroundColor: Colors.green,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Row(
children: <Widget>[
Text(
"Label 1",
),
],
),
),
SizedBox(height: size.height * 0.02),
Container(
height: size.height * 0.05,
child: ListView.separated(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: data.length,
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
width: size.width * 0.03,
);
},
itemBuilder: (BuildContext context, int index) => FilterChip(
padding: EdgeInsets.all(10),
label: Text(
data[index],
style: TextStyle(fontSize: 20),
),
onSelected: (bool value) {
if (selected.contains(index)) {
selected.remove(index);
} else {
selected.add(index);
}
setState(() {});
},
selected: selected.contains(index),
selectedColor: Colors.deepOrange,
labelStyle: TextStyle(
color: Colors.white,
),
backgroundColor: Colors.green,
),
),
),
],
),
),
);
}
}
This is my current screen
This is the desired result
you need to use the widget Wrap for filter Chip....
look at the tutorial
the wrap widget tutorial

Adding an Icon to a List using a button and actively updating UI using Provider state management

I want to add an Icon to a List following UI update using flutter Provider state Management.
I was successful to add an Icon using the floating button and confirm the result by printing the new List length. This ensures the addition of an Icon to a List but it does not update the UI for the new added Icon. Snippets are below
#override
_MedicalCosmeticsDetailsPageState createState() =>
_MedicalCosmeticsDetailsPageState();
}
class _MedicalCosmeticsDetailsPageState
extends State<MedicalCosmeticsDetailsPage> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return ChangeNotifierProvider<GridIcons>(
create: (context) => GridIcons(),
child: SafeArea(
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
iconTheme: IconThemeData(color: Colors.purple),
title: Text(
'xyz',
style: TextStyle(color: Colors.purple),
),
backgroundColor: Colors.transparent,
elevation: size.width * 0.05,
actions: [
Padding(
padding: EdgeInsets.only(right: size.width * 0.01),
child: IconButton(
icon: Icon(
Icons.search,
),
onPressed: () {},
),
),
],
),
body: GridViewPage(),
floatingActionButton: Consumer<GridIcons>(
builder: (context, myIcons, _) {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
print(myIcons.iconList.length);
myIcons.addIcon();
},
);
},
),
),
),
);
}
}
```//floating button for adding an ICON
```class GridIcons with ChangeNotifier {
List<IconData> iconList = [
Icons.ac_unit,
Icons.search,
Icons.arrow_back,
Icons.hdr_on_sharp,
];
addIcon<IconData>() {
iconList.add(Icons.sentiment_dissatisfied);
notifyListeners();
}
getIconList<IconData>() {
return iconList;
}
}
```//Function for icon addition
class GridViewPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
List _iconList = GridIcons().getIconList();
return ChangeNotifierProvider<GridIcons>(
create: (context) => GridIcons(),
child: Consumer<GridIcons>(
builder: (context, myIcon, child) {
return GridView.builder(
itemCount: _iconList.length,
padding: EdgeInsets.all(8.0),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250.0),
itemBuilder: (BuildContext context, int index) {
print('_buildGridViewBuilder $index');
return Card(
color: Colors.purple.shade300,
margin: EdgeInsets.all(8.0),
child: InkWell(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
_iconList[index],
size: 48.0,
color: Colors.purple.shade100,
),
Divider(),
Text(
'Index $index',
textAlign: TextAlign.center,
style: GoogleFonts.dmSans(
fontSize: 16,
color: Colors.white,
),
),
],
),
onTap: () {
print('Row: $index');
},
),
);
},
);
},
),
);
}
}
The icon doesn't appear in the UI although an icon is added to the Icon List.
You can copy paste run full code below
Step 1: In GridViewPage, you do not need ChangeNotifierProvider
Step 2: remove List _iconList = GridIcons().getIconList();
Step 3: use myIcon.iconList.length and myIcon.iconList[index]
code snippet
class GridViewPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
//List _iconList = GridIcons().getIconList();
return Consumer<GridIcons>(
builder: (context, myIcon, child) {
return GridView.builder(
itemCount: myIcon.iconList.length,
...
Icon(
myIcon.iconList[index],
size: 48.0,
working demo
full code
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
class MedicalCosmeticsDetailsPage extends StatefulWidget {
#override
_MedicalCosmeticsDetailsPageState createState() =>
_MedicalCosmeticsDetailsPageState();
}
class _MedicalCosmeticsDetailsPageState
extends State<MedicalCosmeticsDetailsPage> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return ChangeNotifierProvider<GridIcons>(
create: (context) => GridIcons(),
child: SafeArea(
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
iconTheme: IconThemeData(color: Colors.purple),
title: Text(
'xyz',
style: TextStyle(color: Colors.purple),
),
backgroundColor: Colors.transparent,
elevation: size.width * 0.05,
actions: [
Padding(
padding: EdgeInsets.only(right: size.width * 0.01),
child: IconButton(
icon: Icon(
Icons.search,
),
onPressed: () {},
),
),
],
),
body: GridViewPage(),
floatingActionButton: Consumer<GridIcons>(
builder: (context, myIcons, _) {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
print(myIcons.iconList.length);
myIcons.addIcon();
},
);
},
),
),
),
);
}
}
class GridIcons with ChangeNotifier {
List<IconData> iconList = [
Icons.ac_unit,
Icons.search,
Icons.arrow_back,
Icons.hdr_on_sharp,
];
addIcon<IconData>() {
iconList.add(Icons.sentiment_dissatisfied);
notifyListeners();
}
getIconList<IconData>() {
return iconList;
}
}
class GridViewPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
//List _iconList = GridIcons().getIconList();
return Consumer<GridIcons>(
builder: (context, myIcon, child) {
return GridView.builder(
itemCount: myIcon.iconList.length,
padding: EdgeInsets.all(8.0),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250.0),
itemBuilder: (BuildContext context, int index) {
print('_buildGridViewBuilder $index');
return Card(
color: Colors.purple.shade300,
margin: EdgeInsets.all(8.0),
child: InkWell(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
myIcon.iconList[index],
size: 48.0,
color: Colors.purple.shade100,
),
Divider(),
Text(
'Index $index',
textAlign: TextAlign.center,
style: GoogleFonts.dmSans(
fontSize: 16,
color: Colors.white,
),
),
],
),
onTap: () {
print('Row: $index');
},
),
);
},
);
},
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MedicalCosmeticsDetailsPage());
}
}

I want to generate card by onPressed method in my flutter app . Can anyone show me a roadmap for that...?

I have made the listview.builder in my page. In that i have designed my card . Now i want to generate card in the Listveiw.buider one by one by clicking a onpressed method in a floating action button. Which method/function should i write in that onpressed ? and how to generate card in that and what should i change in itemCount and itemBuilder. I need that roadmap. Thanks.
ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Dismissible(
key:Key(null),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {},
confirmDismiss: (direction) {
return showDialog(
context: context, builder: (_) => DeleteCard());
},
background: Container(
color: Colors.red,
padding: EdgeInsets.only(left: 16),
child: Icon(
Icons.delete,
color: Colors.white,
),
alignment: Alignment.centerLeft,
),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
color: Colors.white70,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 120,
padding: EdgeInsets.all(10.0),
child: Text(
"Project ",
style: TextStyle(
fontSize: 11, fontWeight: FontWeight.bold),
),
),
Container(
padding: EdgeInsets.all(10.0),
child: ProjectName(),
),
],
),
// item add start
Container(
padding: EdgeInsets.all(10.0),
child: TextFormField(
decoration: InputDecoration(
hintText: "Item name" ,hintStyle: TextStyle(fontSize: 12),
),
),
),
Container(
padding: EdgeInsets.all(10.0),
child: TextFormField(
decoration: InputDecoration(
hintText: "Amount",hintStyle: TextStyle(fontSize: 12),
),
keyboardType: TextInputType.number,
),
),
],
),
),
);
}
),
This is something you are looking for I think. Just replace the ListTile with your own Card
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var listLength = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter App :)"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
listLength++;
});
}),
body: Container(
child: ListView.builder(
itemCount: listLength,
itemBuilder: (context, index) {
return ListTile(
leading: Text("$index"),
title: Text("List Tile as Widget"),
);
})),
);
}
}
I have solved it by using a var which initial value in 0 then make a function in set state and increment the variable. Then I called the function in my floating action button and in listview.builder item count I set the var name. I hope it will help others it's a easy solution to generate card by using onpressed.

How to remove bottom from default tab bar

I need to add a tab bar without an app bar and I got a solution from StackOverflow to use flexible space and it is working but it makes additional unwanted space in tab bar bottomHow to remove this or hide this?
My full code
import 'package:flutter/material.dart';
class TemplesListingWithTabMode extends StatefulWidget {
TemplesListingWithTabMode({Key key}) : super(key: key);
#override
_TemplesListingWithTabModeState createState() =>
_TemplesListingWithTabModeState();
}
class _TemplesListingWithTabModeState extends State<TemplesListingWithTabMode> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height-kToolbarHeight-kMaterialListPadding.top-kTabLabelPadding.top,
child: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
flexibleSpace: TabBar(
indicatorColor: Colors.pink,
tabs: [
Tab(
child: Text("ALL",style: TextStyle(color: Colors.pink),),
),Tab(
child: Text("Favorites",style: TextStyle(color: Colors.pink),),
)
]),
),
body : Container(
color: Colors.grey,
child: TabBarView(
children: [
ListView.builder(
itemCount: 100,
itemBuilder: (context,index){
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
}),
ListView.builder(
itemCount: 5,
itemBuilder: (context,index){
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
})
]),
),
),
),
)
],
);
}
}
The solution provided by #Darshan is not solved my issue and the solution is
Wrap TabBar in SafeArea widget.
and the result is
How to remove this small bottom from appbar?
The reason is AppBar have its size + status bar size. There are multiple ways fix this. As other answer mentioned, simple way is to add SafeArea.
And note that even after you will get ugly little space under two tabs.
To solve that you can use PreferredSize (there are other ways for this also).
Code for the above screenshot:
class _TemplesListingWithTabModeState extends State<TemplesListingWithTabMode> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size(double.infinity, 60),
child: TabBar(
indicatorColor: Colors.pink,
tabs: [
Tab(
child: Text("ALL",style: TextStyle(color: Colors.pink),),
),Tab(
child: Text("Favorites",style: TextStyle(color: Colors.pink),),
)
]),
),
body : Container(
color: Colors.grey,
child: TabBarView(
children: [
ListView.builder(
itemCount: 100,
itemBuilder: (context,index){
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
}),
ListView.builder(
itemCount: 5,
itemBuilder: (context,index){
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
})
]),
),
),
),
);
}
}
By default, ListView acts as if SafeArea is turned on.
Setting the padding to zero will remove that white space.
ListView(
padding: EdgeInsets.zero;
...
);
Discussion on ListView and the default SafeArea
Wrap TabBar in SafeArea widget. It adds the necessary padding to the child widget which in your case, minimizes the space you are seeing. Working code below:
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
flexibleSpace: SafeArea(
child: TabBar(
indicatorColor: Colors.pink,
tabs: [
Tab(
child: Text("ALL",style: TextStyle(color: Colors.pink),),
),Tab(
child: Text("Favorites",style: TextStyle(color: Colors.pink),),
)
]),)
),
Hope this answers your question.
You can create your appbar by extending AppBar
class MyAppBar extends AppBar {
MyAppBar({PreferredSizeWidget child, Color backgroundColor})
: super(bottom: child, backgroundColor: backgroundColor);
#override
Size get preferredSize => bottom.preferredSize;
}
class TemplesListingWithTabMode extends StatefulWidget {
TemplesListingWithTabMode({Key key}) : super(key: key);
#override
_TemplesListingWithTabModeState createState() =>
_TemplesListingWithTabModeState();
}
class _TemplesListingWithTabModeState extends State<TemplesListingWithTabMode> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: MyAppBar(
backgroundColor: Colors.white,
child: TabBar(indicatorColor: Colors.pink, tabs: [
Tab(
child: Text(
"ALL",
style: TextStyle(color: Colors.pink),
),
),
Tab(
child: Text(
"Favorites",
style: TextStyle(color: Colors.pink),
),
)
]),
),
body: Container(
color: Colors.grey,
child: TabBarView(children: [
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
}),
ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("i am $index"),
),
),
);
})
]),
),
),
);
}
}
import 'package:bubble_tab_indicator/bubble_tab_indicator.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class AppBarrTest extends StatefulWidget {
#override
_AppBarrTestState createState() => _AppBarrTestState();
}
class _AppBarrTestState extends State<AppBarrTest>with SingleTickerProviderStateMixin {
int index = 0;
TabController _controller;
#override
void initState() {
_controller = new TabController(length: 2, vsync: this);
_controller.addListener(() {
setState(() {});
});
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
flexibleSpace: fun_Appbar(),
bottom: PreferredSize(
preferredSize: Size.fromHeight(50),
child: Column(
children: <Widget>[
Card(
shape: Border.all(color: Colors.blue),
color: Colors.white,
child: fun_tabBar(20),
),
],
),
),
),
),
);
}
fun_Appbar(){
double h = MediaQuery.of(context).size.height;
return Container(
height: 50,
child: Center(
child: Text(
"Messages",
style: TextStyle(
fontSize: 22,
color: Colors.white,
letterSpacing: 2.0,
fontFamily: 'Nunito',
),
),
),
);
}
fun_tabBar(double fontSize){
return TabBar(
controller: _controller,
//indicatorWeight: 20,
indicatorSize: TabBarIndicatorSize.label,
labelPadding: EdgeInsets.only(left: 0, right: 0),
dragStartBehavior: DragStartBehavior.start,
unselectedLabelColor: Colors.black,
indicatorColor: Colors.red,
indicator: new BubbleTabIndicator(
indicatorHeight: 40.0,
indicatorColor: Color(0xFF343193),
//padding: EdgeInsets.all(20),
tabBarIndicatorSize: TabBarIndicatorSize.tab,
indicatorRadius: 30,
),
tabs: <Widget>[
Tab(
child: Container(
alignment: Alignment.center,
child: Text(
"Inbox",
style: TextStyle(
fontFamily: 'Nunito',
fontSize: fontSize,
),
),
),
),
Tab(
child: Container(
alignment: Alignment.center,
child: Text(
"Sent",
style: TextStyle(
fontFamily: 'Nunito',
fontSize: fontSize,
),
),
),
),
],
);
}
}
bubble_tab_indicator: "^0.1.4"
or Just wrap your flexible space with SizeBox and set height
flexibleSpace: SizedBox(
height: 100,
child: TabBar(
indicatorColor: Colors.pink,
tabs: [
Tab(
child: Text("ALL",style: TextStyle(color: Colors.pink),),
),Tab(
child: Text("Favorites",style: TextStyle(color: Colors.pink),),
)
]),
),