Flutter Animation - Card Flip without using pre defined packages - flutter

I'm trying to flip a card from front to back and back to front without using the dependencies, but could not implement. I have seen where people have used a pre defined Flip Card package but without the dependency I'm finding trouble. Please help me out.
I want the card to flip to back as soon as I click on the "Icon Button" and back as soon as I click "Go Back" Button. I tried the idea without using the animation and is working just fine, but how do I implement the flip animation is what I feel is difficult.
class NotificationItemCard extends StatefulWidget {
const NotificationItemCard({
Key? key,
}) : super(key: key);
#override
State<NotificationItemCard> createState() => _NotificationItemCardState();
}
class _NotificationItemCardState extends State<NotificationItemCard> {
late bool showCardFrontSide;
#override
void initState() {
showCardFrontSide = true;
super.initState();
}
void onChangeView() {
setState(() {
showCardFrontSide = !showCardFrontSide;
});
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
height: 140.h,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(8),
),
child: showCardFrontSide
? const NotificationCardFrontSide()
: NotificationCardBackSide(
onChangeView: onChangeView,
),
),
showCardFrontSide
? Align(
alignment: const Alignment(0.95, -1),
child: IconButton(
key: const ValueKey("IconButton"),
onPressed: onChangeView,
icon: const Icon(Icons.info_outline),
),
)
: const SizedBox.shrink()
],
);
}
}
class NotificationCardFrontSide extends StatelessWidget {
const NotificationCardFrontSide({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(
key: const ValueKey("FrontSideSizedBox"),
width: 126.w,
child: Center(
child: CircleAvatar(
radius: 50.r,
),
),
),
SizedBox(
key: const ValueKey("FrontSideSizedTextBox"),
width: 222.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox1"),
),
Text(
"Prediction Deadline",
// "Prediction Deadline - ${DateConverterUtil.convert(lobby.match.start)}",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox2"),
),
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox3"),
),
SizedBox(
key: const ValueKey("FrontSideSizedButtonBox"),
width: 150.w,
height: 45.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
key: const ValueKey("FrontSideButtonSizedBox"),
width: 70.w,
child: TextButton(
onPressed: () {},
child: Text(
"deny",
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
SizedBox(
width: 70.w,
child: TextButton(
onPressed: () {},
child: Text(
"deny",
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
],
),
),
],
),
),
],
);
}
}
class NotificationCardBackSide extends StatelessWidget {
final VoidCallback onChangeView;
const NotificationCardBackSide({
Key? key,
required this.onChangeView,
}) : super(key: key);
Widget getTeamLogo(String image) {
return CircleAvatar(
backgroundColor: const Color(0xFFD9D9D9),
radius: 30.r,
child: Image.network(
image,
errorBuilder: (context, error, stackTrace) {
return Text(
"Error",
style: Theme.of(context).textTheme.displayMedium?.copyWith(
color: Colors.red,
),
);
},
height: 65.h,
width: 65.w,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: Text(
"Loading...",
style: Theme.of(context).textTheme.displayMedium,
),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
height: 62.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
getTeamLogo(""),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.clip),
key: const ValueKey("BackSideSizedText1"),
),
Text(
"Prediction Deadline",
// "Prediction Deadline - ${DateConverterUtil.convert(lobby.match.start)}",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.clip),
key: const ValueKey("BackSideSizedText2"),
),
],
),
getTeamLogo(""),
],
),
),
SizedBox(
key: const ValueKey("BackSideButtonBox"),
height: 30.h,
width: 100.w,
child: OutlinedButton(
onPressed: onChangeView,
child: const Text("Go Back"),
key: const ValueKey("BackSideButtonText"),
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8.r,
),
),
),
),
),
)
],
);
}
}

