Change Container Size onTap event in flutter - flutter

I have a 2 containers in Row, when i click on one container it should change its size, i have set the default size of the container and when the container is tapped it should change the size of the container.
Below is my code:
double selectedWidthActive = width * 0.45;
double selectedWidthInActive = width * 0.40;
double selectedHeightActive = height * 0.45;
double selectedHeightInActive = width * 0.40;
GestureDetector(
onTap: (){
setState(() {
selected = true;
credit = true;
});
},
child: Container(
width: selected ? selectedWidthActive : selectedWidthInActive,
height: selected ? selectedHeightActive : selectedHeightInActive,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Color(0xffFFD4E2), Color(0xffFF8FB3)], begin: Alignment.topCenter, end: Alignment.bottomCenter),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SvgPicture.asset('assets/svg/debit_account.svg',width: 50,),
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.75),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text('Debit Card', style: TextStyle(fontSize: 13, fontFamily: 'Gilroy Medium'),),
),
),
],
),
),
),
),
When i printed the value in console its not changing.
This is my expected output.
Please help me on this.

Try this:
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool selected = false;
bool credit = false;
double selectedWidthActive = 0;
double selectedHeightActive = 0;
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
double selectedWidthInActive = width * 0.40;
double selectedHeightInActive = width * 0.40;
return Scaffold(
body: GestureDetector(
onTap: () {
setState(() {
selected = true;
credit = true;
selectedWidthActive = width * 0.45;
selectedHeightActive = height * 0.45;
});
},
child: Container(
width: selected ? selectedWidthActive : selectedWidthInActive,
height: selected ? selectedHeightActive : selectedHeightInActive,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFFD4E2), Color(0xffFF8FB3)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
const FlutterLogo(),
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.75),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(
'Debit Card',
style:
TextStyle(fontSize: 13, fontFamily: 'Gilroy Medium'),
),
),
),
],
),
),
),
),
);
}
}

real simple
double w = width * 0.45;
double h = height* 0.45;
...event i.e. on click, etc
setState(() {
w = width * 0.40;
h = height* 0.40;
});

Your current code is working fine. I just check that and able to change the width and height once it tap. Are you facing an issue when you tap other and previous tapped item is not getting change? If so, Please manage the boolean selected, credit there. Please check the code I have tried as below. with the result
Row(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = true;
credit = false;
});
},
child: Container(
width: selected ? selectedWidthActive : selectedWidthInActive,
height: selected
? selectedHeightActive
: selectedHeightInActive,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFFD4E2), Color(0xffFF8FB3)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.75),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
child: Text('Debit Card', style: TextStyle(
fontSize: 13, fontFamily: 'Gilroy Medium'),),
),
),
],
),
),
),
),
SizedBox(width: 10,),
GestureDetector(
onTap: () {
setState(() {
selected = false;
credit = true;
});
},
child: Container(
width: credit ? selectedWidthActive : selectedWidthInActive,
height: credit
? selectedHeightActive
: selectedHeightInActive,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffBDF4FF), Color(0xff7AE7FF)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.75),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
child: Text('Credit Card', style: TextStyle(
fontSize: 13, fontFamily: 'Gilroy Medium'),),
),
),
],
),
),
),
),
],

Saitoh Akira's answer is correct but It can be develop.
onTap: () {
setState(() {
selected = !selected;
credit = !credit;
selectedWidthActive = width * 0.45;
selectedHeightActive = height * 0.45;
});
},
using onTap function like this is more efficient

Related

Bottom container inside stack moves upwards as keyboard opens on textfeild click - Flutter

