How to change tab programmatically on BottomAppBar flutter? - flutter

I am working on a flutter application where I need to change my tab programmatically, here If I came on the last screen of the stack then I need to redirect to the first tab programmatically instead of closing the app.
Please consider the following code snnipet:
final PageStorageBucket bucket = PageStorageBucket();
Widget currentScreen = HomeFragment();
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFF3F5F9),
body: PageStorage(
child: currentScreen,
bucket: bucket,
),
bottomNavigationBar: BottomAppBar(
shape: CircularNotchedRectangle(),
child: Container(
width: double.infinity,
height: 15.5,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
currentScreen = HomeFragment();
currentTab = 0;
});
},
child: Expanded(
child: Container(
height: 15.5,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/home.png',
color: currentTab == 0 ? Color(0xFF193F70) : Color(0xFFABAAAA),
),
SizedBox(
height: 3.0,
),
Text(
'Home',
),
],
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
redirectToLogin();
});
},
child: Expanded(
child: Container(
height: 15.5,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/login_icon.png',
color: currentTab == 1 ? Color(0xFF193F70) : Color(0xFFABAAAA),
),
SizedBox(
height: 3.0,
),
Text(
'Login',
),
],
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
redirectToSignUp();
});
},
child: Expanded(
child: Container(
height: 15.5,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/signup_icon.png',
color: currentTab == 2 ? Color(0xFF193F70) : Color(0xFFABAAAA),
),
SizedBox(
height: 3.0,
),
Text(
'SignUp',
),
],
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
currentScreen = ProfileFrag();
currentTab = 3;
});
},
child: Expanded(
child: Container(
height: 15.5,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/menu_icon.png',
color: currentTab == 3 ? Color(0xFF193F70) : Color(0xFFABAAAA),
),
SizedBox(
height: 3.0,
),
Text(
'Menu',
),
],
),
),
),
),
],
),
),
),
);}
Here I am looking for something that can redirect to a different tab programmatically. Also please let me know if I am doing something wrong here.

I believe it would be better to use a real Flutter TabBar. Have you considered this solution?
There is a complete tutorial on this blog : https://blog.logrocket.com/flutter-tabbar-a-complete-tutorial-with-examples/
It includes a way to change tabs programmatically. This is actually what I am trying to do with my own app.
Let me know if this could work for you.

Related

Flutter - how to position the background to the bottom with stack