You can implement this with AnimatedBuilder and Transform, Use example below:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: Scaffold(body: MyApp())));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
late AnimationController _controller;
Widget _front = Card1();
Widget _back = Card2();
late Widget _card = _front;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 600));
_controller.addListener(() {
if (_controller.value >= .5 && _card != _back) {
setState(() => _card = _back);
} else if (_controller.value < .5 && _card != _front) {
setState(() => _card = _front);
}
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: () {
if (_controller.value == 1)
_controller.reverse(from: 1);
else
_controller.forward(from: 0);
},
child: AnimatedBuilder(
animation: _controller,
builder: (c, anim) => Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.0025)
..rotateY(_controller.value * pi),
alignment: FractionalOffset.center,
child: _card,
),
),
),
);
}
}
class Card1 extends StatelessWidget {
const Card1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 150,
height: 300,
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Card1'),
Text('I\'m front of the card'),
],
),
);
}
}
class Card2 extends StatelessWidget {
const Card2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Transform.scale(
scaleX: -1,
child: Container(
width: 150,
height: 300,
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Card2'),
Text('I\'m back of the card'),
],
),
),
);
}
}
The result:
(Thanks to this answer for transform code)

Related

How to separate different widgets alongside another widget?

This is my problem:
I want to achieve this design:
How can I separate one to each other, first the homePageTimerUI and below the countDownTimer
?
This is my code:
homePageTimerUI.dart
class HomePageTimerUI extends StatefulWidget {
const HomePageTimerUI({Key? key}) : super(key: key);
#override
State<HomePageTimerUI> createState() => _HomePageTimerUIState();
}
class _HomePageTimerUIState extends State<HomePageTimerUI> {
#override
Widget build(BuildContext context) {
return SizedBox(
height: double.maxFinite,
width: double.infinity,
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
bottom: PreferredSize(
preferredSize: const Size.fromHeight(40),
child: Container(
color: Colors.transparent,
child: SafeArea(
child: Column(
children: <Widget>[
TabBar(
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
color: Color(0xff3B3B3B), width: 4.0),
insets:
EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 11.0)),
indicatorWeight: 15,
indicatorSize: TabBarIndicatorSize.label,
labelColor: const Color(0xff3B3B3B),
labelStyle: const TextStyle(
fontSize: 12,
letterSpacing: 1.3,
fontWeight: FontWeight.w500),
unselectedLabelColor: const Color(0xffD7D7D7),
tabs: const [
Tab(
text: "POMODORO",
icon: Icon(Icons.work_history, size: 40),
),
Tab(
text: "SHORT BREAK",
icon: Icon(Icons.ramen_dining, size: 40),
),
Tab(
text: "LONG BREAK",
icon: Icon(Icons.battery_charging_full_rounded,
size: 40),
),
])
],
),
),
),
),
),
body: TabBarView(
children: const <Widget>[
// Center(
// child: StartPomodoro(),
// ),
// Center(
// child: ShortBreak(),
// ),
// Center(child: LongBreak()),
],
),
),
),
);
}
}
countDownTimer.dart
class CountDownTimer extends StatefulWidget {
#override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer>
with TickerProviderStateMixin {
late AnimationController controller;
String get timerString {
Duration duration = controller.duration! * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return Scaffold(
backgroundColor: Colors.white10,
body: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.amber,
height:
controller.value * MediaQuery.of(context).size.height,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.center,
child: Stack(
children: <Widget>[
CustomPaint(
painter: CustomTimerPainter(
animation: controller,
backgroundColor: Colors.white,
color: themeData.indicatorColor,
)),
Align(
alignment: FractionalOffset.center,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Text(
timerString,
style: TextStyle(
fontSize: 112.0,
color: Colors.white),
),
],
),
),
],
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return FloatingActionButton.extended(
onPressed: () {
if (controller.isAnimating)
controller.stop();
else {
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
}
},
icon: Icon(controller.isAnimating
? Icons.pause
: Icons.play_arrow),
label: Text(
controller.isAnimating ? "Pause" : "Play"));
}),
],
),
],
),
),
],
);
}),
);
}
}
class CustomTimerPainter extends CustomPainter {
CustomTimerPainter({
required this.animation,
required this.backgroundColor,
required this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
#override
bool shouldRepaint(CustomTimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
This is my own attempt to solve the issue, but didn't work
class StackedPages extends StatelessWidget {
const StackedPages({super.key});
#override
Widget build(BuildContext context) {
return Column(
children: [
HomePageTimerUI(),
CountDownTimer(),
],
);
}
}
How can achieve this design?
Thank you for any help you can offer
Are you asking for Stack() widget?
You want to replace one for another?
You could use AnimatedSwitcher().
AnimatedSwitcher(
duration: const Duration(seconds: 1), child: MyWidget());
Where MyWidget() is asigned to the widget you want to show via SetState(). The widgets are switched with a nice animation.
If you need to have one Widget placed one above the other in the vertical axis, you should try to remove the scaffold and the SizedBox with infity values.
if this class can't stack.
Just using static type.
add these codes at the same file with CountDownTimer.
static const Widget countDownTimer = CountDownTimer();
...
// class CountDownTimer
Then, you must import this file and call this widget by this parameter.
example
#override
Widget build(BuildContext context) {
return Column(
children: [
HomePageTimerUI(),
countDownTimer,
],
);
}
but you don't need to use StackPages just put countDownTimer in your pages.

How can I create a ListView correctly?

I'm not able to create a Listview in Flutter because of when I create a Listview of widgets the screen stays empty, it's something like that 1
This is the Code that I wrote and returns a list view:
import 'package:dietapp/pages/homepage.dart';
import 'package:dietapp/pages/list.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:dietapp/pages/profile.dart';
import 'package:dietapp/pages/createReg.dart';
import 'package:percent_indicator/percent_indicator.dart';
void main() {}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const SafeArea(child: TopBar()),
const Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.only(left: 25, bottom: 20),
child: Text('Seguiment Diari', style: TextStyle(fontSize: 20)),
)),
Align(alignment: Alignment.center, child: TypesListView()),
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const CreateReg()));
},
label: const Text('Crear'),
icon: const Icon(Icons.add),
),
);
}
}
class TopBar extends StatelessWidget {
const TopBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
"Dietapp",
style: TextStyle(
color: Colors.black, fontSize: 30, fontWeight: FontWeight.bold),
),
],
),
);
}
}
class TotalLabel extends StatefulWidget {
final String typeOf;
final String subtitle;
final Function() onPressed;
final double fillBar;
const TotalLabel(
{required this.typeOf,
required this.subtitle,
required this.onPressed,
required this.fillBar,
Key? key})
: super(key: key);
#override
State<TotalLabel> createState() => _TotalLabelState();
}
class _TotalLabelState extends State<TotalLabel> {
Color getColor(double fillBar) {
if (fillBar < 0.5) {
return Colors.orange;
} else {
return Colors.green;
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onPressed,
child: Container(
width: 350,
height: 125,
padding: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.5),
boxShadow: [
BoxShadow(
offset: const Offset(10, 20),
blurRadius: 10,
spreadRadius: 0,
color: Colors.grey.withOpacity(.05)),
],
),
child: Column(
children: [
Text(widget.typeOf,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
)),
const SizedBox(
height: 5,
),
Text(
widget.subtitle,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.normal,
fontSize: 12),
),
const SizedBox(
height: 10,
),
const Spacer(),
LinearPercentIndicator(
width: 300,
lineHeight: 10,
barRadius: const Radius.circular(50),
backgroundColor: Colors.black12,
progressColor: getColor(widget.fillBar),
percent: widget.fillBar,
),
const Spacer()
],
),
),
);
}
}
class TypesListView extends StatelessWidget {
const TypesListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
TotalLabel(
typeOf: 'Proteines',
subtitle: 'Range',
onPressed: () {},
fillBar: 0.2),
],
);
}
}
When I run the code, the error view is the following:
I have also tried to use a Stateless widget returning a list view but didn't worked.
Thanks you so much :)
The following is an example of how to use a ListView. Note that I created a MaterialApp since ListView is a Material Widget. You can replace ListViewExample with your own Widget containing a ListView.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ListView Example',
home: ListViewExample(),
);
}
}
class ListViewExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
Text('Text Widget 1'),
Text('Text Widget 2'),
Text('Text Widget 3'),
],
);
}
}
ListView.builder(
itemCount: 5
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Text("Some text $index")
),
);
}),
More about listview