I have a stack with list of content and custom dialogBox that I created. It contains textfeild. When I click the textfeild, keyboard opens and push dialog box way above the keyboard. There is alot of gap between the bottom of the dialog and the start of the keyboard. How can I keep the bottom of dialog stuck to the top the keyboard in a clean manner.
import 'package:flutter/material.dart';
class CombinedHomeView extends StatefulWidget {
// --- Services Headings
#override
_CombinedHomeViewState createState() => _CombinedHomeViewState();
}
class _CombinedHomeViewState extends State<CombinedHomeView> {
_showGrocOrderReviewDialog(Size _deviceSize) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
width: double.infinity,
height: _deviceSize.height * 0.28,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"How was your last order?",
style: TextStyle(
fontFamily: fontMontserrat,
color: Colors.black87,
),
),
SizedBox(height: 10),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.2),
borderRadius: BorderRadius.all(
Radius.circular(_deviceSize.height * 0.02),
),
),
child: SingleChildScrollView(
child: TextField(
maxLines: 5,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Add additional remarks',
hintStyle: TextStyle(
fontSize: _deviceSize.height * 0.015,
fontFamily: fontMontserrat,
color: Colors.black38,
),
),
),
),
),
),
SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: SmallBtn(
passedText: "Cancel",
passedBorderColor: Colors.green,
passedBGColor: Colors.white,
passedFontColor: Colors.brown,
),
),
SizedBox(width: 10),
Expanded(child: SmallBtn(passedText: "Submit")),
],
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
Size _deviceSize = MediaQuery.of(context).size;
return Stack(
alignment: Alignment.center,
children: [
// ------------ List of content
ListView( // few simple widgets here),
// ------------ Dialog
_showGrocOrderReviewDialog(_deviceSize)
],
);
}
}
You can ignore the below code. It is just a code of SmallBtn incase anyone needs it.
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class SmallBtn extends StatelessWidget {
final String passedText;
IconData passedIcon;
Color passedBGColor;
Color passedFontColor;
Color passedBorderColor;
bool isShadowEnabled;
SmallBtn({
#required this.passedText,
this.passedIcon,
this.passedBGColor,
this.passedFontColor,
this.passedBorderColor,
this.isShadowEnabled,
});
#override
Widget build(BuildContext context) {
isShadowEnabled == null
? isShadowEnabled = false
: isShadowEnabled = isShadowEnabled;
final deviceSize = MediaQuery.of(context).size;
return Container(
// alignment: Alignment.bottomLeft,
// width: deviceSize.width * 0.5 + passedText.length * 3,
padding: EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5),
height: deviceSize.height * 0.04,
decoration: BoxDecoration(
color: passedBGColor == null ? Colors.brown : passedBGColor,
borderRadius: BorderRadius.all(
Radius.circular(
deviceSize.height * 0.02,
),
),
border: Border.all(
color: passedBorderColor == null
? Colors.transparent
: passedBorderColor,
),
boxShadow: [
isShadowEnabled
? BoxShadow(
color: Colors.brown,
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
0.0, // horizontal
1.0, // vertical
),
)
: BoxShadow()
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
passedIcon != null
? Icon(
passedIcon,
color: Colors.white,
size: deviceSize.height * 0.02,
)
: Container(),
passedIcon != null
? SizedBox(width: deviceSize.width * 0.01)
: SizedBox(),
Text(
passedText,
style: TextStyle(
fontSize: deviceSize.height * 0.018,
fontFamily: "Montserrat",
color: passedFontColor != null ? passedFontColor : Colors.white,
),
),
],
),
);
}
}
Why are you using a stack? If you replace the stack with a column your dialog will not be pushed to the top of the screen.

Transparent card but with shadow effect from elevation

I'm having trouble making a card that has a transparent white color (opacity 0.4). But, with shadow from the elevation effect.
If I remove the elevation, there's no shadow effect and the card look transparent. But, if I add some elevation, the transparent effect ruined. Here's what I've tried:
Widget cardMenu(String title) {
return Container(
padding: EdgeInsets.symmetric(horizontal: UIComponent.componentPadding),
child: Stack(
alignment: Alignment.topCenter,
children: [
Positioned(
top: -100,
child: Container(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Center(
child: Text(
title,
style: TextStyle(color: Colors.transparent),
),
),
),
)
),
Align(
alignment: Alignment.bottomCenter,
child: Card(
elevation: 0,
color: Colors.white.withOpacity(0.4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(UIComponent.cardButtonRadius),
),
),
child: Container(
height: 350,
width: 180,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
padding: EdgeInsets.all(UIComponent.widgetPadding),
child: Text(
title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: UIComponent.h1,
color: UIComponent.neutralDark,
),
),
)
],
),
),
),
)
],
),
);
}
The output of my code:
What I'm expecting to be:
Hii Christophorus Anindityo N
Make a class for BoxShadow property of container.
class CustomBoxShadow extends BoxShadow {
final BlurStyle blurStyle;
const CustomBoxShadow({
Color color = const Color(0xFF000000),
Offset offset = Offset.zero,
double blurRadius = 0.0,
this.blurStyle = BlurStyle.normal,
}) : super(color: color, offset: offset, blurRadius: blurRadius);
#override
Paint toPaint() {
final Paint result = Paint()
..color = color
..maskFilter = MaskFilter.blur(this.blurStyle, blurSigma);
assert(() {
if (debugDisableShadows)
result.maskFilter = null;
return true;
}());
return result;
}
}
And use this class in a Container
Container(
child: Center(
child: Container(
height: 200.0,
width: 300.0
decoration: BoxDecoration(
boxShadow: [
CustomBoxShadow(
color: Colors.black,
offset: Offset(5.0, 5.0),
blurRadius: 5.0,
blurStyle: BlurStyle.outer
)
],
),
child: Text("Transparent Card with Shadow", style:TextStyle(fontSize:15))),
)
)
Now you are good to code :)

