How to randomly change rgb color? - flutter

In the application, when you click on the screen, you need to change the color to random, but it must be in RGB format. How can I get a random RGB color?
class _HomePageState extends State<HomePage> {
Color _color = Colors.white;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Color picker"),
centerTitle: true,
),
body: GestureDetector(
onTap: () {
setState(() {
_color = ...
});
},
child: Container(
color: _color,
padding: const EdgeInsets.all(20),
),
),
);
}
}

You can do like this
class _HomePageState extends State<HomePage> {
Random random = Random();
Color _color = Colors.white;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Color picker"),
centerTitle: true,
),
body: GestureDetector(
onTap: () {
setState(() {
_color = Color.fromRGBO(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
1,
);
});
},
child: Container(
color: _color,
padding: const EdgeInsets.all(20),
),
),
);
}
}

Best wat to get a random color:
Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0)
This import is required.
import 'dart:math' as math;
or
Colors.primaries[Random().nextInt(Colors.primaries.length)]

The other solutions (so far) are literally creating an arbitrary RGB value as requested, but I suspect the OP wants a "different but workable color". Random RGB is a poor way to generate those. You want randomness in the HSV direction.
In that case, supply random values to HSVColor.fromAHSV. Alpha should be 1.0 (opaque). Hue can be anything from 0.0 to 360.0. Saturation should probably be between 0.5 and 1.0 (more color than grey). Value should be between 0.0 and 0.5 if you have contrasting light text, and 0.5 to 1.0 if you have contrasting dark text.

Related

Flutter color animation produces unwanted flashing

I want to animate from this white color with slight opacity to a black color with very high opacity.
Colors are
Color(0xB1FFFFFF) - White
Color(0x0B000000) - Black
This will produce an animation with a "flash". However, this should not happen.
What am I doing wrong? When doing the same animation with css, it does not "flash".
This is how it looks when using css and how I would expect it:
The jump to white is not important, it's just the animation restarting.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(const AnimatedContainerApp());
class AnimatedContainerApp extends StatefulWidget {
const AnimatedContainerApp({Key? key}) : super(key: key);
#override
_AnimatedContainerAppState createState() => _AnimatedContainerAppState();
}
class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
double _width = 50;
double _height = 50;
Color _color = Color(0xB1FFFFFF);
BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('AnimatedContainer Demo'),
),
body: Center(
child: AnimatedContainer(
width: _width,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: _borderRadius,
),
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_color = Color(0x0B000000);
});
},
child: const Icon(Icons.play_arrow),
),
),
);
}
}
I found an alternative of this using Stack widget.
class _AnimatedContainerAppState extends State<AnimatedContainerApp>{
double _width = 50;
double _height = 50;
Color colorA = Color(0xB1FFFFFF);
Color colorB = Color(0x9F000000); //change your color here
double opacity = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.pink,
appBar: AppBar(
title: const Text('AnimatedContainer Demo'),
),
body: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: SizedBox(
key: const ValueKey("C"),
width: _width,
height: _height,
child: Stack(
fit: StackFit.expand,
children: [
//fixed color
AnimatedOpacity(
opacity: (1 - opacity).abs(),
duration: const Duration(seconds: 1),
child: ColoredBox(color: colorA),
),
AnimatedOpacity(
opacity: opacity,
duration: const Duration(seconds: 1),
child: ColoredBox(color: colorB),
),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
opacity = opacity == 0 ? 1 : 0;
});
},
child: const Icon(Icons.play_arrow),
),
),
);
}
}
You can also try with others animated widget like AnimatedCrossFade , FadeTransition etc.
I now understand why this "issue" exists.
Since both colors vary a lot both in opacity and color, a basic interpolation by time over the rgba values produces this behavior.
Whilst the alpha is being interpolated, the color is so too, and this creates a temporary darker color in between.
Dart interpolates colors by mapping the difference in colors to the time in the rgba spectrum.
a + (b - a) * t
This article describes very good what happens and other possible solutions for interpolating colors.
Also using HSL instead of rgba might also solve the issue. However, converting the color to HSL every time is not near as performant as flat rgba interpolation. Dart is all about performance, so this might be why they went for this very basic approach.
My personal solution to the problem was a very basic one though. I asked the designer to bring the colors closer together :)

Create a progress bar indicator shapes in flutter

