How to make DropdownButtonFormField to occupy the minimum possible space? - user-interface

The flutter DropDownButton will automatically shrink to size of the largest label of the choices, like so :-
But a DropDownButtonFormField changes this behavior, and instead occupies the whole space available to it.
So, how do I make the DropDownButtonFormField mimic the space occupation behavior of a DropDownButton ?

I had a similar problem trying to make DropDownButtonFormField fit a minimal possible space in a Row. Unfortunately, InputDecorator widgets that are used inside the DropDownButtonFormField don't support children that can set their own width (such as DropDownButton) and require maxWidth to be capped by parent.
I managed to make it work using IntrinsicWidth widget (warning: according to the docs, this widget is relatively expensive because it adds a speculative layout pass before the final layout phase):
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IntrinsicWidth(
child: DropdownButtonFormField<String>(
value: "1",
items: [
DropdownMenuItem(
value: "1",
child: Text("1"),
),
DropdownMenuItem(
value: "2",
child: Text("2"),
),
],
onChanged: _onCurrencyChanged,
)),
],
)
IntrinsicWidth sets child's width to the child's maximum intrinsic width, satisfying InputDecorator's need to have a fixed width.

Related

Aligning transparent PNG with underlying elements

I have an image of a resistor with transparent regions where the color code goes. Behind the resistor I'm trying to position the colors so that I can generate any resistor combination.
I managed to get it right on my phone in portrait mode and it looks almost right in the browser when I resize it to a specific size:
However, in landscape mode or in a larger browser window, the colors no longer align with the image:
I am using a stack for putting items on top of each other in Z-direction
Stack(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _rings,
),
Image(image: AssetImage('assets/resistor.png')),
]
),
and I use an ugly combination of spacers and my own Ring implementation, which is basically a constrained box
_rings = [
Spacer(flex: 10),
Ring( _ringColors[0]),
Spacer(flex: 1),
Ring( _ringColors[1]),
Spacer(flex: 1),
Ring( _ringColors[2]),
Spacer(flex: 14),
];
Ring:
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: 40.0,
minHeight: 100.0,
),
child: Material(
color: _ringColors[widget.colorIndex.value],
));
}
I don't see how this will be responsive for all orientations and sizes.
How would one typically approach this in Flutter?
I followed the advise of #pskink and created one image per ring in the same size as the original one.
I then stack 4 images on top of each other, each with a different Color, using BlendMode to exchange the non-transparent color by a given one.
Stack(
children: <Widget>[
Image.asset("assets/ring1.png", color: Colors.yellow,),
Image.asset("assets/ring2.png", color: Colors.purple,),
Image.asset("assets/ring3.png", color: Colors.brown,),
Image.asset("assets/resistor.png",),
]
),
For real resistor values based on an input value, the color needs to be dynamic, of course.
The approach suggested by #Christopher Moore didn't work out for me, because I want compatibility for web. It may still be useful for someone. It uses the image package, for which I need I/O to get a byte[] which is then decoded as an image.
Reference in pubspec.yaml:
dev_dependencies:
image: ^3.0.2
Parts of the code (untested since I could not use await either, sorry):
import 'package:image/image.dart' as png;
import 'dart:io';
...
var file = File('assets/colors.png'); // direct I/O not allowed in web
var bytes = await file.readAsBytes();
var image = png.decodeImage(bytes);

Make a card big enough to fit the child text