How can I change a container color on tap with Provider?

I am trying to create a custom style checkbox that is a container with rounded edges. It should show a different color icon when tapped. I am not sure how to do this can anyone help? Here is the code: (Edit I updated the code to show the gridview builder that the checkbox is placed in. The gridviewbuilder builds a card based on the length of a list in the provider class. I am trying to get the checkbox to work independently of the other gridview cards.
//this is the function in the provider class
toggleCheckbox(bool checkboxStatus){
if (checkboxStatus = false){
return checkboxStatus = true;
} else if (checkboxStatus = true){
return checkboxStatus = false;
}
notifyListeners();
}
GridView.builder(
itemCount: bloc.readingList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 12/16, crossAxisCount: 2, crossAxisSpacing: 20.0, mainAxisSpacing: 20),
itemBuilder: (BuildContext context, int index) {
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(3.0, 6.0),
blurRadius: 10.0)
],
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
image: NetworkImage('${bloc.readingList[index].storyImage}'),
fit: BoxFit.cover,
),
),
child: Padding(
padding: const EdgeInsets.only(
top: 8.0, bottom: 0.0, left: 0.0, right: 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TopicTag(index: index,),
CardContents(),
],
),
),
),
);
},
),
class CardContents extends StatefulWidget {
const CardContents({
Key key,
}) : super(key: key);
#override
_CardContentsState createState() => _CardContentsState();
}
class _CardContentsState extends State<CardContents> {
bool checkboxStatus = false;
#override
Widget build(BuildContext context) {
final bloc = Provider.of<ReadingListBloc>(context);
return ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
color: Colors.blueGrey.withOpacity(.5),
child: Column(
children: <Widget>[
Text('Title Here (color change with topic)',
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
fontFamily: "Calibre-Semibold",
letterSpacing: 1.0,
)),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8.0, bottom: 8),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white),
child: GestureDetector(
onTap:(){},
// bloc.toggleCheckbox(checkboxStatus),
child: checkboxStatus
? Icon(Icons.check_circle, color: Colors.green)
: Icon(Icons.check_circle, color: Colors.white)),
),
),
],
),
],
),
),
),
);
}
}
Considering that you have setup your provider correctly, you could do something like below.
// add the property below to your provider
bool checkboxStatus = false;
void toggleCheckbox(){
checkboxStatus = !checkboxStatus;
notifyListeners();
}
Now for the listeners, you can just check this new property, considering that bloc is your provider.
GestureDetector(
onTap: () {
bloc.toggleCheckbox(checkboxStatus);
},
child: bloc.checkboxStatus ? Icon(Icons.check_box, color: Colors.green)
: Icon(Icons.check_circle, color: Colors.white)),
I'm assuming that for some reason you want to use a provider. Of course you could also use a StatefulWidget if you only need the status in this widget.

Container filled with widgets beond hight and width without getting overflowed

