I was trying to build a UI for my application like this. But views of tabs are not visible. I've used tabs in many flutter applications but the UI has to exactly like below
Appbar with image as background
Half portion of user image in appbar section and rest below it
A tabbar below these.
.
.
.
My code here
class _MyHomePageState extends State<MyHomePage> with
TickerProviderStateMixin{
double screenSize;
double screenRatio;
AppBar appBar;
List<Tab> tabList = List();
TabController _tabController;
#override
void initState() {
tabList.add(new Tab(text:'Overview',));
tabList.add(new Tab(text:'Workouts',));
_tabController = new TabController(vsync: this, length:
tabList.length);
super.initState();
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size.width;
appBar = AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
);
return Container(
color: Colors.white,
child: Stack(
children: <Widget>[
new Container(
height: 300,
width: screenSize,
decoration:new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("images/app_image.jpg"),
fit: BoxFit.cover,
),
),
),
Scaffold(
backgroundColor: Colors.transparent,
appBar: appBar,
body:
Stack(
children: <Widget>[
new Positioned(
child: Column(
children: <Widget>[
Center(
child: Container(
child: CircleAvatar(
backgroundImage:
NetworkImage('http://res.cloudinary.com/'),
backgroundColor: Colors.green,
radius: 20,
),
),
),
SingleChildScrollView(
child: Container(
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('* * * * *',textAlign: TextAlign.center,style: TextStyle(fontSize: 18.0,color: Colors.pink),),
new Text('CAPTAIN',textAlign: TextAlign.center,style: TextStyle(fontSize: 18.0)),
],
crossAxisAlignment: CrossAxisAlignment.center,
),
),
),
],
),
width: screenSize,
top: 170,
),
new Positioned(
width: screenSize,
top: 310,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: new Column(
children: <Widget>[
new Container(
decoration: new BoxDecoration(color: Theme.of(context).primaryColor),
child: new TabBar(
controller: _tabController,
indicatorColor: Colors.pink,
indicatorSize: TabBarIndicatorSize.tab,
tabs: tabList
),
),
new Container(
height: 20.0,
child: new TabBarView(
controller: _tabController,
children: tabList.map((Tab tab){
_getPage(tab);
}).toList(),
),
)
],
),
),
)
],
),
),
],
),
);
}
Widget _getPage(Tab tab){
switch(tab.text){
case 'Overview': return OverView();
case 'Orders': return Workouts();
}
}
}
tabList.map((Tab tab){
_getPage(tab);
}).toList()
The piece above is from your provided code, you called _getPage(tab) in the map without a return statement. Simply make a slight change to this
tabList.map((Tab tab){
return _getPage(tab);
}).toList()
Or
tabList.map((Tab tab) => _getPage(tab)).toList()
children: tabList.map((Tab tab){
_getPage(tab);
}).toList(),
Some how this above your logic will getting null children for TabBarView, So views of tabs are not visible, need to check for it.
OtherWise you can assign children of TabBarView manualy
children: <Widget>[
OverView(),
Workouts(),
],
Related
I was trying to move the TabBar based on picture below. I wanted to move its position right under the piano picture in the middle. I am confused of which place should I put the TabBar. Here is my complete codes:
class MusicAmbient extends StatefulWidget {
const MusicAmbient({super.key});
#override
State<MusicAmbient> createState() => _MusicAmbientState();
}
class _MusicAmbientState extends State<MusicAmbient> with SingleTickerProviderStateMixin {
late final TabController controller = TabController(length: 2, vsync: this);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: controller,
tabs: const [
Tab(text: "Epic"),
Tab(text: "Relax"),
],
),
),
body: Container(
color: Colors.black,
child: SafeArea(
child: Container(
height: MediaQuery.of(context).size.height,
color: const Color.fromARGB(115, 55, 55, 55),
child: Stack(
children: [
//Piano Background & Tabs
Align(
alignment: Alignment.topLeft,
child: Wrap(
children: [
ImageButton(path: bgamb, callback: () => Get.back(), type: IconType.NONE),
Container(
height: MediaQuery.of(context).size.height,
color: const Color.fromARGB(115, 55, 55, 55),
child: TabBarView(
controller: controller,
children: [
MusicEpic(),
MusicRelax(),
],
),
),
],
),
),
],
),
),
),
),
);
}
}
Is there a way to achieve it correctly in Flutter? Any tips and tricks will be appreciated.
I want to put a widget onto other's view.
Here is what I did
In normal version without countdown timer, there is no whitespace inside the screen. It is %50 %50 divided by colours(red and blue).
What I want to do is adding that countdown timer without creating whitespace. Directly adding it onto those colours on the center.
I saw that with Stack it is possible to do. I tried it but couldn't remove the white area.
Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Column(
children: [
Expanded(
flex: 40,
child: new Container(
width: double.infinity,
child: new Column(
children: <Widget>[
box1 = new Expanded(
flex: boxSize1,
child: InkWell(
onTap: () {
clickBox1();
}, // Handle your callback
child: new Container(
alignment: Alignment.topCenter,
color: colorRandom,
),
),
),
TimeCircularCountdown(
unit: CountdownUnit.second,
countdownTotal: 3,
onUpdated: (unit, remainingTime) => print('Updated'),
onFinished: () {
setState(() {
visibility = false;
});
},
),
box2 = new Expanded(
flex: boxSize2,
child: InkWell(
onTap: () {
clickBox2();
}, // Handle your callback
child: new Container(
alignment: Alignment.topCenter,
color: color,
),
),
),
],
),
),
),
],
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Column(
children: [
Expanded(
child: Container(
color: Colors.blue,
)),
Expanded(
child: Container(
color: Colors.red,
)),
],
),
Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Colors.white,
),
// use your countdown timer widget in child
),
)
],
),
);
}
What I want to do is make a TextField stay in the same position by scrolling down the screen. I want to know if there is a way to do this?
This is the TextField that I want to be floating:
This is the code, the CardWidget are just cards and searchInput is the textField:
class RouteListPage extends StatefulWidget {
#override
_RouteListPageState createState() => _RouteListPageState();
}
class _RouteListPageState extends State<RouteListPage> {
TextEditingController searchController = new TextEditingController();
#override
Widget build(BuildContext context) {
final _screenSize = MediaQuery.of(context).size;
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
searchInput(),
CardWidget(),
CardWidget(),
CardWidget(),
CardWidget(),
SizedBox(height: 25.0)
],
),
),
);
}
Widget searchInput(){
return Container(
margin: EdgeInsets.symmetric(horizontal: 24, vertical: 25.0),
padding: EdgeInsets.symmetric(horizontal: 24),
decoration: BoxDecoration(
color: Color(0xfff6f6f6),
borderRadius: BorderRadius.circular(30),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black45,
offset: Offset(0.0, 2.0),
blurRadius: 10.0,
),
],
),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Buscar rutas",
hintStyle: TextStyle(fontFamily: "WorkSansSemiBold", fontSize: 16.0),
border: InputBorder.none
),
)
),
InkWell(
onTap: () {},
child: Container(
child: Icon(Icons.search, color: Tema.Colors.loginGradientEnd, size: 28.0)
)
)
],
),
);
}
}
You can use a Stack widget and have the scrolling widget below the TextField widget. Use the Positioned widget to control the position of searchInput()
Your build method will change to this:
#override
Widget build(BuildContext context) {
final _screenSize = MediaQuery.of(context).size;
return Scaffold(
body: Stack(
children: <Widget>[
SingleChildScrollView(
child: Column(
children: <Widget>[
CardWidget(),
CardWidget(),
CardWidget(),
CardWidget(),
SizedBox(height: 25.0)
],
),
),
Positioned(
top: 24.0,
left: 0.0,
right: 0.0,
child: searchInput(),
)
],
),
);
}
Instead of SingleChildScrollView try using this
Stack(
children: <Widget>[
searchInput(),
ListView(
children: <Widget>[
CardWidget(),
CardWidget(),
CardWidget()
],
)
],
),
Use a Stack and add your scrollview and the input as children:
Stack(
children: [
SingleChildScrollView(),
searchInput(),
],
)
I'm creating a UI with 5 buttons. One of them should be center and its width should be 50% of the screen. The height should be the same size (it should be a circle). I tried with MediaQuery.of(context).size.width but it doesn't work.
This is the closest I got:
The code is:
Widget _playButton() {
return FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 0.5, // I know this is wrong
child: Container(
alignment: new FractionalOffset(0.0, 0.0),
color: Colors.red,
/*decoration: new BoxDecoration(
color: hexToColor('#E8532E'),
shape: BoxShape.circle,
),*/
child: Center(
child: Text(
"PLAY",
style: TextStyle(fontSize: 20.0, color: Colors.white),
),
),
),
);
}
The container where I have this button:
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
body: new Stack(
alignment: AlignmentDirectional.center,
children: <Widget>[_myScreenOptions(), _playButton()],
),
),
);
}
Obviously, the rest of the buttons should be clickable.
If you wanna create a circular button, you don't have to worry about width & height, giving only one size is enough... or you can use FractionallySizedBox, as you already did.
Code output:
Sample code:
import 'package:flutter/material.dart';
class SampleCenterButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
_myScreenOptions(),
_playButton(),
],
),
),
);
}
_playButton() {
return GestureDetector(
onTap: () {
print("Play game");
},
child: FractionallySizedBox(
widthFactor: 0.5,
child: Container(
// defining one dimension works as well, as Flutter knows how to render a circle.
// width: MediaQuery.of(context).size.width/2,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(
child: Text(
"PLAY",
style: TextStyle(fontSize: 30, color: Colors.white),
),
),
),
),
);
}
_myScreenOptions() {
return Column(
children: <Widget>[
buildRow([
buildOption(Color(0xff1D4554), Icons.person, "Teams"),
buildOption(Color(0xff229B8D), Icons.folder_open, "Pets"),
]),
buildRow([
buildOption(Color(0xffE7C16A), Icons.videogame_asset, "Modes"),
buildOption(Color(0xffF2A061), Icons.settings, "Options"),
]),
],
);
}
Widget buildOption(Color bgColor, IconData iconData, String title) {
return Expanded(
child: Container(
color: bgColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
iconData,
size: 80,
),
Text(
title,
style: TextStyle(fontSize: 30),
),
],
),
),
);
}
buildRow(List<Widget> buttons) {
return Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: buttons,
),
);
}
}
I'm trying to make a profile page, where the users info is at the top. And then have a tab view below that for different views.
This is the code I'm using at the moment, when I take the TabBarView out it doesn't through an error, and if I wrap the TabBarView in an Expanded the error RenderFlex children have non-zero flex but incoming height constraints are unbounded. comes up.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(''),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
CircleAvatar(
minRadius: 45.0,
backgroundImage: NetworkImage(
'https://www.ienglishstatus.com/wp-content/uploads/2018/04/Anonymous-Whatsapp-profile-picture.jpg'),
),
Padding(
padding: EdgeInsets.only(left: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Testing Name',
style: TextStyle(
fontSize: 22.0,
color: Colors.grey.shade800,
),
),
Text(
'#testing_username',
style: TextStyle(
fontSize: 13.0,
color: Colors.grey.shade800,
),
),
],
),
),
],
),
),
DefaultTabController(
length: 3,
child: Column(
children: <Widget>[
TabBar(
tabs: <Widget>[
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
],
),
TabBarView(
children: <Widget>[
Container(
color: Colors.grey,
),
Container(
color: Colors.green,
),
Container(
color: Colors.purple,
),
],
),
],
),
)
],
),
);
}
I did try a variation of this but couldn't get it to work.
The error description is clear, the TabBarView doesn't have a bounded height. the parent widget also doesn't have a bounded height. So, the Expanded widget will not solve this issue.
EDIT: below solutions are for above question(with columns).In general cases, use a ListView with shrinkWrap: true.(Or any other widgets with shrinkWrap) As #Konstantin Kozirev mentioned correctly, the shrinkWrap causes some performance issues. look for a better updated solution.
There are some options:
1st Solution:
Wrap the parent widget(Column) with a limited height widget like SizedBox or AspectRatio. Then use the Expanded widget like this:
Expanded(
child: TabBarView(...),
)
2nd Solution:
Use a bounded widget like SizedBox or AspectRatio on the TabBarView itself:
SizedBox(
height: 300.0,
child: TabBarView(...),
)
Note Your can also calcuate the height dynamicly if the height is not static.
I solved it by adding TabBar inside Container and TabBarView inside Expanded:
DefaultTabController(
length: 3,
child: Column(
children: <Widget>[
Container(child: TabBar(..)),
Expanded(child: TabBarView(..)),
],
),
);
try to use IndexedStack instead of TabBarView
i tried Expanded, shrinkWrap = true , ...
but no one work's fine
just try example.
Example:
class Product extends StatefulWidget {
#override
_ProductState createState() => _ProductState();
}
class _ProductState extends State<Product> with SingleTickerProviderStateMixin {
TabController tabController;
int selectedIndex = 0;
#override
void initState() {
super.initState();
tabController = TabController(length: 5, vsync: this, initialIndex: 0);
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
initialIndex: 0,
child: Scaffold(
body: ListView(
shrinkWrap: true,
children: [
TabBar(
tabs: <Widget>[
Tab(
text: 'one',
),
Tab(
text: 'two',
),
Tab(
text: 'three',
),
],
controller: tabController,
onTap: (index) {
setState(() {
selectedIndex = index;
tabController.animateTo(index);
});
},
),
IndexedStack(
children: <Widget>[
Visibility(
child: Text('test1'),
maintainState: true,
visible: selectedIndex == 0,
),
Visibility(
child: Text('test2'),
maintainState: true,
visible: selectedIndex == 1,
),
Visibility(
child: Text('test3'),
maintainState: true,
visible: selectedIndex == 2,
),
],
index: selectedIndex,
),
],
),
),
);
}
}
special thank's to #arbalest
based on #Yamin answer I used SizeBox Like below to get full page
SizedBox.expand(
child: TabBarView(),
)
or any other size :
SizedBox(
height: height:MediaQuery.of(context).size.height // or every other size ,
child: TabBarView(),
)
The error message in console mentions this: "Viewports expand in the cross axis to fill their container and constrain their children to match their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of vertical space in which to expand".
Clearly, the horizontal viewport here is referring to the TabBarView widget which is not given a height constraint.
So wrap both the TabBar and TabBarView widgets in Expanded widgets and give appropriate flex values to them to let them share their parent's height.
Concretely,
DefaultTabController(
length: 3,
child: Column(
children: <Widget>[
Expanded(
flex: 1,
child: TabBar(
tabs: <Widget>[
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
Tab(
icon: Padding(
padding: EdgeInsets.all(6.0),
child: Image.asset(
"assets/images/icons/butterlike.png",
color: Colors.grey.shade800,
),
),
),
],
),
),
Expanded(
flex: 9,
child: TabBarView(
children: <Widget>[
Container(
color: Colors.grey,
),
Container(
color: Colors.green,
),
Container(
color: Colors.purple,
),
],
),
)
],
),
)