Tried creating tabs in product detail page in flutter. But tabs is in stateful widget. When I inserted tab class name in home class, getting error

I need to insert tabs below elevated button. When I am using it as separate file, its working fine. Please suggest any ways to insert tabs in this code. I am in the learning stage of flutter.Here is the code link on codepen.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
class TabsPart extends StatefulWidget {
#override
_TabsPartState createState() => _TabsPartState();
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: const Text('Welcome to Flutter'),
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Positioned(
child: Container(
alignment: Alignment.topCenter,
decoration: const BoxDecoration(
image: DecorationImage(
alignment: Alignment.bottomRight,
fit: BoxFit.cover,
image: AssetImage('assets/images/img1.png'))),
),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(14),
),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
margin: const EdgeInsets.only(bottom: 16),
width: 12 * 1.5,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(3),
),
),
),
const ProductNameAndPrice(),
const Spacing(),
const ProductDesc(),
const Spacing(),
const SizedBox(
height: 16,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
onSurface: Colors.white),
onPressed: null,
child: Text('Add to Cart',
style: TextStyle(
color: Colors.white, fontSize: 16)),
),
const Spacing(),
],
),
),
))
],
),
),
),
),
);
}
}
class Spacing extends StatelessWidget {
const Spacing({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return const SizedBox(
height: 16,
);
}
}
class RectButton extends StatelessWidget {
final String label;
const RectButton({
Key? key,
required this.label,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 32,
width: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9),
border: Border.all(color: Colors.white)),
child: Center(
child: Text(
label,
style: TextStyle(color: Colors.white, fontSize: 20),
)),
);
}
}
class ProductNameAndPrice extends StatelessWidget {
const ProductNameAndPrice({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Product 1',
style: TextStyle(
color: Color.fromARGB(255, 250, 235, 235), fontSize: 30),
),
Text(
'\u{20B9}${150}',
style: TextStyle(color: Colors.white, fontSize: 20),
),
],
);
}
}
class ProductDesc extends StatelessWidget {
const ProductDesc({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'This is a good product with \nexcellent quality. purchase it as soon as possible! \nFew numbers only Left in stocks',
style: TextStyle(color: Colors.white, fontSize: 16, height: 1.6)),
],
);
}
}
class _TabsPartState extends State<TabsPart> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(
icon: Icon(Icons.android),
text: "Tab 1",
),
Tab(icon: Icon(Icons.phone_iphone), text: "Tab 2"),
],
),
title: Text('TutorialKart - TabBar & TabBarView'),
),
body: TabBarView(
children: [
Center(child: Text("Page 1")),
Center(child: Text("Page 2")),
],
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
class Home extends StatefulWidget {
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
late TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
const ProductNameAndPrice(),
const ProductDesc(),
const SizedBox(height: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(onSurface: Colors.black),
onPressed: null,
child: Text('Add to Cart',
style: TextStyle(color: Colors.black, fontSize: 16)),
),
TabBar(
indicatorColor: Colors.grey,
controller: _tabController,
tabs: [
const Tab(
icon: Icon(
Icons.widgets,
color: Colors.black,
),
),
Tab(
icon: Icon(
Icons.widgets,
color: Colors.black,
),
),
],
),
Expanded(
child: TabBarView(
controller: _tabController,
children: const [
Text("POSTS"),
Text("REELS"),
],
),
),
]),
);
}
}
class RectButton extends StatelessWidget {
final String label;
const RectButton({
Key? key,
required this.label,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 32,
width: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9),
border: Border.all(color: Colors.white)),
child: Center(
child: Text(
label,
style: TextStyle(color: Colors.white, fontSize: 20),
)),
);
}
}
class ProductNameAndPrice extends StatelessWidget {
const ProductNameAndPrice({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Product 1',
style: TextStyle(color: Colors.black, fontSize: 30),
),
Text(
'\u{20B9}${150}',
style: TextStyle(color: Colors.black, fontSize: 20),
),
],
);
}
}
class ProductDesc extends StatelessWidget {
const ProductDesc({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'This is a good product with \nexcellent quality. purchase it as soon as possible! \nFew numbers only Left in stocks',
style: TextStyle(color: Colors.black, fontSize: 16, height: 1.6)),
],
);
}
}
try this

