Xamarin Forms - Get the size of an AbsoluteLayout - height

I cannot find the way to get the Width and the Height of a Xamarin.Forms.View.
I have this object:
public class SquareLayout : View
{
public static readonly BindableProperty ScalingBaseProperty =
BindableProperty.Create(nameof(ScalingBase), typeof(ScalingBaseType), typeof(SquareLayout), ScalingBaseType.Average,
propertyChanged: OnScalingBasePropertyChanged);
public ScalingBaseType ScalingBase
{
get { return (ScalingBaseType)GetValue(ScalingBaseProperty); }
set { SetValue(ScalingBaseProperty, value); }
}
public enum ScalingBaseType
{
Average,
Height,
Width
}
public static void OnScalingBasePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
SquareLayout sq = ((SquareLayout)bindable);
Debug.WriteLine("|Width = {0}|Height = {1}|", sq.Bounds.Width, sq.Bounds.Height);
switch (sq.ScalingBase)
{
case ScalingBaseType.Average:
double size = (sq.Bounds.Width + sq.Bounds.Height) / 2;
sq.WidthRequest = size;
sq.HeightRequest = size;
break;
case ScalingBaseType.Height:
sq.WidthRequest = sq.Bounds.Height;
break;
case ScalingBaseType.Width:
sq.HeightRequest = sq.Bounds.Width;
break;
}
Debug.WriteLine("|Width = {0}|Height = {1}|", sq.Bounds.Width, sq.Bounds.Height);
}
}
Basically, you declare somewhere this SquareLayout and then, based on an Enum, the layout is resized as a Square.
So, I then have this XAML part
<ContentPage.Content>
<AbsoluteLayout BackgroundColor="White">
...
<AbsoluteLayout x:Name="ToolsLayout" BackgroundColor="Red"
AbsoluteLayout.LayoutBounds="0.5, 0.05, 0.9, 0.075"
AbsoluteLayout.LayoutFlags="All">
<control:SquareLayout BackgroundColor="White" ScalingBase="Height"
AbsoluteLayout.LayoutBounds="0, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All">
</control:SquareLayout>
<control:SquareLayout BackgroundColor="White" ScalingBase="Height"
AbsoluteLayout.LayoutBounds="1, 0.5, 0.1, 1"
AbsoluteLayout.LayoutFlags="All">
</control:SquareLayout>
</AbsoluteLayout>
...
</AbsoluteLayout>
</ContentPage.Content>
Which would give me a Rectangle with two Square around.. But nothing !
I tried to display the Width and the Height but nothing.. I tried the Bounds as well as you can see in the example, but nothing one more time..
The only values I get are -1
Does someone can help me? Thank in advance !

Xamarin has very less documentation for newbies , took some time to figure this out , basically during design time the the width and height property have a default value of -1 , which indicates auto , there is no way of knowing during design time what the values will be , hence you need to use 'events' to get the width and height property in this case you will use SizeChanged event , when the layout bounds are set during runtime this event will trigger.
In your xaml codebehind use this event to get your widh and height of yourlayout , i have used a lambda function , this can be implemented in many ways i just find this method easy.
yourlayout.SizeChanged+=(sender,e)=>
{
//Add your child objects here and set its values using yourlayout.Height etc
};
Instead of adding your children within this function you can use it to return a value and use that instead.
NOTE:I am not sure if this is the best practice for MVVM or otherwise

Related

How to make an If statement check for if a variable equals a negative number; issue making an adventure game with X,Y coordinates