We have a problem about our delivery system with progress indicator. Does anyone can suggest a library of progress indicator for flutter. The progress has a shape design. The sample image below.
Progress indicator image sample
You can achieve this using a Row, Containers and CustomClipper class. I've created a library for this purpose. You can use the library from here: progress_stepper.
The following code creates a stepper:
ProgressStepper(
width: 300,
height: 15,
stepCount: 5,
builder: (index) {
double widthOfStep = 300 / 5;
if (index == 1) {
return ProgressStepWithArrow(
width: widthOfStep,
defaultColor: Color(0xFFCECECF),
progressColor: Color(0xFFFBB040),
wasCompleted: true,
);
}
return ProgressStepWithChevron(
width: widthOfStep,
defaultColor: Color(0xFFCECECF),
progressColor: Color(0xFFFBB040),
wasCompleted: false,
);
},
)
It will create a Stepper like the following image:
You can copy paste run full code below
You can use package https://pub.dev/packages/clippy_flutter and https://pub.dev/packages/step_progress_indicator
When step index == 0 return Point else return Chevron
code snippet
StepProgressIndicator(
totalSteps: 3,
currentStep: 2,
size: 20,
selectedColor: Colors.orangeAccent,
unselectedColor: Colors.grey,
customStep: (index, color, _) => index == 0
? Point(
triangleHeight: 20.0,
edge: Edge.RIGHT,
child: Container(
color: color,
child: Center(child: Text('')),
))
: Chevron(
triangleHeight: 20.0,
edge: Edge.RIGHT,
child: Container(
color: color,
child: Center(child: Text('')),
)),
),
working demo
full code
import 'package:flutter/material.dart';
import 'package:clippy_flutter/clippy_flutter.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StepProgressIndicator(
totalSteps: 3,
currentStep: 2,
size: 20,
selectedColor: Colors.orangeAccent,
unselectedColor: Colors.grey,
customStep: (index, color, _) => index == 0
? Point(
triangleHeight: 20.0,
edge: Edge.RIGHT,
child: Container(
color: color,
child: Center(child: Text('')),
))
: Chevron(
triangleHeight: 20.0,
edge: Edge.RIGHT,
child: Container(
color: color,
child: Center(child: Text('')),
)),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

How to change Text color depending on background so that there is good contrast between the two colors

#override
Widget build(BuildContext context) {
var backgroundColor = Colors.orange; // this color could be anything
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(12),
color: backgroundColor,
child: Text("Hello World"), // if backgroundColor: Colors.orange this is visible but if backgroundColor: Colors.black, it isn't visible
),
),
);
}
Output (backgroundColor: Colors.orange, Text is visible):
Output (backgroundColor: Colors.black, Text isn't visible):
you can use computeLuminance() of Color class. Something like this:
#override
Widget build(BuildContext context) {
var backgroundColor = Colors.orange; // this color could be anything
var foregroundColor = backgroundColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(12),
color: backgroundColor,
child: Text("Hello World", style: TextStyle(color: foregroundColor)),
),
),
);
}
Of course you need to play around with the luminance IF-statement ... 1.0 is white and 0.0 is black. Yellow for instance is something about 0.8.

How to change CupertinoButton background color only when onPressed is called

I have tried following code but it does not change the color of the button only when it is pressed.
//class attribute
Color bgColor = Colors.deepPurpleAccent;
//Widget
CupertinoButton(
color: bgColor,
child: Text('LOGIN', style: TextStyle(fontFamily: 'Roboto',)),
borderRadius: const BorderRadius.all(Radius.circular(80.0)),
onPressed: () {
this.setState(() {
bgColor = Colors.black;
});
print(_emailValue);
print(_passwordValue);
Navigator.pushReplacementNamed(context, '/products');
},
),
If you just want to adjust an opacity of the highlighted button color, you can change pressedOpacity property:
CupertinoButton(
pressedOpacity: 0.4,
...
The default pressedOpacity value is 0.1, which is quite low. I found 0.4 is more natural to native iOS look.
You can wrap your CupertinoButton with a GestureDetector. Than use the onTapDown and onTapCancel to change color only when pressed. Like this:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Color _buttonColor = Colors.deepPurpleAccent;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: GestureDetector(
onTap: () {
print(_emailValue);
print(_passwordValue);
Navigator.pushReplacementNamed(context, '/products');
},
onTapDown: (tapDetails) {
setState(() => _buttonColor = Colors.black);
},
onTapCancel: () {
setState(() => _buttonColor = Colors.deepPurpleAccent);
},
child: CupertinoButton(
color: _buttonColor,
child: Text('test'),
onPressed: () {},
pressedOpacity: 1.0,
),
),
),
),
);
}
}
Now you can use onTap event on GestureDetector for calling navigation or whatever you need.
Your code works.
You just need to put the "bgColor" outside of the build function, so that when the setState is called, it doesn't set it again back to Purple.
Color bgColor = Colors.deepPurpleAccent;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CupertinoButton(
color: bgColor,
child: Text(
'LOGIN',
style: TextStyle(
fontFamily: 'Roboto',
),
),
borderRadius: const BorderRadius.all(Radius.circular(80.0)),
onPressed: () {
this.setState(
() {
bgColor = Colors.black;
},
);
// Navigator.pushReplacementNamed(context, '/products');
},
),
),
);
}
Unfortunate, there's no way you can do it.
You can extend the CupertinoButton and add the functionality, or use the RawMaterialButton and make it with the appearance that you need.
Edit: If you want to permanently change the color of the button, the #sina-seirafi answer is the correct one. But if you want to the button to be black only went you are pressing the RawMaterialButton with the black splash color is the best solution.