I'm a beginner at app dev and I'm trying out flutter. I'm currently having a problem with positioning my background on the project that I am currently testing out.I'm following a UI kit that I am trying to copy for the purpose of practicing, but I am having problem with the UI.
I tried using stack but the whole screen is wrapped with its children and not taking up space. it looks like this:
and this is what I wanted to do:
This is the background that I wanted to put in my app, it is not literally a background or wallpaper because of its size. I just needed this to be placed at the bottom of the screen or background:
this is the code that I currently have:
import 'package:audit_finance_app/constant/theme.dart';
import 'package:audit_finance_app/widgets/widgets.dart';
import 'package:audit_finance_app/screens/homescreen.dart';
import 'package:flutter/material.dart';
import 'dart:math' as math;
class SignInPage extends StatefulWidget {
const SignInPage({super.key});
#override
State<SignInPage> createState() => _SignInPageState();
}
class _SignInPageState extends State<SignInPage> {
late List<String> inputPass;
String defaultPass = '1234';
#override
void initState() {
inputPass = [];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
const SizedBox(
width: double.maxFinite,
height: double.maxFinite,
child: Image(
image: AssetImage('assets/background.png'),
),
),
CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
AuditTheme.primaryColor,
AuditTheme.secondaryColor,
],
),
),
),
leadingWidth: 100,
leading: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row(
children: const [
Expanded(
child: ImageIcon(
AssetImage('assets/logo/white_logo.png'),
),
),
Text(
'Audit',
style: TextStyle(fontSize: 20),
),
],
),
),
title: const Text('Sign In'),
centerTitle: true,
actions: [
Transform(
alignment: Alignment.center,
transform: Matrix4.rotationY(math.pi),
child: IconButton(
onPressed: () {},
icon: const Icon(Icons.sort),
),
),
],
),
SliverList(
delegate: SliverChildListDelegate(
[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Widgets().sixedBoxHeight(50),
Column(
children: [
const CircleAvatar(
radius: 35,
backgroundImage:
AssetImage('assets/logo/audit_logo.png'),
),
Widgets().sixedBoxHeight(10),
const Text(
'Ledjoric Vermont',
style: TextStyle(fontSize: 20),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
pinIconTest(inputPass.isNotEmpty
? Colors.black
: Colors.grey),
pinIconTest(inputPass.length >= 2
? Colors.black
: Colors.grey),
pinIconTest(inputPass.length >= 3
? Colors.black
: Colors.grey),
pinIconTest(inputPass.length == 4
? Colors.black
: Colors.grey),
],
),
Card(
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
numPad(const Text('1'), () => inputPin('1')),
numPad(const Text('2'), () => inputPin('2')),
numPad(const Text('3'), () => inputPin('3')),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
numPad(const Text('4'), () => inputPin('4')),
numPad(const Text('5'), () => inputPin('5')),
numPad(const Text('6'), () => inputPin('6')),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
numPad(const Text('7'), () => inputPin('7')),
numPad(const Text('8'), () => inputPin('8')),
numPad(const Text('9'), () => inputPin('9')),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
const SizedBox(
width: 100,
height: 100,
),
numPad(const Text('0'), () => inputPin('0')),
numPad(
const Icon(Icons.backspace_sharp),
() => deletePin(),
),
],
),
],
),
),
],
),
],
),
),
],
),
],
),
);
}
Widget pinIconTest(Color color) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: Icon(
Icons.circle,
size: 35,
color: color,
),
);
}
Widget numPad(Widget widget, void Function() function) {
return SizedBox(
width: 100,
height: 100,
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.grey,
textStyle: const TextStyle(
fontSize: 30,
),
),
onPressed: function,
child: widget,
),
);
}
void inputPin(String value) {
setState(() {
inputPass.length != 4 ? inputPass.add(value) : null;
inputPass.length == 4 ? checkPass() : null;
});
print(inputPass);
}
void checkPass() {
var stringList = inputPass.join('');
if (stringList == defaultPass) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const HomeScreen(),
),
);
}
print(stringList);
}
void deletePin() {
setState(() {
inputPass.isNotEmpty ? inputPass.removeLast() : null;
});
print(inputPass);
}
}
I was missing the fact you want to place at the bottom that background, however to achieve that you can do it as the code below shows:
class SignInPage extends StatefulWidget {
const SignInPage({super.key});
#override
State<SignInPage> createState() => _SignInPageState();
}
class _SignInPageState extends State<SignInPage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
const Align(
alignment: Alignment.bottomCenter,
child: Image(
image: AssetImage('assets/background.png'),
),
),
//Other child here
],
),
);
}
}
And this is the result:
You can use the example below for the status bar. I don't know about the real problem.
You can try using this way for gradient color
SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
statusBarGradient: LinearGradient(
colors: [Colors.red, Colors.blue],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
);
You need to wrap your image in a Positioned Widget.
Positioned(bottom: 0.0,
child: const SizedBox(
width: double.maxFinite,
height: double.maxFinite,
child: Image(
image: AssetImage('assets/background.png'),
),
),
Or you can use the alignment property of the Stack to stick everything onto the bottom. I'm not sure this is exactly what you want though.
body: Stack(
alignment: Alignment.bottomCenter,
fit: StackFit.expand,
children: <Widget>[
const SizedBox(
width: double.maxFinite,
height: double.maxFinite,
child: Image(
image: AssetImage('assets/background.png'),
),
),

flutter AnimatedPositioned cause a Ui jank

I am using AnimatedPositioned to make animation.
Obx(() {
return AnimatedBuilder(
animation: controller.animationController,
builder: (context, child) =>
AnimatedPositioned(
duration: const Duration(milliseconds: 1000),
bottom: controller.actionsBottom,
child: child!,
),
child:
!controller.trloaded.value
? const SizedBox()
: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
GlobalButton(
title: controller.trLanding('signUp'),
type: ButtonType.outlinedPrimary,
width: 154.w,
height: 56,
onTap: () => controller.goToSignUp(),
),
SizedBox(width: 20.w),
GlobalButton(
borderWidth: 1,
borderColor: AppColors.primary[800]!,
title: controller.trLanding("signIn"),
width: 154.w,
height: 56,
onTap: () => controller.goToSignIn()),
],
),
Container(
margin: const EdgeInsets.only(top: 16, bottom: 16),
child: Row(
children: [
Text(
"By Signing up you agree with our ",
style: textTheme.bodyText2!.copyWith(
color: AppColors.neutral[400],
),
),
GestureDetector(
onTap: () {
// clearData();
push(TermsPage());
},
child: Text(
"Terms and Conditions",
style: textTheme.bodyText2!.copyWith(
color: AppColors.primary[700],
),
),
),
],
),
),
],
),
);
}),
When I run the app by profile mode I got these problems:
To fix that I am using Animation Builder and I added my widgets to its child but I have the above problem. How can I fix that?