I'm new to Javascript (and coding in general), and I'm trying to make a pretty basic in-browser adventure game, but immediately I've encountered a problem. I wanted it to plot your location as if on an X,Y graph so I could easily mark out a map for it later with coordinates. So, you start at 0,0, and when you move West it changes to -1,0, so on, and I'm using If statements to check your location. But, it always assumes you're at the lowest negative possible, and so always says you're at 'Room 3'.
I think it does this because it doesn't recognise the - in the check as part of the number, and instead thinks you're asking if it equals the number minus itself, which would be zero, which is the game's default position. But, at the same time, it still thinks you're at the lowest possible position even if you move off 0,0, so I don't know. If that is the case, I would like to know how to fix it, and if that isn't the case, I would like to know what the real problem is.
Below is the entire program so far. This is my first time really trying to code something by myself, with no tutorial involved, so I apologise for how training-wheels-y it is.
let x=0
let y=0
let time=0
let button = document.getElementById('button');
let buttonNorth = document.getElementById('buttonNorth');
let buttonWest = document.getElementById('buttonWest');
let buttonEast = document.getElementById('buttonEast');
let buttonSouth = document.getElementById('buttonSouth');
button.onclick = function() {
reporter()
locatron()
}
buttonNorth.onclick = function() {
updateNorth()
reporter()
locatron()
}
buttonWest.onclick = function() {
updateWest()
reporter()
locatron()
}
buttonEast.onclick = function() {
updateEast()
reporter()
locatron()
}
buttonSouth.onclick = function() {
updateSouth()
reporter()
locatron()
}
function reporter() {
console.log(`location is: ${x},${y}`)
console.log(`time is: ${time}`)
}
function updateNorth() {
y = y+1
time=time+1
}
function updateWest() {
x = x-1
time=time+1
}
function updateEast() {
x = x+1
time=time+1
}
function updateSouth() {
y = y-1
time=time+1
}
function locatron() {
if(x==0,y==0) {
totalDescription.innerHTML = `Room 1`
}
if(x==-1,y==0) {
totalDescription.innerHTML = `Room 2`
}
if(x==-2,y==0) {
totalDescription.innerHTML = `Room 3`
}
else {
totalDescription.innerHTML = `This area has not been written yet.`
}
}
I've tried turning the number in the If statement into a string, but it just does the same thing. The only way I can get it to display any message other than 'Room 3' is by moving it along the Y axis, at which point it changes to my equivalent of an error message, 'This area has not been written yet.'. I also tried looking the problem up, but the wording on it is so finnicky that the only results I would get back are how to 'check if a variable is negative', which is not at all what I want.
I appreciate any help I can get.

Read a list of parameters from a LuaRef using LuaBridge

[RESOLVED]
I'm building a game engine that uses LuaBridge in order to read components for entities. In my engine, an entity file looks like this, where "Components" is a list of the components that my entity has and the rest of parameters are used to setup the values for each individual component:
-- myEntity.lua
Components = {"MeshRenderer", "Transform", "Rigidbody"}
MeshRenderer = {
Type = "Sphere",
Position = {0,300,0}
}
Transform = {
Position = {0,150,0},
Scale = {1,1,1},
Rotation = {0,0,0}
}
Rigidbody = {
Type = "Sphere",
Mass = 1
}
I'm currently using this function (in C++) in order to read the value from a parameter (given its name) inside a LuaRef.
template<class T>
T readParameter(LuaRef& table, const std::string& parameterName)
{
try {
return table.rawget(parameterName).cast<T>();
}
catch (std::exception e) {
// std::cout ...
return NULL;
}
}
For example, when calling readVariable<std::string>(myRigidbodyTable, "Type"), with myRigidbodyTable being a LuaRef with the values of Rigidbody, this function should return an std::string with the value "Sphere".
My problem is that when I finish reading and storing the values of my Transform component, when I want to read the values for "Ridigbody" and my engine reads the value "Type", an unhandled exception is thrown at Stack::push(lua_State* L, const std::string& str, std::error_code&).
I am pretty sure that this has to do with the fact that my component Transform stores a list of values for parameters like "Position", because I've had no problems while reading components that only had a single value for each parameter. What's the right way to do this, in case I am doing something wrong?
I'd also like to point out that I am new to LuaBridge, so this might be a beginner problem with a solution that I've been unable to find. Any help is appreciated :)
Found the problem, I wasn't reading the table properly. Instead of
LuaRef myTable = getGlobal(state, tableName.c_str());
I was using the following
LuaRef myTable = getGlobal(state, tableName.c_str()).getMetatable();

Unreal Engine - How to get the AxisMappings via C++ code

