Following are the screenshots of the Ui of Buttons which I want to make using Flutter.
There are the packages Pie chart and Syncfusion's package, but these are different for this approach.
Help me to create these.
I've found my solution and now adding on the request of #dijkstra
I've used PieChart widget to implement it.
First of all, create a model class
class PieButtonModel {
PieButtonModel({this.title, required this.onPressed});
final VoidCallback onPressed;
final String? title;
}
Now, create a stateless class for Ui. I've used two PieChart widgets in stack to match the required output.
class PieButtonScreen extends StatelessWidget {
PieButtonScreen({Key? key, required this.buttonsData, this.startsFrom}) : super(key: key);
final List<PieButtonModel> buttonsData;
final double? startsFrom;
int touchedIndex = -1;
#override
Widget build(BuildContext context) {
return Center(
child: StatefulBuilder(builder: (context, stateful) {
return Stack(
clipBehavior: Clip.none,
children: [
Container(
decoration: const BoxDecoration(
color: kGreyColor,
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Color(0xff1143A7),
Color(0xff00B6FE),
],
),
),
width: double.infinity,
height: double.infinity,
),
Container(
margin: const EdgeInsets.all(10),
decoration: const BoxDecoration(
color: kWhiteColor,
shape: BoxShape.circle,
),
width: double.infinity,
height: double.infinity,
),
PieChart(
PieChartData(
pieTouchData: PieTouchData(touchCallback: (FlTouchEvent event, pieTouchResponse) {
stateful(() {
if (!event.isInterestedForInteractions ||
pieTouchResponse == null ||
pieTouchResponse.touchedSection == null) {
touchedIndex = -1;
return;
}
touchedIndex = pieTouchResponse.touchedSection!.touchedSectionIndex;
pieButtonPressed(touchedIndex, buttonsData);
});
}),
borderData: FlBorderData(
show: true,
border: const Border(
top: BorderSide(color: Colors.red),
)),
sectionsSpace: 5,
centerSpaceRadius: 60,
centerSpaceColor: const Color(0xFFe7e8e9),
startDegreeOffset: startsFrom ?? 0,
sections: showingSections()),
),
Positioned.fill(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
Get.find<ValveViewController>().removeView();
},
child: Neumorphic(
style: const NeumorphicStyle(
boxShape: NeumorphicBoxShape.circle(),
color: kWhiteColor,
border: NeumorphicBorder(
color: Color(0xFF919192),
width: 2,
)),
child: Container(
height: 90,
width: 90,
decoration: BoxDecoration(
// shape: BoxShape.circle,
borderRadius: BorderRadius.circular(100),
),
child: const CircleAvatar(
backgroundImage: AssetImage('assets/images/icon.jpg'),
),
),
),
),
],
),
)
],
);
}),
);
}
}
And then, create a list of sections
List<PieChartSectionData> showingSections() {
return List.generate(buttonsData.length, (i) {
PieButtonModel pbm = buttonsData[i];
final isTouched = i == touchedIndex;
final fontSize = isTouched ? 14.0 : 11.0;
final radius = isTouched ? 100.0 : 90.0;
var val = buttonsData.length / 100;
List<String>? title = pbm.title?.replaceAll('/ ', '').split(" ");
return PieChartSectionData(
color: kGreyColor,
value: val,
title: title?.isEmpty == true
? ""
: title?.length == 1
? title![0]
: title!.length == 2
? "${title[0]}\n${title[1]}"
: title.length == 3
? "${title[0]}\n${title[1]}\n${title[2]}"
: "${title[0]}\n${title[1]}\n${title[2]}\n${title[3]}",
radius: radius,
titleStyle: TextStyle(
overflow: TextOverflow.ellipsis,
fontSize: fontSize,
color: kBlackColor,
),
);
});
}
Here is the output.
Related
I'm building an App I have to build UI like below but I don't have any idea that how to create UI like this. Kindly guide me through this.
var listImages = [
"https://source.unsplash.com/random/200x200?sig=1",
"https://source.unsplash.com/random/200x200?sig=2",
"https://source.unsplash.com/random/200x200?sig=3",
"https://source.unsplash.com/random/200x200?sig=4",
"https://source.unsplash.com/random/200x200?sig=5"
];
Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: [
for (int i = 0; i < (listImages.length>=4?4:listImages.length); i++)
Transform.translate(
offset: Offset(i == 0 ? 0.0 : i * 44, 0),
child: Container(
height: 70,
width: 70,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: Colors.black87,
),
clipBehavior: Clip.hardEdge,
child: (i+1)>=4?Text("+ ${listImages.length-3}",style:const TextStyle(color: Colors.green),):Image.network(listImages[i]),
),
)
],
),
)
Below are the methods used to prepare the layout
// this method return the layout as per your expectations, here images are the // list of items you want to use and max count are the list of max item you want // to show except the count tile.
Widget getItems(List<String> images, int maxCount) =>
Stack(
children: List.generate(images.length <= maxCount ? images.length : maxCount+1, (index) {
if(index == maxCount){
return Positioned(
left: index * 60,
child: Container(
padding: const EdgeInsets.all(2), // Border width
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 2,
),
color: Colors.black,
borderRadius: BorderRadius.circular(40)),
child: SizedBox.fromSize(
size: const Size.fromRadius(48), // Image radius
child: Center(
child: Text(
style: const TextStyle(
color: Color(0xff58D56D),
fontSize: 30
),
"+${images.length-maxCount}"
),
),
),
),
);
}
else {
return Positioned(
left: index * 60, child: getItemWidget(images[index]));
}
}),
);
// pass the image url you want to show.
Widget getItemWidget(String imageUrl) => Stack(
children: [
Container(
padding: const EdgeInsets.all(2), // Border width
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(40)),
child: ClipRRect(
borderRadius: BorderRadius.circular(40),
child: SizedBox.fromSize(
size: Size.fromRadius(48), // Image radius
child: Image.network(
imageUrl,
fit: BoxFit.fill,
),
),
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
padding: const EdgeInsets.all(2), // Border width
decoration: const BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: SizedBox.fromSize(
size: Size.fromRadius(20), // Image radius
child: Image.network(
"https://play-lh.googleusercontent.com/STIZ_iftiehDCSynHXQaLqiL-F4kbZwasXOB2nae5pXTOpNKz8XSd7_VCF1Zgc3Z8Q",
fit: BoxFit.contain,
),
),
),
),
)
],
);
Below code is used to show the items
getItems(["https://cdn.pixabay.com/photo/2013/07/13/10/07/man-156584__340.png",
"https://static.vecteezy.com/system/resources/thumbnails/001/993/889/small/beautiful-latin-woman-avatar-character-icon-free-vector.jpg",
"https://static.toiimg.com/thumb/resizemode-4,msid-76729536,width-1200,height-900/76729536.jpg",
"https://www.nj.com/resizer/zovGSasCaR41h_yUGYHXbVTQW2A=/1280x0/smart/cloudfront-us-east-1.images.arcpublishing.com/advancelocal/SJGKVE5UNVESVCW7BBOHKQCZVE.jpg",
"https://i.kinja-img.com/gawker-media/image/upload/t_original/ijsi5fzb1nbkbhxa2gc1.png"], 3),
)
Output:
The point is using Stack and Positioned to positiond widgets.
(index to padding, maxPerson to set maximum widget to show)
https://dartpad.dev/ example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final colors = const [
Colors.yellow,
Colors.green,
Colors.blue,
Colors.orange,
Colors.cyan,
Colors.brown,
];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PersonStacker(colors: colors),
),
);
}
}
class PersonStacker extends StatelessWidget {
final List<Color> colors;
final int maxPerson;
const PersonStacker({required this.colors, this.maxPerson = 3});
#override
Widget build(BuildContext context) {
return Stack(
children: [
...colors
.getRange(0, maxPerson)
.toList()
.asMap()
.map((index, color) => MapEntry(index, Person(index, color: color)))
.values
.toList(),
...colors.length > maxPerson
? [Person(maxPerson, plus: colors.length - maxPerson)]
: []
],
);
}
}
class Person extends StatelessWidget {
final int index;
final Color color;
final Color colorBorder;
final double size = 100;
final double offset = 30;
final int? plus;
const Person(this.index,
{this.plus, this.color = Colors.black, this.colorBorder = Colors.black});
Widget renderChild() => plus != null
? Center(
child: Text(
"+$plus",
style: const TextStyle(color: Colors.white, fontSize: 20),
),
)
: Container();
#override
Widget build(BuildContext context) {
return Positioned(
left: index * offset,
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color,
border: Border.all(width: 2, color: colorBorder),
borderRadius: BorderRadius.circular(size),
),
child: renderChild(),
),
);
}
}
Result
I have a ReorderdableList with 5 Widgets and each of them is Draggable.
The Draggable Widget works great, but it seems that this makes the onReorder function not work.
This is my ReorderableListView:
return Scaffold(
body: ReorderableListView(
onReorder: ((oldIndex, newIndex) {
print('onReorder');
}),
onReorderStart: (index) => print('reorder start'),
scrollDirection: Axis.horizontal,
children: [
for (final card in handCards)
HandCard(key: ValueKey(card), card, player, handOwner),
],
),
);
Each Handcard returns a Draggable Widget. Is there a way to make sure both still work?
Handcard Widget:
class HandCard extends ConsumerStatefulWidget {
HandCard(this.card, this.player, this.handOwner, {Key? key})
: super(key: key);
String handOwner;
dynamic card;
Player player;
#override
_HandCardState createState() => _HandCardState();
}
class _HandCardState extends ConsumerState<HandCard> {
#override
void initState() {
isVisibled = true;
// TODO: implement initState
super.initState();
print(isVisibled);
}
void setVisible() {
setState(() {
isVisibled = true;
});
}
late bool isVisibled;
#override
Widget build(BuildContext context) {
var handCardPickProvider =
ref.watch(handCardHighlightProvider(widget.card).notifier);
var handCardPick = ref.watch(handCardHighlightProvider(widget.card));
var gameStateProvider = ref.watch(GameStateProvider);
var handSize = ref.watch(handSizeProvider(widget.handOwner).state);
return Draggable<HandCard>(
onDragStarted: () {
// change state of current cards in hand
handSize.state = handSize.state - 1;
},
onDragEnd: (details) {
handSize.state = handSize.state + 1;
},
onDragCompleted: () {
setState(() {
isVisibled = true;
});
},
data: widget,
childWhenDragging: SizedBox.shrink(),
feedback: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(widget.card.imageLink),
fit: BoxFit.fill,
),
),
width: 100,
height: 150,
child: Stack(children: [
(widget.card is CharacterCard)
? Positioned(
right: 0,
left: 60,
child: Container(
color: Colors.white,
width: 40,
height: 13,
child: Center(
child: Text(
widget.card.power.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.bold),
),
),
),
)
: const SizedBox.shrink(),
Positioned(
left: 2,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(
child: Text(
widget.card.cost.toString(),
style: TextStyle(color: Colors.white, fontSize: 12),
)),
))
]),
),
child: (isVisibled)
? InkWell(
onTap: () {
print('click');
// If it is the counter move and the card has a counter effect we can use it
if (gameStateProvider.gameSession!.moves.length != 0) {
Move currentMove = gameStateProvider.gameSession!
.moves[gameStateProvider.gameSession!.atMove - 1];
print(currentMove.moveType);
// Handle on counter effect
if (currentMove.moveType == 'on counter effect' &&
currentMove.toPlayer.id == widget.player.id) {
handCardPickProvider.highlightCard(widget.card);
}
}
},
child: Container(
margin: EdgeInsets.all(1),
decoration: BoxDecoration(
boxShadow: [
(handCardPick)
? BoxShadow(
color: Colors.white,
spreadRadius: 1,
blurRadius: 10)
: BoxShadow(
color: Colors.white,
spreadRadius: 0,
blurRadius: 0),
],
image: DecorationImage(
image: AssetImage(widget.card.imageLink),
fit: BoxFit.fill,
),
),
width: 100,
height: 150,
child: Stack(children: [
(widget.card is CharacterCard)
? Positioned(
right: 0,
left: 60,
child: Container(
color: Colors.white,
width: 40,
height: 13,
child: Center(
child: Text(
widget.card.power.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.bold),
),
),
),
)
: const SizedBox.shrink(),
Positioned(
left: 2,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(
child: Text(
widget.card.cost.toString(),
style: TextStyle(color: Colors.white, fontSize: 12),
)),
))
]),
),
)
: SizedBox.shrink(),
);
}
}
I am currently doing a chat app using flutter. I have 2 users and when one users start to chat with other user ,a document will be added in the "Chats" collection. If "user 1" starts a chat, a document of unique ID will be added in the collection. But the problem is, this document is not listed when I use .get() method...Please check what is the problem...
Here is my code:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:nebula_chat_app/backend/pics.dart';
import 'package:nebula_chat_app/main.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:nebula_chat_app/backend/FireBase.dart';
class InChat extends StatefulWidget {
final String secondUserId;
final String SeconduserName;
const InChat({Key key, this.secondUserId,this.SeconduserName}) : super(key: key);
#override
_InChatState createState() => _InChatState(secondUserId,SeconduserName);
}
class _InChatState extends State {
var messages;
String docu;
List ko;
Future> offlinemessage;
final String SecondUserId;
final String SeconduserName;
String typeMessage;
ScrollController _controller2;
TextEditingController controller2;
_InChatState(this.SecondUserId,this.SeconduserName);
#override
void initState() {
controller2 = TextEditingController();
addUser();
_controller2 = ScrollController();
database.collection("Chats").get().then((value) {
var usersinChat = value.docs.map((e) => e.id).toList();
print(usersinChat);
docu = usersinChat.singleWhere((element) => ((element == auth.currentUser.uid.toString() + SecondUserId) || (element == SecondUserId + auth.currentUser.uid.toString())),orElse: ()
=> auth.currentUser.uid.toString() + SecondUserId
);
}).then((value) {
messages = database.collection("Chats").doc(docu).collection("Messages").snapshots();
print("_________________$docu");
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(icon: Icon(Icons.arrow_back_ios_sharp,color: Colors.white,), onPressed: () => Navigator.pop(context)),
title: Text(SeconduserName,style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: GFS(25, context),
color: Colors.white
),),
actions: [
IconButton(icon: Icon(Icons.search,color: Colors.white,), onPressed: null)
],
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Theme.of(context).primaryColorLight,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: MediaQuery.of(context).size.height*0.75,
width: MediaQuery.of(context).size.width,
child: StreamBuilder(
stream: messages,
builder: (context, snapshot){
if(!snapshot.hasData) return Center(child: CircularProgressIndicator(),);
else
return ListView.builder(
controller: _controller2,
itemCount: snapshot.data.docs.length,
itemBuilder: (context,int index) {
if (!snapshot.hasData) return SizedBox();
else {
if (snapshot.data.docs[index]["from"] == SecondUserId){
print("Second ======> $SecondUserId");
if(_keyboardIsVisible()){
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {_controller2.animateTo(_controller2.position.maxScrollExtent,duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn ); });
}
return ReceiveContainer(
text: snapshot.data.docs[index]["message"].toString());
}
else{
return SendContainer(
text: snapshot.data.docs[index]["message"].toString(), status: "seen",);
}
}
}
);
},
)
),
Container(
height: MediaQuery.of(context).size.height*0.1,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: MediaQuery.of(context).size.height*0.07,
alignment: Alignment.center,
width: MediaQuery.of(context).size.width*0.75,
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
boxShadow: [BoxShadow(color: Colors.black26,spreadRadius: 1.0,blurRadius: 3.0)],
borderRadius: BorderRadius.circular(40.0)
),
child: Padding(
padding: EdgeInsets.only(left:MediaQuery.of(context).size.width*0.07),
child: TextField(
controller: controller2,
style: TextStyle(
color: Colors.black,
),
decoration: InputDecoration(
focusColor: Colors.black,
hintText: 'Type here',
border: InputBorder.none,
focusedBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
hintStyle: TextStyle(
color: Colors.black26,
fontSize: GFS(20, context)
)
),
onSubmitted: (text) {
setState(() {
controller2.text = text;
});
},
),
),
),
Container(
height: MediaQuery.of(context).size.height*0.07,
width: MediaQuery.of(context).size.width*0.2,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
shape: BoxShape.circle,
boxShadow: [BoxShadow(color: Colors.black26,spreadRadius: 1.0,blurRadius: 3.0)],
),
child: InkWell(
onTap: () {
database.collection("Chats").doc(docu).collection("Messages").doc(Timestamp.now().millisecondsSinceEpoch.toString()).set(
{
"from":auth.currentUser.uid.toString(),
"message": controller2.text,
"timestamp" : Timestamp.now().millisecondsSinceEpoch
});
setState(() {
controller2.text = "";
});
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {_controller2.animateTo(_controller2.position.maxScrollExtent,duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn ); });
},
child: SizedBox(
width:MediaQuery.of(context).size.width*0.1,
height:MediaQuery.of(context).size.height*0.035,
child: SvgPicture.asset(sendIcon,fit: BoxFit.contain,)),
),
)
],
),
) ///Typing Container
],
),
),
),
);
}
bool _keyboardIsVisible() {
return !(MediaQuery.of(context).viewInsets.bottom == 0.0);
}
void checkCommon() {
}
}
class ReceiveContainer extends StatelessWidget {
final String text;
const ReceiveContainer({Key key, this.text}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
alignment: Alignment.centerLeft,
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height*0.1,
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: MediaQuery.of(context).size.height*0.02,horizontal:MediaQuery.of(context).size.width*0.05 ),
child: Container(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width*0.1,
maxWidth: MediaQuery.of(context).size.width*0.5,
minHeight: MediaQuery.of(context).size.height*0.06,
),
decoration: BoxDecoration(
color:Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(20.0),
boxShadow: [BoxShadow(color: Colors.black26,spreadRadius: 1.0,blurRadius: 2.0)]
),
child: Padding(
padding: EdgeInsets.all(MediaQuery.of(context).size.width*0.4*0.1),
child: Text(text,style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: GFS(19, context),
color:Theme.of(context).textTheme.headline1.color
),),
),
),
),
);
}
}
class SendContainer extends StatelessWidget {
final String text;
final String status;
const SendContainer({Key key, this.text,this.status}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height*0.1,
),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: MediaQuery.of(context).size.height*0.03,
width: MediaQuery.of(context).size.width*0.1,
child: checkStatus(status)
),
Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height*0.02,bottom: MediaQuery.of(context).size.height*0.02,left:MediaQuery.of(context).size.width*0.05 ,right:MediaQuery.of(context).size.width*0.02 ),
child: Container(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width*0.1,
maxWidth: MediaQuery.of(context).size.width*0.5,
minHeight: MediaQuery.of(context).size.height*0.06,
),
decoration: BoxDecoration(
color:Theme.of(context).primaryColorDark,
borderRadius: BorderRadius.circular(20.0),
boxShadow: [BoxShadow(color: Colors.black26,spreadRadius: 1.0,blurRadius: 2.0)]
),
child: Padding(
padding: EdgeInsets.all(MediaQuery.of(context).size.width*0.4*0.1),
child: Text(text,style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: GFS(19, context),
color: Colors.white
),),
),
),
),
],
),
),
);
}
checkStatus(statusss) {
{
if(statusss == 'delivered') return SvgPicture.asset(doubleCheckIcon,fit: BoxFit.contain,color: Colors.black,);
else if (statusss == 'Not delivered') return SvgPicture.asset(checkIcon,fit: BoxFit.contain,color: Colors.black,);
else if (statusss == 'seen') return SvgPicture.asset(doubleCheckIcon,fit: BoxFit.contain,color: Colors.green,);
}
}
}
I aim using a BottomNavigationBar that contains an icon with a badge that displays the number of products a user have in his shopping cart;
there is only one place to add an product to the cart which i call AddToCartRow :
class AddToCartRow extends StatefulWidget {
final productId;
AddToCartRow(this.productId);
#override
_AddToCartRowState createState() => _AddToCartRowState();
}
class _AddToCartRowState extends State<AddToCartRow> {
TextEditingController _text_controller = TextEditingController();
final CartController cartController = CartController();
int quantity = 1;
#override
void initState() {
super.initState();
_text_controller.text = quantity.toString();
}
void increment() {
setState(() {
quantity += 1;
_text_controller.text = quantity.toString();
});
}
void decrement() {
setState(() {
quantity -= 1;
_text_controller.text = quantity.toString();
});
}
void quantityChanged(val) {
setState(() {
quantity = int.parse(val);
});
}
void addToCart() {
var data = {
"product_id": widget.productId.toString(),
"quantity": quantity.toString(),
};
cartController.addToCart(data);
}
#override
Widget build(BuildContext context) {
return Obx(
() => Padding(
padding: EdgeInsets.all(10),
child: Row(
children: [
// Button
GestureDetector(
child: Container(
height: 50,
width: MediaQuery.of(context).size.width / 2 - 15,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
decoration: BoxDecoration(
color: CupertinoTheme.of(context).primaryColor,
borderRadius: BorderRadius.circular(4),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"ADD TO CART ",
style: TextStyle(color: CupertinoColors.white),
),
Icon(
CupertinoIcons.bag,
color: CupertinoColors.white,
)
],
),
),
onTap: addToCart),
SizedBox(
width: 10,
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: cartController.modifying.value == true
? CupertinoActivityIndicator()
: Container(),
),
),
// Count
Container(
width: MediaQuery.of(context).size.width / 2 - 15,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 50,
child: Row(
children: [
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: CupertinoColors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
bottomLeft: Radius.circular(4),
),
),
width: 50,
height: 50,
child: CupertinoButton(
padding: EdgeInsets.zero,
child: Icon(CupertinoIcons.minus),
onPressed: decrement),
),
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: CupertinoColors.white,
),
alignment: Alignment.center,
child: CupertinoTextField(
controller: _text_controller,
textAlign: TextAlign.center,
onChanged: quantityChanged,
style: TextStyle(
fontSize: 25,
color: CupertinoColors.secondaryLabel),
decoration: BoxDecoration(
borderRadius: BorderRadius.zero,
color: CupertinoColors.white),
)),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: CupertinoColors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(4),
bottomRight: Radius.circular(4),
),
),
width: 50,
height: 50,
child: CupertinoButton(
padding: EdgeInsets.zero,
child: Icon(CupertinoIcons.plus),
onPressed: increment),
)
],
),
),
],
),
)
],
),
),
);
}
}
And there is one place to view the products count (in the cart) in the BottomNavigationBar which is above the AddToCartRow in the widgets tree:
BottomNavigationBarItem(
icon: Obx(
() => Stack(
alignment: Alignment.topRight,
children: [
Icon(CupertinoIcons.bag),
Container(
decoration: BoxDecoration(
color: cartController.loading.value == true
? CupertinoColors.white
: CupertinoTheme.of(context).primaryColor,
borderRadius: BorderRadius.circular(10),
),
alignment: Alignment.center,
width: 20,
height: 20,
child: cartController.loading.value == true
? CupertinoActivityIndicator()
: Text(
cartController.cartProductsCont.toString(),
style: TextStyle(
color: CupertinoColors.white,
fontWeight: FontWeight.bold),
),
)
],
),
),
activeIcon: Icon(CupertinoIcons.bag_fill),
label: 'Cart',
),
and the CartControllerClass:
class CartController extends GetxController {
var cartProducts = [].obs;
var cartProductsCont = 0.obs;
var emptyCart = true.obs;
var loading = true.obs;
var modifying = false.obs;
void getCart() async {
var response = await api.getCart();
response = response.data;
if (response["data"].length == 0) {
emptyCart.value = true;
cartProducts.clear();
} else {
emptyCart.value = false;
cartProducts.assignAll(response["data"]["products"]);
cartProductsCont.value = cartProducts.length;
}
loading.value = false;
modifying.value = false;
}
void addToCart(data) async {
loading.value = true;
modifying.value = true;
await api.addProductToCart(data).then((value) => getCart());
}}
in the first time when i call getCart from the widget that holds the BottomNavigatioBar every thing works great, but when i call getCart from AddToCartRow no thing happend , WHY ?
Your State class is not injecting the CartController instance into Get's State Manager using Get.put()
class _AddToCartRowState extends State<AddToCartRow> {
TextEditingController _text_controller = TextEditingController();
final CartController cartController = CartController();
int quantity = 1;
Get.put(CartController())
class _AddToCartRowState extends State<AddToCartRow> {
TextEditingController _text_controller = TextEditingController();
final CartController cartController = Get.put(CartController());
// You're missing a Get.put which Get ↑↑↑↑ needs to track
int quantity = 1;
}
I am new in flutter. I have implemented a button and i want to progress indicator like below on click of the button.
I have already use percent indicator package to implement but it's not archive properly.
my code is,
class DownloadIndicatorWidget extends StatefulWidget {
bool download = false;
#override
_DownloadIndicatorWidgetState createState() => _DownloadIndicatorWidgetState();
}
class _DownloadIndicatorWidgetState extends State<DownloadIndicatorWidget> {
#override
Widget build(BuildContext context) {
return widget.download?ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
height: 40,
decoration: BoxDecoration(
border: Border.all(
color: Color(0xff9F00C5), // <--- border color
width: 10.0,
),
borderRadius: BorderRadius.circular(10.0)
),
child: LinearPercentIndicator(
// width: MediaQuery.of(context).size.width -
// width:107,
animation: true,
lineHeight: 40.0,
animationDuration: 2500,
percent: 1,
center: Text(
"Downloading...",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontSize: 14
)),
linearStrokeCap: LinearStrokeCap.roundAll,
progressColor: Color(0xff9F00C5),
backgroundColor: Colors.white,
),
),
):RaisedButton(
onPressed: () {
setState(() {
widget.download = true;
});
},
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
padding: EdgeInsets.all(0.0),
child: Ink(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Color(0xff9F00C5), Color(0xff9405BD),Color(0xff7913A7),Color(0xff651E96), Color(0xff522887)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
borderRadius: BorderRadius.circular(10.0)
),
child: Container(
constraints: BoxConstraints(maxWidth: 300.0, minHeight: 50.0),
alignment: Alignment.center,
child: Text(
"Download",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w800,
fontSize: 18
),
),
),
),
);
}
}
So, how to implement properly to archive like image ? and if there is any other way to achieve it, please do suggest me i really need this.
Thanks in advance!
This code may help you.
import 'dart:async';
import 'package:flutter/material.dart';
class Progress extends StatefulWidget {
#override
_ProgressState createState() => _ProgressState();
}
class _ProgressState extends State<Progress> {
double progress = 0;
void initState() {
super.initState();
Timer.periodic(Duration(milliseconds: 100), (Timer t) {
setState(() {
if (progress > 120) {
progress = 0;
} else {
progress += 5;
}
});
});
}
#override
Widget build(BuildContext context) {
return Center(
child: FlatButton(
onPressed: () {},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
height: 45,
width: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.indigo,
width: 1,
)),
child: Stack(
children: <Widget>[
AnimatedContainer(
color: Colors.indigo,
width: progress,
duration: Duration(milliseconds: 100),
curve: Curves.fastOutSlowIn,
),
Center(child: Text("Downloading...")),
],
))),
),
);
}
}