copyWith() method of ThemeData class in Dart - dart

when trying to understand the functionality of copyWith() method in ThemeData class in Dart
I created the function but when I use it it doesn't change the first value that I have passed before at the opposite of my expectation and I don't understand what I've missed in my code which causes this problem
My function:
enum Color {
RED,
BLUE,
GREEN,
YELLOW,
BLACK,
}
enum Brightness {
LIGHT,
DARK,
}
class ThemeData {
final Color accentColor;
final Color backgroundColor;
final Color buttonColor;
final Brightness brightness;
ThemeData(
{this.accentColor = Color.BLACK,
this.backgroundColor = Color.BLUE,
this.brightness = Brightness.LIGHT,
this.buttonColor = Color.RED});
ThemeData copyWith(
{Color? accentColor,
Color? backgroundColor,
Color? buttonColor,
Brightness? brightness}) {
return ThemeData(
accentColor: accentColor ?? this.accentColor,
backgroundColor: backgroundColor ?? this.backgroundColor,
buttonColor: buttonColor ?? this.buttonColor,
brightness: brightness ?? this.brightness);
}
}
Input:
import 'Copywith.dart';
void main() {
var theme = ThemeData();
theme.copyWith(accentColor: Color.RED);
print(theme.accentColor);
}
Output:
Color.BLACK

This is exactly what copyWith is supposed to do - It does not change the instance upon which it is called, but rather creates a new instance which shares identical field values to the original, other than those values which are specified as arguments to copyWith.
To demonstrate using a tweaked version of your example:
import 'Copywith.dart';
void main() {
var original = ThemeData();
var changed = original.copyWith(accentColor: Color.RED);
print(original.accentColor); // Output: Color.BLACK
print(changed.accentColor); // Output: Color.RED
}

Related

Material 3 Top Bar container color not change on scroll

The top app bar container color not change on scroll, the color keep the same. Working with XML views it works fine, but compose doesn't.
If is a bug or the featured was not ported for compose yet, but if ins't a bug, i'm miss something in the code?
I'm using version 1.0.1 of the material 3 library.
Sample code:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
val uiController = rememberSystemUiController()
uiController.setStatusBarColor(Color.Transparent)
MyApplication5Theme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("k") },
modifier = Modifier.statusBarsPadding(),
)
}
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(it)
) {
items((1..100).toList()) {
Text(it.toString(), modifier = Modifier.padding(8.dp))
}
}
}
}
}
}
}
}
I tried create a simple layout with a top app bar and a lazy column, i expected top app bar container color changes on scroll of the lazy column, but the color keep the same.
The TopAppBar composable has a scrollBehavior argument, which is null be default. If you leave it null, it will not react to scroll events, you have to connect it with your scrollable component. You can do that like this:
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { TopAppBar(scrollBehavior = scrollBehavior, ...) },
) { LazyColumn() {} }

How to change primaryVariant color in compose theme?

I am trying to learn how to set a custom application theme in Jetpack compose but I am struggling to set color of primaryVariant color that doesn't seem to be overridden when I create my custom color pallet.
private val MyLightColorPalette = lightColors(
primary = Green,
primaryVariant = Grey,
onPrimary = Color.White,
secondary = Green,
secondaryVariant = Grey,
onSecondary = Color.White,
error = DarkGrey,
)
This is my color pallet and yet it uses that purple color instead of green. Does somebody know why it still using the default purple color?
Here is the rest of the code:
#Composable
fun MyAppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: #Composable () -> Unit) {
val colors = if (darkTheme) {
MyDarkColorPalette
} else {
MyLightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Scaffold() {
TopBar()
}
}
}
}
}
Compose version that I am using is 1.0.4
If the requirement is just to change the status bar color throughout the app to a solid color, this would also work without Accompanist.
Add this to your activity theme XML code.
<item name="android:statusBarColor" tools:targetApi="l">#color/status_bar</item>

How to customize numberpicker in Flutter?

