When using Xamarin, what is the best or most accepted method of handling changes in orientation?
I have a carousel page which rotates through 5 content pages (the same page, just different text/images), in the content pages I have a 6 row grid, each row containing either an image, text or a button.
When changing from portrait to landscape I reset the size and padding of these within OnSizeAllocated. This seems to work randomly for 3 out of 5 content pages, the text in the other 2 will be out of position, and it's not always the same 3 that work either.
I'm guessing there's a better way to do this than manually resize things?
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height); //must be called
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
//reconfigure layout
if (width > height)
{
img.HeightRequest = 62.5;
img.WidthRequest = 62.5;
logo.HeightRequest = 52.5;
logo.WidthRequest = 142.27;
headerStack.Padding = new Thickness(0, -60, 0, 0);
txtStack.Padding = new Thickness(20, -60, 20, 0);
sIndicator.Padding = new Thickness(20, 0, 20, 100);
sButton.Padding = new Thickness(0, -40, 0, 0);
}
else
{
img.WidthRequest = 250;
img.HeightRequest = 250;
logo.HeightRequest = 70;
logo.WidthRequest = 189.7;
headerStack.Padding = new Thickness(20, 40, 20, 0);
txtStack.Padding = new Thickness(20, 0, 20, 0);
sIndicator.Padding = new Thickness(20, 25, 20, 0);
}
}
}
With a few tweaks to what I was setting I got this working just fine, would still be interested in other peoples' views on how they do it.
Related
I generate the scene above using the OnDraw method below:
protected override void OnDraw(SKCanvas canvas, int width, int height)
{
int i = 0;
int step = 0;
List<SKRect> rects = new List<SKRect>();
// get the 2D equivalent of the 3D matrix
var rotationMatrix = rotationView.Matrix;
// get the properties of the rectangle
var length = Math.Min(width / 6, height / 6);
canvas.Clear(EffectMedia.Colors.XamarinLightBlue);
foreach (var n in numbers)
{
var rect = new SKRect(0 + step, 0, 100 + step, 100);
rects.Add(rect);
step += 120;
}
//var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;
var paint = new SKPaint
{
Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
// first do 2D translation to the center of the screen
canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);
// The following line is disabled because it makes the whole canvas rotate!
// canvas.Concat(ref rotationMatrix);
foreach (var n in numbers)
{
canvas.RotateDegrees((float)-3);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
var shadow = SKShader.CreateLinearGradient(
new SKPoint(0, 0), new SKPoint(0, length * 2),
new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
null,
SKShaderTileMode.Clamp);
var paintShadow = new SKPaint
{
Shader = shadow,
Style = SKPaintStyle.Fill,
IsAntialias = true,
BlendMode = SKBlendMode.SoftLight
};
foreach (var r in rects)
{
r.Offset(0, 105);
canvas.DrawRoundRect(r, 30, 30, paintShadow);
}
i++;
}
}
The idea is to make all those rounded boxes rotate (vertically) around their own axis.
I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes ( canvas.Concat(ref rotationMatrix); makes the whole canvas rotate [*]).
Do you have any hint on how that can be achieved?
Note [*]: there's a call to rotationView.RotateYDegrees(5) every X milliseconds to update the rotationMatrix used by OnDraw.
This is what I'd like to achieve, any hints / directions would be really appreciated... :-)
The following piece of code rotates those shapes around their Z-axis:
canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();
Thanks
I am creating a simulator using P5.js. Within the simulator, I need a green box, however it does not seem to be appearing. The code is below:
var outputs = [];
function setup() {
createCanvas(600, 400, WEBGL);
background(200);
for (var i = 0; i < 1; i++) {
drop = new Water(width / 2, height / 2, 0, 1);
outputs[i] = drop;
}
}
function draw() {
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
for (var i = 0; i < outputs.length; i++) {
outputs[i].update();
}
background(200);
}
Here is the water class:
function Water(x_, y_, z_, yVel_) {
this.r = random(0.25, 1);
this.xOff = random(-(this.r / 10), (this.r / 10));
this.zOff = random(-(this.r / 10), (this.r / 10));
this.x = x_ + this.xOff;
this.y = y_;
this.z = z_ + this.zOff;
this.yVel = yVel_;
this.pos = createVector(this.x, this.y, this.z);
this.show = function() {
push();
translate(this.pos.x, this.pos.y, this.pos.z);
noStroke();
fill(0, 0, 255);
sphere(this.r * 2);
pop();
}
this.update = function() {
this.vel = createVector(random(-(this.r / 10), (this.r / 10)),
this.yVel, random(-(this.r / 10),
(this.r / 10)));
this.pos.add(this.vel);
this.show();
}
}
This is a web based simulation, with another module which appears to be working fine.
Any help would be greatly appreciated. Thanks in advance!
Removing the parts that require the Water class, and moving the background function call to the top of draw, it seems to work just fine.
So, the problem is
Either that you forgot to put background on top
Or something's wrong with the Water class.
Here's your code with the mentioned problems fixed.
var outputs = [];
function setup() {
createCanvas(600, 400, WEBGL);
}
function draw() {
background(200);
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.min.js"></script>
Its not rendering because you're background is over your scene
function draw() {
background(200);
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
for (var i = 0; i < outputs.length; i++) {
outputs[i].update();
}
}
What your doing is drawing the box and the drops and you cover it all up with your background
if you don't have a background you will see how p5.js renders animation
p5.js not moving it, its just looping through draw every frame and the background covers up the previous frame
I need to rotate the image 180 degrees, but when I add in the rotate code, the image becomes a square.
var moulding_matte_canvas_height = [],
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
width = 5.171363636363637,
opening_i = 0,
rotate = 180 * Math.PI / 180,
i = 2;
moulding_matte_canvas_height[0] = 225;
canvas.width = 285;
canvas.height = 335;
img = new Image();
img.src = 'http://www.asa.tframes.org:1881/system/components/compimg/80ac89fad42cf14561b641df241bf406/pattern';
function moulding_get_segment_width(img_width, opening_i)
{
return 175;
}
//
$(img).on("load", function() {
ctx.save();
ctx.translate(width, moulding_matte_canvas_height[opening_i]);
//ctx.rotate(rotate);
//ctx.rotate(Math.PI);
ctx.drawImage(img, 0, 0, moulding_get_segment_width(img.width, i), width);
ctx.restore();
//
});
$("#mattes").append(canvas); /*appending the canvas*/
http://fiddle.jshell.net/onpa628e/1/
(Whitespace is intentional due to other elements that will be drawn and the red next to the image is just for clarity)
Without rotate:
With rotate:
Expected:
Your image looks like a square, because it's only showing a tiny portion on the canvas. This happens because translate is only moving ~ 5px (your "width" variable) on the x axis.
Here's your example modified with a higher x value.
I want to get the size of my label. It doesn't work like it should. It gets the size, but only for the standard fontsize. But I'm not using the standard one.
Could this be a problem: "Unable to find style 'FontStyle' in skin 'GameSkin' Repaint UnityEngine.GUISkin:GetStyle(String)"
I have this code:
string test ="test";
Vector2 SizeVect;
public int FontSize = 1;
Rect TestRect:
void OnGUI(){
TestRect = new Rect(...);
FontStyle = new GUIStyle();
FontStyle.fontSize = FontSize;
SizeVect = GUI.skin.GetStyle("FontStyle").CalcSize(new GUIContent(test));
GUI.Label(TestRect, test, FontStyle);
}
Try below code, documentation here.
SizeVect = GUI.skin.label.CalcSize(new GUIContent(test));
Update: When font size is changed, this also works.
private float fontSize = 12;
void OnGUI()
{
fontSize = GUI.HorizontalSlider(new Rect(50, 50, 200, 20), fontSize, 8, 64);
var str = "ABCDEFG";
var style = GUI.skin.label;
style.fontSize = (int)fontSize;
var size = style.CalcSize(new GUIContent(str));
var rect = new Rect(100, 100, size.x, size.y);
GUI.Label(rect,str );
GUI.Box(rect,"");
}
See snapshot below:
I'm creating graphics by the code and placing them into a Bitmap. But they are higher than this Bitmap container.
import flash.display.*;
function getLine(){
var containerWidh:Number =enter code here 300;
var containerHeight:Number = 300;
var borderWidt:Number = 1;
var spriteWrap:Sprite = new Sprite();
var innerContainer:Sprite = new Sprite();
innerContainer.x = 0;
innerContainer.y = 0;
var line1:Shape = new Shape();
line1.graphics.lineStyle(5, 0x6F4356, 1, false, StageScaleMode.SHOW_ALL, CapsStyle.ROUND);
line1.graphics.moveTo(50, 5);
line1.graphics.lineTo(50, 800);
line1.graphics.endFill();
var line2:Shape = new Shape();
line2.graphics.lineStyle(5, 0x6F4356, 1, false, StageScaleMode.SHOW_ALL, CapsStyle.ROUND);
line2.graphics.moveTo(200, 290);
line2.graphics.lineTo(200, 300);
line2.graphics.endFill();
innerContainer.addChild(line1);
innerContainer.addChild(line2);
spriteWrap.addChild(innerContainer);
return spriteWrap;
}
var spriteWrap:Sprite = getLine();
var wrapForBitmap:Sprite = new Sprite();
var drawBitmap:BitmapData = new BitmapData(300, 300, true, 0x00ffaa);
var goOnStage:Bitmap = new Bitmap(drawBitmap);
wrapForBitmap.graphics.beginBitmapFill(drawBitmap);
wrapForBitmap.graphics.lineStyle(1, 0x6F7E84);
wrapForBitmap.graphics.drawRect(0, 0, 300, 300);
wrapForBitmap.graphics.endFill();
wrapForBitmap.x = 10;
wrapForBitmap.y = 10;
drawBitmap.draw(spriteWrap, new Matrix(1, 0, 0, 1, 0, 0));
wrapForBitmap.addChild(goOnStage);
stage.addChild(wrapForBitmap);
Yes of course. Than I redraw my Bitmap using my Sprite
MySprite.graphics.clear();
MySprite.graphics.beginBitmapFill(MyBitmap, new Matrix(1, 0, 0, 1, new_XPos, new_YPos), false, false);
MySprite.graphics.endFill();
Your Shape line1 is higher than your Bitmap's height (300):
line1.graphics.moveTo(50, 5); // begins at x = 50 and y = 5
line1.graphics.lineTo(50, 800); // begins at x = 50 and y = 800
With the following code, you will draw a line from the top to the bottom of your Bitmap:
line1.graphics.moveTo(50, 0);
line1.graphics.lineTo(50, 300);
If you want line1 to be visible without changing it's height, you have to change your Bitmap's height (800) by modifying the second argument of your BitmapData method:
var drawBitmap:BitmapData = new BitmapData(300, 800, true, 0x00ffaa);
You should modify at the same time your rectangle's height:
wrapForBitmap.graphics.drawRect(0, 0, 300, 800);