I'm new to the Unreal Engine and C++...
I'm trying to get the assigned Key of an Axis. I found out that the information are stored in the DefaultInput.ini file but how do i access these data programmatically?
There's a GetAxisValue(const FName) method but it does not return anything.
FString AxisName = "MoveForward";
auto value = PlayerInputComponent->GetAxisValue(FName(*AxisName));
What am I doing wrong? I would really appreciate your help.
Im not sure because I use Blueprints most of the time for this, but one way to get the value is to bind it to a method.
(Example of the AFPSCharacter Template)
PlayerInputComponent->BindAxis("MoveForward", this, &APawn::MoveForward);
And later use it in the method
void AFPSCharacter::MoveForward(float Value){
//for example print the val
UE_LOG(LogTemp, Warning, TEXT("%f"), Value);
}
this was my first thought too but unfortunately you can't get the Keys, you just bind the method to an axis name. The MoveForward's "Value" parameter hold the scale value but not the Key value. 1.0f for example when you press "W" or -1.0f when you press "S".
I've already found a solution for my issue. The GetAxisValue(FName) is the wrong method for this purpose.
Instead I found the UInputSettings class that contains a method named GetAxisMappingByName(FName, TArray)
Here a code snippet how it works:
// Get the instance of the InputSettings
UInputSettings* InputSettings = UInputSettings::GetInputSettings();
// AxisMappings with all the information will be stored here
TArray<FInputAxisKeyMapping> VerticalKeys;
TArray<FInputAxisKeyMapping> HorizontalKeys;
// Load the AxisMappings
InputSettings->GetAxisMappingByName(FName("MoveForward"), VerticalKeys);
InputSettings->GetAxisMappingByName(FName("MoveRight"), HorizontalKeys);
// Each MovementKey gets its own variable
FKey ForwardKey;
FKey BackKey;
FKey LeftKey;
FKey RightKey;
// Assign each key to the correct direction
for (FInputAxisKeyMapping verticalKey : VerticalKeys)
{
if (verticalKey.Scale == 1.0f)
ForwardKey = verticalKey.Key;
else if (verticalKey.Scale == -1.0f)
BackKey = verticalKey.Key;
}
for (FInputAxisKeyMapping horizontalKey : HorizontalKeys)
{
if (horizontalKey.Scale == 1.0f)
RightKey = horizontalKey.Key;
else if (horizontalKey.Scale == -1.0f)
LeftKey = horizontalKey.Key;
}
Is there a better solution for assigning the keys than using for loops? Feel free to correct my code since I'm not really an expert in C++. ;-)

Flex: Spark List's Indeces in View change on Orientation Change