I implemented numberpicker in my app.
I would like to modify the size of the numbers and the color of both highlighted value and those who are not. I managed to modify the highlighted ones wrapping it in the Theme widget and modifing the accentcolor, but don't know how I can do the other customizations?
Theme(
data: Theme.of(context).copyWith(
accentColor: Colors.red,
),
child: NumberPicker.integer(
initialValue: _currentPickerValue,
minValue: 0,
maxValue: 100,
onChanged: (newValue) =>
setState(() => _currentPickerValue = newValue)))
I digged into the code and here is something that I found
selectedStyle = themeData.textTheme.headline.copyWith(color: themeData.accentColor);
defaultStyle = themeData.textTheme.body1; This is ones which are not highlighted
to change the size or color or any other style attribute modifiy those style.
here is an example code:
final theme = Theme.of(context);
Theme(
data: theme.copyWith(
accentColor: Colors.black,// highlted color
textTheme: theme.textTheme.copyWith(
headline5: theme.textTheme.headline5.copyWith(..), //other highlighted style
bodyText2: theme.textTheme.headline5.copyWith(...), //not highlighted styles
)),
child: NumberPicker.integer(...),
);
Update your number picker package to the latest version.
new NumberPicker.integer(
...,
selectedTextStyle: TextStyle(...),
textStyle: TextStyle(...), //styles of the default text
)
Visit NumberPickec class for study properties.

How to change Text color based on background Image - Flutter

