Related
When I created my size config file I encountered this error. I am new to flutter and I was trying to build an E-commerce App. Even though I searched online I didn't find any solution to this problem.
import 'package:flutter/material.dart';
class SizeConfig {
static MediaQueryData _mediaQueryData;
static double screenWidth;
static double screenHeight;
static double defaultSize;
static Orientation orientation;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
orientation = _mediaQueryData.orientation;
}
}
// Get the proportionate height as per screen size
double getProportionateScreenHeight(double inputHeight) {
double screenHeight = SizeConfig.screenHeight;
// 812 is the layout height that designer use
return (inputHeight / 812.0) * screenHeight;
}
// Get the proportionate height as per screen size
double getProportionateScreenWidth(double inputWidth) {
double screenWidth = SizeConfig.screenWidth;
// 375 is the layout width that designer use
return (inputWidth / 375.0) * screenWidth;
}
You've been probably following tutorials from the past year where this was possible, but for now, you have to add "?" at the currently empty variables as "double screenWidth".
In Dart, all variables are non-nullable by default. We cannot assign a null value to a variable because it’ll throw a compilation error, that's why we use the "?" sign.
Also - Appending ! to any variable tells the compiler that the variable is not null, and can be used safely.
The solution you're looking for would probably go something like this:
import 'package:flutter/material.dart';
class SizeConfig {
static MediaQueryData? _mediaQueryData;
static double? screenWidth;
static double? screenHeight;
static double? defaultSize;
static Orientation? orientation;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData!.size.width;
screenHeight = _mediaQueryData!.size.height;
orientation = _mediaQueryData!.orientation;
defaultSize = orientation == Orientation.landscape
? screenHeight! * 0.024
: screenWidth! * 0.024;
}
}
I am trying to create a graph using charts_flutter: ^0.8.1 package in flutter.
Here is my code. I have added SlidingViewport and PanAndZoomBehavior in behaviour.
charts.BarChart(
generateGraphData(months),
barRendererDecorator: charts.BarLabelDecorator<String>(
labelAnchor: charts.BarLabelAnchor.middle,
labelPosition: charts.BarLabelPosition.inside, ),
domainAxis: new charts.OrdinalAxisSpec(viewport: new charts.OrdinalViewport('month', 5),),
animate: false,
rtlSpec: charts.RTLSpec(axisDirection: charts.AxisDirection.reversed),
defaultInteractions: false,
behaviors: [
new charts.SlidingViewport(),
new charts.PanAndZoomBehavior(),
],
),
Is it possible to make the labeltext align vertically like in Horizontal Bar Label Bar? Some thing like the below image. I want to align the label text in the direction of bar chart.
To achieve it you need to create a new class where you need to overwrite one of the internal classes - 'BarRendererDecorator'. In that class there is a method - _decorateVerticalBars which writes the value inside the bars. There is a method call - canvas.drawText() which needs to be fed with one new argument rotation:-math.pi/2. Also to center the text inside the bar need to change the X offset like this - labelX = labelX + (labelElement.measurement.horizontalSliceWidth / 2.5).round();
And then in your decorator call in your graph use the new class you have created. Here is the complete code of the new class. And accept it as answer if it works for you.
import 'dart:math' as math;
import 'package:meta/meta.dart' show required;
import "package:charts_common/common.dart"
show
Color,
GraphicsFactory,
TextDirection,
TextElement,
TextStyle,
ChartCanvas,
TextStyleSpec,
ImmutableBarRendererElement,
BarRendererDecorator;
import "package:charts_common/src/data/series.dart" show AccessorFn;
import "chart_canvas_wrkaround.dart";
import "package:charts_flutter/src/chart_canvas.dart" as Canvasee;
import "package:charts_common/common.dart" as comm;
/* import '../../common/color.dart' show Color;
import '../../common/graphics_factory.dart' show GraphicsFactory;
import '../../common/text_element.dart' show TextDirection, TextElement;
import '../../common/text_style.dart' show TextStyle;
import '../../data/series.dart' show AccessorFn;
import '../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;
import '../common/chart_canvas.dart' show ChartCanvas;
import 'bar_renderer.dart' show ImmutableBarRendererElement;
import 'bar_renderer_decorator.dart' show BarRendererDecorator; */
class BarLabelDecoratorWorkAround<D> extends BarRendererDecorator<D> {
// Default configuration
static const _defaultLabelPosition = BarLabelPosition.auto;
static const _defaultLabelPadding = 5;
static const _defaultHorizontalLabelAnchor = BarLabelAnchor.start;
static const _defaultVerticalLabelAnchor = BarLabelAnchor.end;
static final _defaultInsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.white);
static final _defaultOutsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.black);
static final _labelSplitPattern = '\n';
static final _defaultMultiLineLabelPadding = 2;
/// Configures [TextStyleSpec] for labels placed inside the bars.
final TextStyleSpec insideLabelStyleSpec;
/// Configures [TextStyleSpec] for labels placed outside the bars.
final TextStyleSpec outsideLabelStyleSpec;
/// Configures where to place the label relative to the bars.
final BarLabelPosition labelPosition;
/// For labels drawn inside the bar, configures label anchor position.
final BarLabelAnchor labelAnchor;
/// Space before and after the label text.
final int labelPadding;
BarLabelDecoratorWorkAround(
{TextStyleSpec insideLabelStyleSpec,
TextStyleSpec outsideLabelStyleSpec,
this.labelAnchor = null,
this.labelPosition = _defaultLabelPosition,
this.labelPadding = _defaultLabelPadding})
: insideLabelStyleSpec = insideLabelStyleSpec ?? _defaultInsideLabelStyle,
outsideLabelStyleSpec =
outsideLabelStyleSpec ?? _defaultOutsideLabelStyle;
#override
void decorate(Iterable<ImmutableBarRendererElement<D>> barElements,
comm.ChartCanvas canvas, GraphicsFactory graphicsFactory,
{#required math.Rectangle drawBounds,
#required double animationPercent,
#required bool renderingVertically,
bool rtl = false}) {
// Only decorate the bars when animation is at 100%.
if (animationPercent != 1.0) {
return;
}
/* final newCanvas = canvas as Canvasee.ChartCanvas;
final canvee =
ChartCanvasWorkAround(newCanvas.canvas, newCanvas.graphicsFactory); */
if (renderingVertically) {
_decorateVerticalBars(
barElements, canvas, graphicsFactory, drawBounds, rtl);
} else {
_decorateHorizontalBars(
barElements, canvas, graphicsFactory, drawBounds, rtl);
}
}
void _decorateVerticalBars(
Iterable<ImmutableBarRendererElement<D>> barElements,
ChartCanvas canvas,
GraphicsFactory graphicsFactory,
math.Rectangle drawBounds,
bool rtl) {
// Create [TextStyle] from [TextStyleSpec] to be used by all the elements.
// The [GraphicsFactory] is needed so it can't be created earlier.
final insideLabelStyle =
_getTextStyle(graphicsFactory, insideLabelStyleSpec);
final outsideLabelStyle =
_getTextStyle(graphicsFactory, outsideLabelStyleSpec);
for (var element in barElements) {
final labelFn = element.series.labelAccessorFn;
final datumIndex = element.index;
final label = (labelFn != null) ? labelFn(datumIndex) : null;
// If there are custom styles, use that instead of the default or the
// style defined for the entire decorator.
final datumInsideLabelStyle = _getDatumStyle(
element.series.insideLabelStyleAccessorFn,
datumIndex,
graphicsFactory,
defaultStyle: insideLabelStyle);
final datumOutsideLabelStyle = _getDatumStyle(
element.series.outsideLabelStyleAccessorFn,
datumIndex,
graphicsFactory,
defaultStyle: outsideLabelStyle);
// Skip calculation and drawing for this element if no label.
if (label == null || label.isEmpty) {
continue;
}
var labelElements = label
.split(_labelSplitPattern)
.map((labelPart) => graphicsFactory.createTextElement(labelPart));
final bounds = element.bounds;
// Get space available inside and outside the bar.
final totalPadding = labelPadding * 2;
final insideBarHeight = bounds.height - totalPadding;
final outsideBarHeight = drawBounds.height - bounds.height - totalPadding;
var calculatedLabelPosition = labelPosition;
if (calculatedLabelPosition == BarLabelPosition.auto) {
// For auto, first try to fit the text inside the bar.
labelElements = labelElements.map(
(labelElement) => labelElement..textStyle = datumInsideLabelStyle);
final labelMaxWidth = labelElements
.map(
(labelElement) => labelElement.measurement.horizontalSliceWidth)
.fold(0, (max, current) => max > current ? max : current);
// Total label height depends on the label element's text style.
final totalLabelHeight = _getTotalLabelHeight(labelElements);
// A label fits if the length and width of the text fits.
calculatedLabelPosition =
totalLabelHeight < insideBarHeight && labelMaxWidth < bounds.width
? BarLabelPosition.inside
: BarLabelPosition.outside;
}
// Set the max width, text style, and text direction.
labelElements = labelElements.map((labelElement) => labelElement
..textStyle = calculatedLabelPosition == BarLabelPosition.inside
? datumInsideLabelStyle
: datumOutsideLabelStyle
..maxWidth = bounds.height * 100
..textDirection = rtl ? TextDirection.rtl : TextDirection.ltr);
// Total label height depends on the label element's text style.
final totalLabelHeight = _getTotalLabelHeight(labelElements);
var labelsDrawn = 0;
for (var labelElement in labelElements) {
// Calculate the start position of label based on [labelAnchor].
int labelY;
final labelHeight = labelElement.measurement.verticalSliceWidth.round();
final offsetHeight =
(labelHeight + _defaultMultiLineLabelPadding) * labelsDrawn;
if (calculatedLabelPosition == BarLabelPosition.inside) {
final _labelAnchor = labelAnchor ?? _defaultVerticalLabelAnchor;
switch (_labelAnchor) {
case BarLabelAnchor.end:
labelY = bounds.top + labelPadding + offsetHeight;
break;
case BarLabelAnchor.middle:
labelY = (bounds.bottom -
bounds.height / 2 -
totalLabelHeight / 2 +
offsetHeight)
.round();
break;
case BarLabelAnchor.start:
labelY = bounds.bottom -
labelPadding -
totalLabelHeight +
offsetHeight;
break;
}
} else {
// calculatedLabelPosition == LabelPosition.outside
labelY = bounds.top - labelPadding - totalLabelHeight + offsetHeight;
}
// Center the label inside the bar.
int labelX = (bounds.left +
bounds.width / 2 -
labelElement.measurement.horizontalSliceWidth / 2)
.round();
labelX = labelX +
(labelElement.measurement.horizontalSliceWidth / 2.5).round();
canvas.drawText(labelElement, labelX, labelY, rotation: -math.pi / 2);
labelsDrawn += 1;
}
}
}
void _decorateHorizontalBars(
Iterable<ImmutableBarRendererElement<D>> barElements,
ChartCanvas canvas,
GraphicsFactory graphicsFactory,
math.Rectangle drawBounds,
bool rtl) {
// Create [TextStyle] from [TextStyleSpec] to be used by all the elements.
// The [GraphicsFactory] is needed so it can't be created earlier.
final insideLabelStyle =
_getTextStyle(graphicsFactory, insideLabelStyleSpec);
final outsideLabelStyle =
_getTextStyle(graphicsFactory, outsideLabelStyleSpec);
for (var element in barElements) {
final labelFn = element.series.labelAccessorFn;
final datumIndex = element.index;
final label = (labelFn != null) ? labelFn(datumIndex) : null;
// If there are custom styles, use that instead of the default or the
// style defined for the entire decorator.
final datumInsideLabelStyle = _getDatumStyle(
element.series.insideLabelStyleAccessorFn,
datumIndex,
graphicsFactory,
defaultStyle: insideLabelStyle);
final datumOutsideLabelStyle = _getDatumStyle(
element.series.outsideLabelStyleAccessorFn,
datumIndex,
graphicsFactory,
defaultStyle: outsideLabelStyle);
// Skip calculation and drawing for this element if no label.
if (label == null || label.isEmpty) {
continue;
}
final bounds = element.bounds;
// Get space available inside and outside the bar.
final totalPadding = labelPadding * 2;
final insideBarWidth = bounds.width - totalPadding;
final outsideBarWidth = drawBounds.width - bounds.width - totalPadding;
final labelElement = graphicsFactory.createTextElement(label);
var calculatedLabelPosition = labelPosition;
if (calculatedLabelPosition == BarLabelPosition.auto) {
// For auto, first try to fit the text inside the bar.
labelElement.textStyle = datumInsideLabelStyle;
// A label fits if the space inside the bar is >= outside bar or if the
// length of the text fits and the space. This is because if the bar has
// more space than the outside, it makes more sense to place the label
// inside the bar, even if the entire label does not fit.
calculatedLabelPosition = (insideBarWidth >= outsideBarWidth ||
labelElement.measurement.horizontalSliceWidth < insideBarWidth)
? BarLabelPosition.inside
: BarLabelPosition.outside;
}
// Set the max width and text style.
if (calculatedLabelPosition == BarLabelPosition.inside) {
labelElement.textStyle = datumInsideLabelStyle;
labelElement.maxWidth = insideBarWidth;
} else {
// calculatedLabelPosition == LabelPosition.outside
labelElement.textStyle = datumOutsideLabelStyle;
labelElement.maxWidth = outsideBarWidth;
}
// Only calculate and draw label if there's actually space for the label.
if (labelElement.maxWidth > 0) {
// Calculate the start position of label based on [labelAnchor].
int labelX;
if (calculatedLabelPosition == BarLabelPosition.inside) {
final _labelAnchor = labelAnchor ?? _defaultHorizontalLabelAnchor;
switch (_labelAnchor) {
case BarLabelAnchor.middle:
labelX = (bounds.left +
bounds.width / 2 -
labelElement.measurement.horizontalSliceWidth / 2)
.round();
labelElement.textDirection =
rtl ? TextDirection.rtl : TextDirection.ltr;
break;
case BarLabelAnchor.end:
case BarLabelAnchor.start:
final alignLeft = rtl
? (_labelAnchor == BarLabelAnchor.end)
: (_labelAnchor == BarLabelAnchor.start);
if (alignLeft) {
labelX = bounds.left + labelPadding;
labelElement.textDirection = TextDirection.ltr;
} else {
labelX = bounds.right - labelPadding;
labelElement.textDirection = TextDirection.rtl;
}
break;
}
} else {
// calculatedLabelPosition == LabelPosition.outside
labelX = bounds.right + labelPadding;
labelElement.textDirection = TextDirection.ltr;
}
// Center the label inside the bar.
final labelY = (bounds.top +
(bounds.bottom - bounds.top) / 2 -
labelElement.measurement.verticalSliceWidth / 2)
.round();
canvas.drawText(labelElement, labelX, labelY);
}
}
}
/// Helper function to get the total height for a group of labels.
/// This includes the padding in between the labels.
int _getTotalLabelHeight(Iterable<TextElement> labelElements) =>
(labelElements.first.measurement.verticalSliceWidth *
labelElements.length)
.round() +
_defaultMultiLineLabelPadding * (labelElements.length - 1);
// Helper function that converts [TextStyleSpec] to [TextStyle].
TextStyle _getTextStyle(
GraphicsFactory graphicsFactory, TextStyleSpec labelSpec) {
return graphicsFactory.createTextPaint()
..color = labelSpec?.color ?? Color.black
..fontFamily = labelSpec?.fontFamily
..fontSize = labelSpec?.fontSize ?? 12
..lineHeight = labelSpec?.lineHeight;
}
/// Helper function to get datum specific style
TextStyle _getDatumStyle(AccessorFn<TextStyleSpec> labelFn, int datumIndex,
GraphicsFactory graphicsFactory,
{TextStyle defaultStyle}) {
final styleSpec = (labelFn != null) ? labelFn(datumIndex) : null;
return (styleSpec != null)
? _getTextStyle(graphicsFactory, styleSpec)
: defaultStyle;
}
}
/// Configures where to place the label relative to the bars.
enum BarLabelPosition {
/// Automatically try to place the label inside the bar first and place it on
/// the outside of the space available outside the bar is greater than space
/// available inside the bar.
auto,
/// Always place label on the outside.
outside,
/// Always place label on the inside.
inside,
}
/// Configures where to anchor the label for labels drawn inside the bars.
enum BarLabelAnchor {
/// Anchor to the measure start.
start,
/// Anchor to the middle of the measure range.
middle,
/// Anchor to the measure end.
end,
}
I'm trying to draw an image file into the canvas to compose my widget in Flutter.
I did follow canvas documentation but a did not success. O Image docs, thay say that:
To obtain an Image object, use instantiateImageCodec.
I did try use instantiateImageCodec method, but i just get a Codec instance, not a Image
How is the right way to get an instance of ui.Image to draw on canvas using canvas.drawImage
Here is a snnipet of my code:
Future<ui.Codec> _loadImage(AssetBundleImageKey key) async {
final ByteData data = await key.bundle.load(key.name);
if (data == null)
throw 'Unable to read data';
return await ui.instantiateImageCodec(data.buffer.asUint8List());
}
final Paint paint = new Paint()
..color = Colors.yellow
..strokeWidth = 2.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
var sunImage = new ExactAssetImage("res/images/grid_icon.png");
sunImage.obtainKey(new ImageConfiguration()).then((AssetBundleImageKey key){
_loadImage(key).then((ui.Codec codec){
print("frameCount: ${codec.frameCount.toString()}");
codec.getNextFrame().then((info){
print("image: ${info.image.toString()}");
print("duration: ${info.duration.toString()}");
canvas.drawImage(info.image, size.center(Offset.zero), paint);
});
});
});
This simple utility method returns a Future<UI.Image> given the image asset's path:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as UI;
import 'package:flutter/services.dart';
Future<UI.Image> loadUiImage(String imageAssetPath) async {
final ByteData data = await rootBundle.load(imageAssetPath);
final Completer<UI.Image> completer = Completer();
UI.decodeImageFromList(Uint8List.view(data.buffer), (UI.Image img) {
return completer.complete(img);
});
return completer.future;
}
ui.Codec has a method getNextFrame() which returns a Future<FrameInfo> (you should probably have logic around how many frames but if you know it's always a normal picture you could skip that.) FrameInfo has an image property which is the Image you need.
EDIT: looking at the code you have in the post, it's not clear where you're doing what. Is that all defined within the CustomPainter.paint method? If so, you'd definitely have issues because you can only use the canvas for the duration of the paint call; you should not retain any references to it outside of the function (which would include any asynchronous call).
I'd recommend using a FutureBuilder so that you only draw on the canvas once you've added the image.
That would look something like this:
Future<Image> _loadImage(AssetBundleImageKey key) async {
final ByteData data = await key.bundle.load(key.name);
if (data == null)
throw 'Unable to read data';
var codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
// add additional checking for number of frames etc here
var frame = await codec.getNextFrame();
return frame.image;
}
new FutureBuilder<Image>(
future: loadImage(....), // a Future<String> or null
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Text('Image loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
// ImageCanvasDrawer would be a (most likely) statless widget
// that actually makes the CustomPaint etc
return new ImageCanvasDrawer(image: snapshot.data)
}
},
)
Simple example, based on idea from Simon
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Future<ui.Image> loadImage(String imageName) async {
final data = await rootBundle.load('assets/image/$imageName');
return decodeImageFromList(data.buffer.asUint8List());
}
late ui.Image image;
void main() async {
image = await loadImage('image.jpg');
runApp(App());
}
// canvas.drawImage(image, Offset.zero, Paint());
class ImagePainter extends CustomPainter {
List<ui.Image> images = new List<ui.Image>();
ImagePainter(
{Key key,
#required this.noOfSlice,
#required this.images,
#required this.rotation,
this.boxfit = BoxFit.contain})
:
// : path = new Path()
// ..addOval(new Rect.fromCircle(
// center: new Offset(75.0, 75.0),
// radius: 40.0,
// )),
tickPaint = new Paint() {
tickPaint.strokeWidth = 2.5;
}
final int noOfSlice;
final tickPaint;
final BoxFit boxfit;
ui.ImageByteFormat img;
ui.Rect rect, inputSubrect, outputSubrect;
Size imageSize;
FittedSizes sizes;
double radius,
rotation = 0.0,
_x,
_y,
_angle,
_radiun,
_baseLength,
_imageCircleradius,
_incircleRadius,
_imageOffset = 0.0,
_imageSizeConst = 0.0;
#override
void paint(ui.Canvas canvas, ui.Size size) {
print("image data:: $images");
radius = size.width / 2;
_angle = 360 / (noOfSlice * 2.0);
_radiun = (_angle * pi) / 180;
_baseLength = 2 * radius * sin(_radiun);
_incircleRadius = (_baseLength / 2) * tan(_radiun);
if (noOfSlice == 4) {
_imageOffset = 30.0;
_imageSizeConst = 30.0;
_x = 8.60;
_y = 4.10;
} else if (noOfSlice == 6) {
_imageOffset = 20.0;
_x = 10.60;
_y = 5.60;
} else if (noOfSlice == 8) {
_imageOffset = 40.0;
_imageSizeConst = 30.0;
_x = 12.90;
_y = 6.60;
}
//print("circle radisu:: $_incircleRadius");
canvas.save();
canvas.translate(size.width / 2, size.height / 2);
canvas.rotate(-rotation);
int incr = 0;
rect = ui.Offset((size.width / _x), size.width / _y) & new Size(0.0, 0.0);
imageSize = new Size(size.width * 1.5, size.width * 1.5);
sizes = applyBoxFit(
boxfit,
imageSize,
new Size(size.width / 2 * .50 + _incircleRadius * .8,
size.width / 2 * .50 + _incircleRadius * .8));
inputSubrect =
Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
outputSubrect = Alignment.center.inscribe(sizes.destination, rect);
if (images.length == noOfSlice && images.isNotEmpty)
for (var i = 1; i <= noOfSlice * 2; ++i) {
if (i % 2 != 0) {
canvas.drawLine(
new Offset(0.0, 0.0),
new Offset(0.0, size.width / 2 - 4.2),
tickPaint,
);
} else {
canvas.save();
canvas.translate(-0.0, -((size.width) / 2.2));
ui.Image image = images[incr];
if (image != null) {
canvas.drawImageRect(
image, inputSubrect, outputSubrect, new Paint());
}
canvas.restore();
incr++;
}
canvas.rotate(2 * pi / (noOfSlice * 2.0));
}
canvas.restore();
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
i write this code and i don't know how to fix all error of this code but this code work correctly in pc mode but give error in android mode this is my code :
var background : Texture2D;
var splash : Texture2D;
var font : Font;
private var showADPresents = 3.0;
var size = null;
static var virtualScreen : Vector2 = Vector2(800, 600);
function Update()
{
showADPresents -= Time.deltaTime;
if (Application.CanStreamedLevelBeLoaded(1) && Input.anyKeyDown)
Application.LoadLevel(1);
}
function OnGUI()
{
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3(Screen.width / virtualScreen.x, Screen.height / virtualScreen.y, 1));
GUI.DrawTexture(Rect(0, 0, virtualScreen.x, virtualScreen.y), splash);
if (showADPresents > 0)
{
var alpha = Mathf.Clamp01(showADPresents);
var color = Color.white;
color.a = alpha;
GUI.color = color;
GUI.DrawTexture(Rect(0, 0, virtualScreen.x, virtualScreen.y), background);
var presentsStyle = new GUIStyle(GUI.skin.label);
presentsStyle.font = font;
presentsStyle.fontSize = 48;
size = 300;
color = Color.black;
color.a = alpha;
GUI.color = color;
GUI.Label(Rect(( virtualScreen.x - size) * 0.5, (virtualScreen.y - size) * 0.5, size, size), "Autodesk Presents:", presentsStyle);
}
else
{
var notificationStyle = new GUIStyle(GUI.skin.label);
notificationStyle.font = font;
notificationStyle.fontSize = 16;
GUI.color = Color.black;
var content = null;
if (Application.CanStreamedLevelBeLoaded(1))
content = new GUIContent("Click Screen to Continue");
else
content = new GUIContent("Loading...");
size = notificationStyle.CalcSize(content);
GUI.Label(Rect((virtualScreen.x - size.x) * 0.5, virtualScreen.y - size.y - 80, size.x, size.y),
content, notificationStyle);
}
}
and unity give me this error i cant solve this error plz help to me help :'(
http://upload.ghashang.com/images/gm214joveg1z354rkli.jpg
plz Belief i cant solve this error plz help me
plz solve all error
This is because size is not a static type. It is dynamic, and because there is no operator for a object subtracted from a float, this error is thrown. You have two options. One, you can cast as a float before you subtract.
GUI.Label(Rect(( virtualScreen.x - (float)size) * 0.5, (virtualScreen.y - (float)size) * 0.5, size, size), "Autodesk Presents:", presentsStyle);
The other, is to declare size as a float or int in the declaration.
float size = 0.0f;
//or
int size = 0;
However, later you try to reference size as though it was a Rect, which causes other errors. I would a)declare size as a Rect b)access the respective members of size. Your code will look like:
Rect size;
...
//remove the size = 300; line and replace it with a constructor
GUI.Label(Rect(( virtualScreen.x - size.x) * 0.5, (virtualScreen.y - size.y) * 0.5, size, size), "Autodesk Presents:", presentsStyle);
This will solve your issue, and I recommend you read more about static classes
I'm looking for a way to dynamically convert a String like "30dp" into an int that resembles the amount of pixels. This would mean that StaticClass.theMethodImSearchingFor("16px") would return 16.
My application will get these Strings dynamically and I need a way to store it as a pixel value to use later.
I've already looked at the Android Source code, mainly the classes Resources, TypedArray and TypedValue, but I couldn't find anything useful.
If you need the android resource dimen as a int you can do this in your code:
context.getResources().getDimensionPixelSize(R.dimen.your_dimen_res);
I needed this myself so I wrote a class to handle it. All code in this answer is licensed under Apache License 2.0. Enjoy.
There are two static methods that mimic two TypedValue methods. DimensionConverter.stringToDimension() mimics TypedValue.complexToDimension. DimensionConverter.stringToDimensionPixelSize() mimics TypedValue.complexToDimensionPixelSize.
Supports all current units. Will accept dimension strings like "33sp", " 44 dp " and throw an exception for bad formats.
Simple to use:
String dimension = "38dp";
Log.i(TAG, "Testing: " + dimension);
try {
Log.i(TAG, "Converts to: " + DimensionConverter.stringToDimension(dimension, resources.getDisplayMetrics()));
} catch (NumberFormatException exception) {
Log.i(TAG, "Unable to convert.");
}
Class here:
public class DimensionConverter {
// -- Initialize dimension string to constant lookup.
public static final Map<String, Integer> dimensionConstantLookup = initDimensionConstantLookup();
private static Map<String, Integer> initDimensionConstantLookup() {
Map<String, Integer> m = new HashMap<String, Integer>();
m.put("px", TypedValue.COMPLEX_UNIT_PX);
m.put("dip", TypedValue.COMPLEX_UNIT_DIP);
m.put("dp", TypedValue.COMPLEX_UNIT_DIP);
m.put("sp", TypedValue.COMPLEX_UNIT_SP);
m.put("pt", TypedValue.COMPLEX_UNIT_PT);
m.put("in", TypedValue.COMPLEX_UNIT_IN);
m.put("mm", TypedValue.COMPLEX_UNIT_MM);
return Collections.unmodifiableMap(m);
}
// -- Initialize pattern for dimension string.
private static final Pattern DIMENSION_PATTERN = Pattern.compile("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");
public static int stringToDimensionPixelSize(String dimension, DisplayMetrics metrics) {
// -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics).
InternalDimension internalDimension = stringToInternalDimension(dimension);
final float value = internalDimension.value;
final float f = TypedValue.applyDimension(internalDimension.unit, value, metrics);
final int res = (int)(f+0.5f);
if (res != 0) return res;
if (value == 0) return 0;
if (value > 0) return 1;
return -1;
}
public static float stringToDimension(String dimension, DisplayMetrics metrics) {
// -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics).
InternalDimension internalDimension = stringToInternalDimension(dimension);
return TypedValue.applyDimension(internalDimension.unit, internalDimension.value, metrics);
}
private static InternalDimension stringToInternalDimension(String dimension) {
// -- Match target against pattern.
Matcher matcher = DIMENSION_PATTERN.matcher(dimension);
if (matcher.matches()) {
// -- Match found.
// -- Extract value.
float value = Float.valueOf(matcher.group(1)).floatValue();
// -- Extract dimension units.
String unit = matcher.group(3).toLowerCase();
// -- Get Android dimension constant.
Integer dimensionUnit = dimensionConstantLookup.get(unit);
if (dimensionUnit == null) {
// -- Invalid format.
throw new NumberFormatException();
} else {
// -- Return valid dimension.
return new InternalDimension(value, dimensionUnit);
}
} else {
// -- Invalid format.
throw new NumberFormatException();
}
}
private static class InternalDimension {
float value;
int unit;
public InternalDimension(float value, int unit) {
this.value = value;
this.unit = unit;
}
}
}
Thanks to mindriot, works great and is a lifesaver.
Here it is in C#
note: If for some reason you cannot use Integer types (vs int's) (which will be Java Integers in Mono), I left the code that uses C# int's in comments everywhere that is associated. Just swap the commented int code for the uncommented Integer code everywhere you see it.
Had to use Integer so that it can be determined if there is no match when checking the Dictionary/Map (TryGetValue) of suffixs (in which case it'll be null; if ints are used instead, then the out param will be 0, which corresponds to the first entry of the map, which obviously doesn't work. Too bad TryGetValue didn't return a negeative value upon no match!?).
public class DimensionConverter
{
// -- Initialize dimension string to constant lookup.
//public static readonly Dictionary<string, int> dimensionConstantLookup = initDimensionConstantLookup();
public static readonly Dictionary<string, Integer> dimensionConstantLookup = initDimensionConstantLookup();
//private static Dictionary<string, int> initDimensionConstantLookup()
private static Dictionary<string, Integer> initDimensionConstantLookup()
{
//Dictionary<string, int> m = new Dictionary<string, int>();
Dictionary<string, Integer> m = new Dictionary<string, Integer>();
m.Add("px", (Integer)((int)ComplexUnitType.Px));
m.Add("dip", (Integer)((int)ComplexUnitType.Dip));
m.Add("dp", (Integer)((int)ComplexUnitType.Dip));
m.Add("sp", (Integer)((int)ComplexUnitType.Sp));
m.Add("pt", (Integer)((int)ComplexUnitType.Pt));
m.Add("in", (Integer)((int)ComplexUnitType.In));
m.Add("mm", (Integer)((int)ComplexUnitType.Mm));
/*m.Add("px", (int)ComplexUnitType.Px);
m.Add("dip", (int)ComplexUnitType.Dip);
m.Add("dp", (int)ComplexUnitType.Dip);
m.Add("sp", (int)ComplexUnitType.Sp);
m.Add("pt", (int)ComplexUnitType.Pt);
m.Add("in", (int)ComplexUnitType.In);
m.Add("mm", (int)ComplexUnitType.Mm);*/
return m;
}
// -- Initialize pattern for dimension string.
private static Regex DIMENSION_PATTERN = new Regex("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$");
public static int stringToDimensionPixelSize(string dimension, DisplayMetrics metrics)
{
// -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics).
InternalDimension internalDimension = stringToInternalDimension(dimension);
float value = internalDimension.value;
//float f = TypedValue.ApplyDimension((ComplexUnitType)internalDimension.unit, value, metrics);
float f = TypedValue.ApplyDimension((ComplexUnitType)(int)internalDimension.unit, value, metrics);
int res = (int)(f + 0.5f);
if (res != 0) return res;
if (value == 0) return 0;
if (value > 0) return 1;
return -1;
}
public static float stringToDimension(String dimension, DisplayMetrics metrics)
{
// -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics).
InternalDimension internalDimension = stringToInternalDimension(dimension);
//return TypedValue.ApplyDimension((ComplexUnitType)internalDimension.unit, internalDimension.value, metrics);
return TypedValue.ApplyDimension((ComplexUnitType)(int)internalDimension.unit, internalDimension.value, metrics);
}
private static InternalDimension stringToInternalDimension(String dimension)
{
// -- Match target against pattern.
MatchCollection matches = DIMENSION_PATTERN.Matches(dimension);
if (matches.Count > 0)
{
Match matcher = matches[0];
// -- Match found.
// -- Extract value.
float value = Float.ValueOf(matcher.Groups[1].Value).FloatValue();
// -- Extract dimension units.
string unit = matcher.Groups[3].ToString().ToLower();
// -- Get Android dimension constant.
//int dimensionUnit;
Integer dimensionUnit;
dimensionConstantLookup.TryGetValue(unit, out dimensionUnit);
//if (dimensionUnit == ????)
if (dimensionUnit == null)
{
// -- Invalid format.
throw new NumberFormatException();
}
else
{
// -- Return valid dimension.
return new InternalDimension(value, dimensionUnit);
}
}
else
{
// -- Invalid format.
throw new NumberFormatException();
}
}
private class InternalDimension
{
public float value;
//public int unit;
public Integer unit;
//public InternalDimension(float value, int unit)
public InternalDimension(float value, Integer unit)
{
this.value = value;
this.unit = unit;
}
}
}
This link might help you figure out your conversion, however since pixels and density-independent pixels are not a 1:1 matchup, expect some (minor) distortions.
These units (dp) are relative to a 160 dpi screen, so one dp is one
pixel on a 160 dpi screen. The ratio of dp-to-pixel will change with
the screen density, but not necessarily in direct proportion.