Flutter text and stack widget spaced evenly

I am trying to create a status indicator in flutter with text label on left side and stack widget on right side, I manage to arrange them using Row but the width of each widgets is not separated evenly and the stack max width overflows with the container.
Here is my code so far.
import 'package:flutter/material.dart';
class CustomIndicatorBar extends StatelessWidget {
const CustomIndicatorBar({
Key key,
#required this.percent,
#required this.title,
}) : super(key: key);
final double percent;
final String title;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final double maxBarWidth = constraints.maxWidth;
double barWidth = percent * maxBarWidth;
if (barWidth < 0) {
barWidth = 0;
}
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
Stack(
children: [
Container(
height: 20.0,
decoration: const BoxDecoration(
color: Color(0xFF555454),
),
),
Container(
height: 20.0,
width: barWidth,
decoration: const BoxDecoration(
color: Color(0xFFFA9F1D),
),
)
],
)
],
),
);
},
),
);
}
}
Here is the output
What I want to achieve is to space them out evenly and stack width will not overflow from the container.
Please try my solution:
The result:
Full code:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
title: 'Demo',
home: FirstRoute(),
));
}
class FirstRoute extends StatefulWidget {
const FirstRoute({Key? key}) : super(key: key);
#override
State<FirstRoute> createState() => _FirstRouteState();
}
class _FirstRouteState extends State<FirstRoute> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('First Route'),
),
body: Column(
children: const [
SizedBox(height: 16),
CustomIndicatorBar(
title: 'Mood',
percent: 0.5,
),
SizedBox(height: 16),
CustomIndicatorBar(
title: 'Hunger',
percent: 0.7,
),
],
),
);
}
}
class CustomIndicatorBar extends StatelessWidget {
const CustomIndicatorBar({
Key? key,
required this.percent,
required this.title,
}) : super(key: key);
final double percent;
final String title;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Stack(
children: [
Container(
height: 20.0,
decoration: const BoxDecoration(
color: Color(0xFF555454),
),
),
LayoutBuilder(builder: (context, constraints) {
return Container(
height: 20.0,
width: constraints.maxWidth * percent,
decoration: const BoxDecoration(
color: Color(0xFFFA9F1D),
),
);
})
],
),
)
],
),
);
}
}