I have a tricky one to solve.
In this case I have a container which expands the height and width of the size of the device.
Inside this widget I have other widgets that are placed beond the scope of the visible area.
So now I get the error that the bottom area in this case is overflowed. I thought that I could just set the opacity to 0 and the flip it to 1 when I change state but that not the case since Flutter still knows that there is something there. In good old android you could set the visibility to "gone" to make it don't take up space.
Here is my code for the layout:
Container(
color: primaryColor,
child: Stack(
fit: StackFit.loose,
children: [
SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.topCenter,
child: Column(
children: [
Icon(
Icons.swap_calls,
size: 100,
color: Colors.white,
),
Text(
'TCM Sensory',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w600),
),
Text(
'Made to be perfect',
style: TextStyle(color: Colors.white),
),
],
),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
height: _height,
width: _width,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: secondaryColor,
borderRadius: BorderRadius.circular(_radius),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
setState(() {
if (!_toggle) {
_radius = 0;
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
_title = "Press to Stop";
_color = primaryColor;
_toggle = true;
} else {
_radius = 10;
_width = 150;
_height = 50;
_title = "Press to Start";
_color = secondaryColor;
_toggle = false;
}
});
},
child: Container(
width: 140,
height: 30,
decoration: BoxDecoration(
color: _color,
borderRadius: BorderRadius.circular(8)
),
child: Center(
child: Text(
_title,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600),
),
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text('I am overflowed'),
)],
),
),
),
),
],
),
],
),
);
Here is the issue that occuring.
In android we have three visibility state [ View.GONE, View.INVISIBLE, View.VISIBLE ] but in flutter we can achieve that with Opacity or Visibility Widget like this :
View.INVISIBLE
Opacity(
opacity: 0.0,
child: const Text("you can't see me but I still take up space"),
)
View.Gone
Visibility(
visible: false,
child: const Text("you can't see me and I don’t take any space"),
)
View.VISIBLE
Visibility(
visible: true,
child: const Text("you can see me"),
)
or
Opacity(
opacity: 1.0,
child: const Text("you can see me"),
)
in your case you should do like this :
Visibility(
visible: !_toggle,
child : Padding(
padding: const EdgeInsets.all(16.0),
child: Text('I am overflowed'),
)
)
This should work(just replace your code "I am overflowed" with the padding with my code):
_width == MediaQuery.of(context).size.width ? Padding(
padding: const EdgeInsets.all(16.0),
child: Text('I am overflowed'),
) : Container()
Hope it helped
With Dart 2.3 you can use collection if in lists. Since your Padding with the Overflow-Text is within a Column the Padding is part of a list. If the expression inside the if is true, the Padding will be included otherwise not.
if(!_toogle)
Padding(
padding: const EdgeInsets.all(16.0),
child: Text('I am overflowed'),
)
Here is the link to the documentation: https://dart.dev/guides/language/language-tour#lists
Search for "collection if".

How to create UI with slide animation feature among pictures?

I am looking forward to create a UI in flutter with sliding animation between the images.
As shown in image I want the 1st to image slide left and image at the back to come i front
Code
class CardScrollWidget extends StatelessWidget {
var currentPage;
var padding = 5.0;
var verticalInset =22.0;
CardScrollWidget(this.currentPage);
#override
Widget build(BuildContext context) {
return new AspectRatio(
aspectRatio: widgetAspectRatio,
child: LayoutBuilder(builder: (context, contraints) {
var width = contraints.maxWidth;
var height = contraints.maxHeight;
var safeWidth = width - 2 * padding;
var safeHeight = height - 1 * padding;
var heightOfPrimaryCard = safeHeight;
var widthOfPrimaryCard = heightOfPrimaryCard * cardAspectRatio;
var primaryCardLeft = safeWidth - widthOfPrimaryCard;
var horizontalInset = primaryCardLeft / 2;
List<Widget> cardList = new List();
for (var i = 0; i < images.length; i++) {
var delta = i - currentPage;
bool isOnRight = delta > 0;
var start = padding +
max(
primaryCardLeft -
horizontalInset * -delta * (isOnRight ? 15 : 1),
0.0);
var cardItem = Positioned.directional(
top: padding + verticalInset * max(-delta, 0.0),
bottom: padding + verticalInset * max(-delta, 0.0),
start: start,
textDirection: TextDirection.rtl,
child: ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Container(
decoration: BoxDecoration(color: Colors.white, boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(3.0, 6.0),
blurRadius: 10.0)
]),
child: AspectRatio(
aspectRatio: cardAspectRatio,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(images[i], fit: BoxFit.cover),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
child: Text(title[i],
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
)),
),
SizedBox(
height: 10.0,
),
Padding(
padding: const EdgeInsets.only(
left: 12.0, bottom: 20.0),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 22.0, vertical: 6.0),
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(20.0)),
child: Text("Read Later",
style: TextStyle(color: Colors.white)),
),
)
],
),
)
],
),
),
),
),
);
cardList.add(cardItem);
}
return Stack(
children: cardList,
);
}),
);
}
}
This is often called a 'carousel effect' in UI design. There are multiple packages which seem to already solve what you are trying to do. E.g. the following:
https://pub.dev/packages/carousel_slider
https://pub.dev/packages/flutter_multi_carousel
https://pub.dev/packages/flutter_mobile_carousel
For more alternatives check out:
https://pub.dev/packages?q=carousel