How to set the background color of a Flutter OutlineButton?

class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("..."),
),
body: Container(
color: Colors.green,
child: OutlineButton(
onPressed: () { },
color: Colors.orange,
highlightColor: Colors.pink,
child: Container(
color: Colors.yellow,
child: Text("A"),
),
shape: CircleBorder(),
),
),
);
}
}
The above code gives a transparent button. How can I get an orange OutlineButton?
OutlineButton has been deprecated and has been replaced with OutlinedButton. (Notice the "d".)
OutlinedButton's documentation helped me understand how to use it. Here's an example with these states: Disabled (Grey) --> Normal (Blue) --> Pressed (Red)
return Container(
width: double.infinity,
height: 48,
child: OutlinedButton(
child: Text(
"This is an Outline\"d\"Button. (Not OutlineButton)",
style: TextStyle(color: Colors.white),
),
onPressed: () => print("Tapped"),
//onPressed: null, //Uncomment this statement to check disabled state.
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.disabled)) {
return Colors.grey[100];
}
return Colors.blue;
}),
overlayColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.pressed)) {
return Colors.red;
}
return Colors.transparent;
}),
side: MaterialStateProperty.resolveWith((states) {
Color _borderColor;
if (states.contains(MaterialState.disabled)) {
_borderColor = Colors.greenAccent;
} else if (states.contains(MaterialState.pressed)) {
_borderColor = Colors.yellow;
} else {
_borderColor = Colors.pinkAccent;
}
return BorderSide(color: _borderColor, width: 5);
}),
shape: MaterialStateProperty.resolveWith<OutlinedBorder>((_) {
return RoundedRectangleBorder(borderRadius: BorderRadius.circular(16));
}),
),
),
);
Flutter replaced the former 3 button types (FlatButton, RaisedButton and OutlineButton) with new buttons types (TextButton, ElevatedButton and OutlinedButton) to remain in sync with Material design and also because using MaterialStateProperty provides the ultimate flexibility to achieve whatever state-specific-UI one needs. You can read more about it here.
To modify the backgroundColor of a OutlineButton you can use a DecoratedBox and a Theme widget. At the end of this answer you'll find a quick example.
Anyway I'd still recommend simply using the FlatButton with its color attribute instead.
Wrap your OutlinedButton inside a DecoratedBox. Set the shape of your DecoratedBox to the same shape your OutlinedButton. Now you can use the color attribute of your DecoratedBox to change the color. The result will still have a small padding around the OutlinedButton. To remove this you can wrap the DecoratedBox inside a Theme in which you adjust the ButtonTheme. Inside the ButtonTheme you want to set materialTapTargetSize: MaterialTapTargetSize.shrinkWrap.
The padding is added inside Flutter, to increase the tap area around the button to a minimum size of 48x48 (source). Setting materialTapTargetSize to MaterialTapTargetSize.shrinkWrap removes this minimum size.
FlatButton example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: FlatButton(
color: Colors.pinkAccent,
shape: CircleBorder(),
onPressed: () => {},
child: Text('A'),
),
),
),
);
}
}
OutlinedButton example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MyButton(),
),
),
);
}
}
class MyButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration:
ShapeDecoration(shape: CircleBorder(), color: Colors.pinkAccent),
child: Theme(
data: Theme.of(context).copyWith(
buttonTheme: ButtonTheme.of(context).copyWith(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap)),
child: OutlineButton(
shape: CircleBorder(),
child: Text('A'),
onPressed: () => {},
),
),
);
}
}
It is pretty much easy, just use
backgroundColor: MaterialStateProperty.all(Colors.colorname),
If you need to Change Colour of Outline Border
OutlineButton(
borderSide: BorderSide(color: kPrimaryColor, width: 1),)
Here's way that you can check the background color of the button.
Remove hightlightColor, and try give some value to highlightElevation property of OutlineButton, then press it, you could see initially it loads orange color.