I want to change text (and Icon) colors based on the background image for visibility.
I've tried:
Using palette_generator package, to check the Dominant Color of the background Image and useWhiteForgroundForColor function (returns a bool) from flutter_statusbarcolor package to select black or white color for the my text (and Icon) colors.
The Problem: Sometimes dominant color turns out null. In my tests, this happens with black and white colors and I don't know of any ways to find out which one.
Future<bool> useWhiteTextColor(String imageUrl) async {
PaletteGenerator paletteGenerator =
await PaletteGenerator.fromImageProvider(
NetworkImage(imageUrl),
// Images are square
size: Size(300, 300),
// I want the dominant color of the top left section of the image
region: Offset.zero & Size(40, 40),
);
Color dominantColor = paletteGenerator.dominantColor?.color;
// Here's the problem
// Sometimes dominantColor returns null
// With black and white background colors in my tests
if (dominantColor == null) print('Dominant Color null');
return useWhiteForeground(dominantColor);
}
I found other methods for other languages, but I don't know a way to implement the same method in dart.
Additional note:
My actual code includes some additional complications. I am using a SliverAppBar and here I want to determine the title and icons colors for when the flexibleSpace is expanded. I change their colors when collapsed with the help of the community based on this.
the color class already has a method to calculate luminance, called computeLuminance()
Color textColor = color.computeLuminance() > 0.5 ? Colors.black : Colors.white;
i use the below method to find out which one to be used (either black or white).
Color getTextColor(Color color) {
int d = 0;
// Counting the perceptive luminance - human eye favors green color...
double luminance =
(0.299 * color.red + 0.587 * color.green + 0.114 * color.blue) / 255;
if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font
return Color.fromARGB(color.alpha, d, d, d); }
There are Two ways of getting Text Color based upon the BG Color of Card or Button or Tags.
First One is :
Color txColor = color.computeLuminance() < 0.5 ? Colors.white : Colors.black;
The Second is using Theme , Where user may have dark theme or light theme of device.
import 'dart:math';
import 'package:flutter/material.dart';
class ColorEstimationPage extends StatelessWidget {
Color _randomBackgroundColor() {
List<Color> colors = [Colors.red, Colors.green, Colors.amber, Colors.black];
return colors[Random().nextInt(colors.length)];
}
/// With this you can get the Color either black or white
Color _textColorForBackground(Color backgroundColor) {
if (ThemeData.estimateBrightnessForColor(backgroundColor) ==
Brightness.dark) {
return Colors.white;
}
return Colors.black;
}
#override
Widget build(BuildContext context) {
Color bgColor = _randomBackgroundColor();
return Scaffold(
backgroundColor: bgColor,
body: Center(
child: Text(
"I'm the correct text color!",
style: TextStyle(color: _textColorForBackground(bgColor)),
),
),
);
}
}
You should create the palette generator like this
PaletteGenerator paletteGenerator =
await PaletteGenerator.fromImageProvider(
NetworkImage(imageUrl),
filters: [],
// Images are square
size: Size(300, 300),
// I want the dominant color of the top left section of the image
region: Offset.zero & Size(40, 40),
);
notice the empty list in the filters parameter
Colorful colors
If you have font/background colors that aren't only black and white, you should use some thing else:
final colorDifference = newBackgroundColor.computeLuminance() -
textColor.computeLuminance();
if (colorDifference.abs() < 0.2) {
textColor = textColor.computeLuminance() > 0.5
? Colors.black
: Colors.white;
}
With this, you will only change the font color if necessary (the luminance difference is so less that the colors don't really stand out).
For buttons you can use. this will auto change button color based on background
buttonTheme: ButtonThemeData(
buttonColor: Colors.teal[500],
textTheme: ButtonTextTheme.primary
)

How to pass PointMode into Canvas.drawPoints(..) in Flutter?

I am calling the function drawPoints as below, which follows the API-doc
final paint = new Paint()
..color = Colors.blue[400]
..strokeCap = StrokeCap.round;
var offsetList = [new Offset(2.0, 5.0), new Offset(50.0, 100.0)];
canvas.drawPoints(const PointMode(1), offsetList, paint);
When I pass in const PointMode(1) into the canvas.drawPoints, it throws compiler error. What is the correct way to passing PointMode into this function?
It's correct to use
canvas.drawPoints(PointMode.points, offsetList, paint);
but for the definition you must import 'dart:ui'.
As Alessio Ricci said, you need to import dart:ui. Here is a fuller answer to see everything in context.
How to draw points in Flutter
To paint in Flutter you use the CustomPaint widget. The CustomPaint widget takes a CustomPainter object as a parameter. In that class you have to override the paint method, which gives you a canvas that you can paint on. Here is the code to draw the points in the image above.
#override
void paint(Canvas canvas, Size size) {
final pointMode = ui.PointMode.points;
final points = [
Offset(50, 100),
Offset(150, 75),
Offset(250, 250),
Offset(130, 200),
Offset(270, 100),
];
final paint = Paint()
..color = Colors.black
..strokeWidth = 4
..strokeCap = StrokeCap.round;
canvas.drawPoints(pointMode, points, paint);
}
Notes:
When using low level methods from dart:ui it is a common practice to prefix the classes with ui..
You should stay within the bounds of size.
An Offset is a pair of (dx, dy) doubles, offset from the top left corner, which is (0, 0).
If you don’t set the color, the default is white.
Other options
You can connect the points if you use the PointMode.polygon option.
Using the PointMode.lines option only accepts pairs of lines. Notice that the last point is discarded.
Context
Here is the main.dart code so that you can see it in context. Note the 'dart:ui' as ui import.
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: HomeWidget(),
),
);
}
}
class HomeWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: CustomPaint( // <-- CustomPaint widget
size: Size(300, 300),
painter: MyPainter(),
),
);
}
}
class MyPainter extends CustomPainter { // <-- CustomPainter class
#override
void paint(Canvas canvas, Size size) {
// <-- Insert your painting code here.
}
#override
bool shouldRepaint(CustomPainter old) {
return false;
}
}
See also
See this article for my fuller answer about CustomPaint.
PointMode is an enum, you can not instantiate it. You can check all the available PointModes from here.
To specify PointMode in drawPoints method, you can just change
canvas.drawPoints(const PointMode(1), offsetList, paint);
to
canvas.drawPoints(PointMode.points, offsetList, paint);

Resources