I'm creating a simple card that contains a long description.
I want to set the normal height of the card to 50px and when the user clicks on it I want to expand the card to be able to fit all the content inside.
So far, to obtain my needs I wrote this:
String aLotOfText = "When Gradle resolves the compile classpath, it first resolves the runtime classpath and uses the result to determine what versions of dependencies should be added to the compile classpath. In other words, the runtime classpath determines the required version numbers for identical dependencies on downstream classpaths. Your app's runtime classpath also determines the version numbers that Gradle requires for matching dependencies in the runtime classpath for the app's test APK. The hierarchy of classpaths is described in figure 1.";
bool cardExpanded = false;
InkWell(
onTap: () {
expandCard();
},
child: AnimatedContainer(
height: cardExpanded ? null : 50,
duration: Duration(milliseconds: 200),
child: Card(
child: Text(aLotOfText),
),
)
)
expandCard() {
setState(() {
cardExpanded = !cardExpanded;
});
}
As you can see on the line height: cardExpanded ? null : 50, when cardExpanded is true I didn't specify the height, so in this way I'm able to expand the card to the right height to contain the text.
But with this little hack I've completely lost the animation and as long as this card would go in a listview with 20 or more other cards, the opening and closing makes the list to jump up and down.
I'm sure that there is a way to expand the card to the right height keeping also the animation.
I would also like to specify that the one above is just an example, in my card, there will be images and buttons as well.
In addition, when the card is opened with a button, I could add some text, so the card has to expand as well when it is opened.
That's why I cannot specify a height.
EDIT
With height: cardExpanded ? null : 50 I get what I want, so, the card grows big enough to fit the content, but as you can see there is no animation there
Instead if I provide a value like height: cardExpanded ? 100 : 50, I get the animation, but obviously the card grows until it gets to 100 pixels and it dosen't show all the content.
The result that I would like to obtain is what there is in the first example plus the animation.
Thankyou
You could set two variables:
height = MediaQuery.of(context).size.height * 0.8; //the percentage you want the card to grow
width = MediaQuery.of(context).size.width * 0.8;
So when expanded is true, the container grows.
height: cardExpanded ? height : 50,
width: cardExpanded ? width : 50,
Also, to specify how the animation will perform, you have a property that can make the animation look smoother.
curve: Curves.bounceInOut,
or you could try using a widget like expanded to adjust.

Why should I use [Expanded] / [Flexible] flex over [Align] alignment?

I have been wondering why one should use [Expanded] / [Flexible] flex over [Align] alignment? You can precisely align your widget with [Align] and even potentially avoid [Padding].
Let's see it from another view, is using the flex of [Expanded] / [Flexible] more efficient and faster than [Align]?
There is no comparison between Expanded/Flex and Align. Take a look at the following snippet.
Column(
children: [
Container(color: Colors.blue, height: 200),
Align(child: Container(color: Colors.green)), // doesn't show anything
Expanded(child: Container(color: Colors.orange)), // shows up in the remaining space
],
);
Having Align as the parent of Container won't show anything on screen but if you use Expanded/Flex it will take up the left space.
Not sure what you a referring to. Expanded is for (more or less) "selecting" which widget inside a Row/Column should fill the remaining space. While Align just positions the child inside itself at the given alignment.

Overflow of List-Based ListView

I want to preface this question by saying that I am very new to flutter/dart.
Essentially, I have a list containing a bunch of strings. I want to list them in the main (and only) view. I have this code:
ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(24.0),
children: _availableTraits.map((item) => new Text(item, style: TextStyle(fontSize: 24.0))).toList()
)
I guess I am fortunate that _availableTraits is a relatively large list so that I discovered this problem. The list goes beyond the bottom of the page and a sort of warning/caution tape is put up at the bottom of the screen by flutter along with the error message: BOTTOM OVERFLOWED BY 93 PIXELS.
So how can I force flutter to just use a scroll bar?
Edit:
Figured I should probably share a picture of the problem.
Edit 2:
The above ListView is wrapped in a column element. The column element is wrapped in a scaffold.
In order to fix your issue you need to expand your shrinked ListView, like this:
Column(
children: <Widget>[
Expanded(
child: ListView(
shrinkWrap: true,
...

Flutter efficient image loading at runtime

I am trying to add a dice feature to my Flutter application. In Java, I would generate a random number out of 20, and then pull up the corresponding image based on the result. For example a roll of 14 would pull up an image of dice_image_14.jpg.
I am not sure how to do this in Flutter due to the way build methods work.
The only way I can think to do this is a massive ugly pile of nested conditional statements:
#override
build(Buildcontext context) {
Stack (
diceRoll == 1 ?
Container(
BoxDecoration(
image: ('lib/images/dice_image_1.jpg),
),
) : diecroll == 2?
Container(
BoxDecoration(
image: ('lib/images/dice_image_2.jpg),
),
) : diecroll == 3? // etc etc etc. 20 times!!
);
}
Is there a more realistic solution for loading specific images into a container on demand post runtime?
Just interpolate your diceRoll with your asset path:
BoxDecoration(
image: ('lib/images/dice_image_$diceRoll.jpg)
)
From Dart docs
$variableName (or ${expression})
String interpolation: including a variable or expression’s
string equivalent inside of a string literal.

Resources