track which container was clicked on in flutter

I have 3 containers and in each picture, when you click on which an icon appears. How to assign a value to each container, so that when you click it, you can change it too. Or how to track which container was clicked on
class _EditAccountScreenState extends State<EditAccountScreen> {
bool checkboxValue = false;
...
child: GestureDetector(
onTap: () {
setState(() {
checkboxValue = !checkboxValue;
});
},
child: Padding(
child: Row(
children: <Widget> [
Container(
child: Stack(
children: <Widget>[
Image.asset('assets/images/telegram-512.png',fit: BoxFit.fill),
Positioned(
bottom: 0, right: 15, //give the values according to your requirement
child: checkboxValue
? Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius:BorderRadius.circular(100)
),
child: Icon(
Icons.check,
color: Colors.white,
size: 15,
)
)
: Container(),),],),),
Container(
child: Stack(
children: <Widget>[
Image.asset('assets/images/Viber-Logo.png',fit: BoxFit.fill),
Positioned(
bottom: 0, right: 15, //give the values according to your requirement
child: checkboxValue
? Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius:BorderRadius.circular(100)
),
child: Icon(
Icons.check,
color: Colors.white,
size: 15,
)
)
: Container(),),],),),
Use Gesture Detector to detect Taps on containers.
Here is an example related to this:
Container(
alignment: FractionalOffset.center,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.lightbulb_outline,
color: _lights ? Colors.yellow.shade600 : Colors.black,
size: 60,
),
),
GestureDetector(
onTap: () {
setState(() {
_lights = true;
});
},
child: Container(
color: Colors.yellow.shade600,
padding: const EdgeInsets.all(8),
child: const Text('TURN LIGHTS ON'),
),
),
],
),
)
First of All Make a Integer Variable and then set its value to -1 by default
int selectedContainerIndex = -1;
Now, You Can Wrap each of your Container in seperate GestureDetector, and then on the onTap method you can set the selectedContainerIndex value of your container according to you.
See the below Code
Stack(
children: [
//First Container
GestureDetector(
onTap: () {
selectedContainerIndex = 0;
setState(() {});
},
child: new Container(),
),
//Second Container
GestureDetector(
onTap: () {
selectedContainerIndex = 1;
setState(() {});
},
child: new Container(),
),
//Third Container
GestureDetector(
onTap: () {
selectedContainerIndex = 2;
setState(() {});
},
child: new Container(),
),
],
),
Now To know which Container was tapped you can always use the selectedContainerIndex Value
print(selectedContainerIndex);
NOTE: If your containers are more in numbers say 4 or 5, then I would recommend you to use good practice and show those using some dynamic listview builder, instead of hardcoding them each.

Align Persistentfooterbutton of Scaffold to the right side