Flutter counter not counting up

I have made this scorekeeper app for basketball. I need to count the score and show it on the application. But its stuck on 0. It probably has something to do with the setState().
If possible don't change the code too much since I need to show and explain this to my teacher.
inputPage:
class InputPage extends StatefulWidget {
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('basketball counter'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(children: <Widget>[Expanded(child: HoopDesign()), Text(Counter.counter.toString())] ),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: CardDesign1(),
),
Expanded(
child: CardDesign3(),
),
Expanded(
child: CardDesign2(),
),
],
)),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: CardDesign6(),
),
Expanded(
child: CardDesign4(),
),
Expanded(
child: CardDesign5(),
),
],
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: HoopDesign(),
),
],
),
),
],
),
);
}
}
Containers:
import 'package:flutter/material.dart';
import 'input_page.dart';
//#region Team1 cards
class CardDesign3 extends StatefulWidget {
#override
CardDesign3State createState() => CardDesign3State();
}
class CardDesign3State extends State<CardDesign3> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 3 punter lijn!',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
class CardDesign2 extends StatefulWidget {
#override
_CardDesign2State createState() => _CardDesign2State();
}
class _CardDesign2State extends State<CardDesign2> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() => Counter.counter += 2);
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 2 punter lijn',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
class CardDesign1 extends StatefulWidget {
#override
_CardDesign1State createState() => _CardDesign1State();
}
class _CardDesign1State extends State<CardDesign1> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() => Counter.counter++);
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 1 punter lijn',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
//#endregion
//#region Team2 cards
class CardDesign4 extends StatefulWidget {
#override
CardDesign4State createState() => CardDesign4State();
}
class CardDesign4State extends State<CardDesign4> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
Counter2.counter += 3 ;
}
);
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 3 punter lijn!',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
class CardDesign5 extends StatefulWidget {
#override
_CardDesign5State createState() => _CardDesign5State();
}
class _CardDesign5State extends State<CardDesign5> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
Counter2.counter += 2;
});
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 2 punter lijn',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
class CardDesign6 extends StatefulWidget {
#override
_CardDesign6State createState() => _CardDesign6State();
}
class _CardDesign6State extends State<CardDesign6> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
Counter2.counter++;
});
},
child: Container(
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.circular(10),
),
child: Text(
'Vanaf de 1 punter lijn',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
height: 100,
width: 100,
));
}
}
//#endregion
class HoopDesign extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/basketballhoop.jpg'),
),
shape: BoxShape.circle,
),
);
}
}
//#region Counters integers
class Counter {
static int counter = 0;
}
class Counter2 {
static int counter = 0;
}
//#endregion
Main:
import 'package:flutter/material.dart';
import 'input_page.dart';
void main() => runApp(BasketballCounter());
class BasketballCounter extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Color(0xFFEE682D),
scaffoldBackgroundColor: Color(0xFFEE682D),
),
home: InputPage(),
);
}
}
What the app looks like:
(see the 0 on the side of the top hoop)
https://i.imgur.com/JwLnVaU.png
I appreciate the help :)
You need to re-render InputPage to get the new value of the counter.
Sample: (I refactored the code, refer to HalfCourt widget)
class InputPage extends StatelessWidget {
const InputPage({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('basketball counter'),
),
body: Column(
children: <Widget>[
const Expanded(child: HalfCourt()),
const Expanded(child: HalfCourt(isUpperSide: false)),
],
),
);
}
}
class HalfCourt extends StatefulWidget {
const HalfCourt({
this.isUpperSide = true,
Key? key,
}) : super(key: key);
final bool isUpperSide;
#override
_HalfCourtState createState() => _HalfCourtState();
}
class _HalfCourtState extends State<HalfCourt> {
int counter = 0;
#override
Widget build(BuildContext context) {
final Widget hoopAndScore = Expanded(
child: Row(
children: <Widget>[
const Expanded(child: HoopDesign()),
Text(counter.toString())
],
),
);
return Column(
children: <Widget>[
if (widget.isUpperSide) hoopAndScore,
Row(
children: <Widget>[
Expanded(
child: CardDesign(
onPressed: () => setState(() => counter++),
text: 'Vanaf de 1 punter lijn',
),
),
Expanded(
child: CardDesign(
onPressed: () => setState(() => counter += 3),
text: 'Vanaf de 3 punter lijn!',
),
),
Expanded(
child: CardDesign(
onPressed: () => setState(() => counter += 2),
text: 'Vanaf de 2 punter lijn',
),
),
],
),
if (!widget.isUpperSide) hoopAndScore
],
);
}
}
class CardDesign extends StatelessWidget {
CardDesign({
required this.onPressed,
required this.text,
Key? key,
}) : super(key: key);
final VoidCallback onPressed;
final String text;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: onPressed,
child: Container(
height: 100,
width: 100,
margin: const EdgeInsets.all(15),
decoration: const BoxDecoration(
color: Color(0xFFEF7F4D),
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Text(
text,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: 'Bullpen3D',
fontSize: 20,
),
),
),
);
}
}
class HoopDesign extends StatelessWidget {
const HoopDesign({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 100.0,
width: 100.0,
color: Colors.orange,
);
}
}