I have a spark list with a variable row_height (2 custom itemRenderer: Header 30 px, Contact 60 px) that on the only first orientation change after a scroll, change the indexes in view.
I tried to set Header to be 60 px height, and i had no problems with the orientation change.
I'm not setting the verticalScrollPosition anywhere. Adding an event listener on the viewport's list and watching the verticalScrollPosition, it doesn't change on orientation change.
I really don't know how can i fix that.
EDIT:
This is the code relative to the list:
<fx:Script>
protected function creationCompleteHandler(event:FlexEvent):void
{
addressBookViewModel = ViewModelFactory.getInstance().getAddressBookViewModel();
addressBookViewModel.getUserContacts(onDataReceived);
}
protected function pagedContactsList_initializeHandler(event:FlexEvent):void
{
asyncListView.list = pagedContactsList;
}
private function onDataReceived():void
{
pagedContactsList.length = (BusinessContext.getInstance().getTotalContacts() + BusinessContext.getInstance().getTotalLastNames());
loadPagedData();
}
private function createPendingItemFunctionHandler(index:int, ipe:ItemPendingError):Object
{
if(!addressBookViewModel.pageUp)
{
addressBookViewModel.pageUp = true;
addressBookViewModel.currentPage++;
addressBookViewModel.getMoreUserContacts(onMoreDataRecieved, onMoreDataMissing);
}
return loadingDataHeader;
}
private function onMoreDataRecieved():void
{
loadPagedData();
}
private function loadPagedData():void
{
for(var i:int = 0; i < addressBookViewModel.contacts.length; i++)
{
pagedContactsList.setItemAt(addressBookViewModel.contacts.getItemAt(i), pagedContactsList.lastItemInsertedIndex);
pagedContactsList.lastItemInsertedIndex++;
}
addressBookViewModel.pageUp = false;
}
internal var headerItemRender:ClassFactory = new ClassFactory(HeaderItemRenderer);
internal var contactItemRenderer:ClassFactory = new ClassFactory(ContactItemRenderer);
private function rendererFunction(item:Object):ClassFactory
{
return item.hasOwnProperty("isHeader") ? headerItemRender : contactItemRenderer;
}
</fx:Script>
<fx:Declarations>
<custom:PagedArrayList id="pagedContactsList" initialize="pagedContactsList_initializeHandler(event)"/>
</fx:Declarations>
<s:List id="list" width="100%"
height="100%" itemRendererFunction="rendererFunction" change="list1_changeHandler(event)">
<s:AsyncListView id="asyncListView" createPendingItemFunction="createPendingItemFunctionHandler" />
</s:List>
The curious thing is that before and after the orientation change the list.scroller.viewport.verticalScrollPosition has the same value even if the list has scrolled ~ 40 rows. (40 is the page size).
I have many lists in my app, and every list that has const row_height has no issue, but the 2 with a variable row_height have this problem. Maybe it's caused by the AsyncListView.
EDIT 2:
I removed the AsyncListView, binding directly addressBookViewModel.contacts to the list.dataProvider, removing the pagination and the issue is still there.
EDIT 3:
I think that the only thing to do is to put breakpoints everywhere in the Scroller's class.
EDIT 4:
This issue happens only when scrolling to the bottom of the list.
EDIT 5:
Find the issue!
VerticalLayout.as, in updateDisplayListVirtual(row 1797) there's a call to a method (updateLLV) that set up a LinearLayoutVector using a typicalLayoutElement. This is lazily init with the first itemRenderer added to the dataGroup of the list. In my case it's the HeaderItemRenderer (30px).
After the updateLLV, the startIndex (index of the first visible item) is setted by calling the indexOf on the LinearLayoutVector and passing the verticalScrollPosition. (briefly: verticalScrollPosition / typicalLayoutElement.height)
The problem is that nowhere is taken into consideration the variableRowHeight!
Workaround found! Not so elegant, but it works.
stage.eventListener(StageOrientationEvent.ORIENTATION_CHANGING, yourReorientHandler, false, 1)
Setting the priority is really important, otherwise the updateDisplayListVirtual will be called before your handler.
private function reorientHandler(event:StageOrientationEvent):void
{
var IndecesInView:Vector.<int> = list.dataGroup.getItemIndicesInView();
var firstInView:int = IndecesInView[0];
callLater(
function():void
{
if(!list.layout.getScrollPositionDeltaToElement(firstInView+1)) return;
list.scroller.viewport.verticalScrollPosition += list.layout.getScrollPositionDeltaToElement(firstInView+1).y;
});
}

Images handling in cocos2d android?

According to the different-2 screen resolution, can't use a single image for every device.
So, how to manage this thing in Cocos2d-android ?
or
Using setScale() is ok with it.
You have to create a method that can get the appropriate image according to screen size.
There are following steps that will help you to get image
1) Get the screen size and store that in a variable
I have used as
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
display = wm.getDefaultDisplay();
if(display.getWidth()<=320)
{
GameCons.setSCreenSize(1);
}else if(display.getWidth()<=480)
{
GameCons.setSCreenSize(2);
}else if(display.getWidth()<=860)
{
GameCons.setSCreenSize(3);
}else
{
GameCons.setSCreenSize(4);
}
Now we have screen size(1,2,3,4) store in variable screenSize
2)Now assign the name to images you are using
assuming if we have four images of player.png for four resolution
then assign there name as
player_1.png
player_2.png
player_3.png
player_4.png
These are same images for different resolution
3) Now create method that will return a name of image as
public static String getImageURI(String name) {
if (screenSize== 1) {
return name + "_1.png";
} else if (screenSize== 2) {
return name + "_2.png";
} else if (screenSize== 3) {
return name + "_3.png";
} else {
return name + "_4.png";
}
}
4) Now you have to use this method in your layer while passing name to sprite or some other
e.g:
target = CCSprite.sprite(getImageURI("player"));
You have to only pass the name before the underscore in method as above the real name is like player_1.png but we have only passes player
the getImageURI will return a appropriate name according to the screen size
assuming if we have screen size 2 then the
getImageURI will return
player_2.png
so code will become like target = CCSprite.sprite("player_2.png");//getImageURI will return player_2.png