I want to display a List and beneath it a Persistent footer, a Column with some rows. I use persistentFooterButtons of Scaffold.
The closest to what I get is this:
But I am unable to align the fields to the right.
When I work with Align or Spacer, the Widgets disappear.
The content of persistentFooterButtons.
FittedBox(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.pushNamed(context, RouteName.BAUSTELLEN);
},
child: Align(
alignment: Alignment.bottomLeft,
child: Text('Bestellen'),
),
),
Row(
children: <Widget>[
Text('$priceInfo '),
MyFutureBuilder(
future: sum,
builder: (context, double sum) {
var mySum = formatDoubleNumber(sum);
return Text('$mySum');
},
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
Row(
children: <Widget>[
Text('Ihr Einkaufsrahmen '),
Text(
'$einkaufsrahmen',
style: TextStyle(
color: einkaufsrahmen == 0 ? Colors.red : Colors.black),
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
],
),
);
If I put the elements directly to persitentFooterButtons, this is what I get, the text is scattered around and my list is not shown.
and the Code
Scaffold(
body: WarenkorbListe(),
persistentFooterButtons: <Widget>[
// WarenkorbFooter(),
FlatButton(
onPressed: () {
Navigator.pushNamed(context, RouteName.BAUSTELLEN);
},
child: Align(
alignment: Alignment.bottomLeft,
child: Text('Bestellen'),
),
),
Row(
children: <Widget>[
Text('$priceInfo '),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
Row(
children: <Widget>[
Text('Ihr Einkaufsrahmen '),
Text(
'$einkaufsrahmen',
style: TextStyle(
color: einkaufsrahmen == 0 ? Colors.red : Colors.black),
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
],
);
Try to align with your column instead
FittedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end, // this
children: <Widget>[

How can I make the table take the available space along the height?

I have the following table
#override
Widget build(BuildContext context){
final TheGroupPageArguments arguments = ModalRoute.of(context).settings.arguments;
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: [
Flexible(
flex: 1,
child: Align(
alignment: Alignment.center,
child: DigitalSpeedMeter(),
),
),
Flexible(
flex: 6,
child: Table(
children: [
TableRow(children: [backButton(), backButton(), backButton()]),
TableRow(children: [backButton(), backButton(), backButton()]),
],
),
),
]
),
),
);
}
But it only takes half the screen height. How can I make it strecht to it's parent's height?
This is how it looks now
This is what it should look like
This is what it should look like
You can use the "Expanded" instead of "Flexible".
I can't find a good solution.
Anyone know a good way?
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Text(
'0\nMPH',
textAlign: TextAlign.center,
),
),
),
),
Expanded(
flex: 6,
child: Column(
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: FlatButton(
onPressed: () {},
color: Colors.tealAccent,
child: Text("button1"),
),
),
Expanded(
child: FlatButton(
onPressed: () {},
color: Colors.green,
child: Text("button2"),
),
),
],
),
),
Expanded(
child: Container(
color: Colors.grey,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: FlatButton(
onPressed: () {},
color: Colors.blue,
child: Text("button3"),
),
),
Expanded(
child: FlatButton(
onPressed: () {},
color: Colors.amber,
child: Text("button4"),
),
),
],
),
),
),
],
),
),
],
),
),
);
}
I found a solution. How about this?
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20.0),
child: Column(children: [
Flexible(
flex: 1,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Text(
'0\nMPH',
textAlign: TextAlign.center,
),
),
),
),
),
Flexible(
flex: 6,
child: Table(
children: [
TableRow(children: [backButton(), backButton(), backButton()]),
TableRow(children: [backButton(), backButton(), backButton()]),
],
),
),
]),
),
);
}
Widget backButton() {
return Container(
height: MediaQuery.of(context).size.height / 7 * 6 / 2 - 7,
child: FlatButton(
onPressed: () {},
color: Colors.tealAccent,
child: Text("button"),
),
);
}
I ended up doing the following. A widget that makes the rows and columns dynamically based on the the widgets put into it.
import 'package:flutter/material.dart';
class ExpandingGrid extends StatelessWidget {
final List<Widget> tiles;
final int columns;
const ExpandingGrid({this.tiles, this.columns});
int _rows(){
return (tiles.length / columns).ceil();
}
int _tileIndex(int row, int column) => row * columns + column;
Widget _gridTile(int row, int column){
if(_tileIndex(row, column) < tiles.length)
{
return Expanded(
child: tiles[_tileIndex(row, column)],
);
}
return Spacer();
}
#override
Widget build(BuildContext context) {
return Column(
children:
[
for(int r = 0; r < _rows(); r++ )
Expanded(
child: Row
(
children :
[
for(int c = 0; c < columns; c++)
_gridTile(r, c),
]
),
)
]
);
}
}