Calculate Android TranslationY value for different screens and Animation - c#

I have a fragment for more options in my app that I want mostly hidden except for one small rectangle that says "Pull up for more options". This rectangle is parked at the bottom of the screen. When the user pulls it up, it then pops up from the bottom but NOT taking over the full screen, only about 1/3rd of the bottom. Just enough to show some of the options (checkboxes).
I am doing this and have it working by setting the TranslationY setting of the options fragment layout, which is in a FrameLayout container by the way, so that it is at the bottom of the screen and just shows my "Pull up for more options" text.
Then, when they pull up on that, I have some motion events to bring it up to where I want.
Here is the issue, I can get it working just fine on one display using hard coded TranslationY settings. For example, on a Galaxy S2 which has a density of 1.5 (HDPI 240) and a screen of 480x800, these are my hard coded values that work. I had to find them just by playing around with the numbers.
int trackOptionsHome = 650; //Parked at bottom of screen.
int trackOptionsExtended = 450; //Extended out where I want it to.
Again, with those hard coded values on the S2, it works fine and the way I want. However, if I now try a different device that is STILL HDPI (1.5/240) except the screen size is 480x640 (3.5in), it does not display properly which is to be expected. So then I implemented something like this:
float trackOptionsHome = ((dMetrics.HeightPixels / dMetrics.Density) + 120);
float trackOptionsExtended = ((dMetrics.HeightPixels / dMetrics.Density) - 100);
This was to try to take into account for different display density and sizes. I was then trying to do math at the end of each to position my fragment where I want it. However, I am getting inconsistent results and the numbers are still arbitrary. I have to find them by playing around.
This raises two questions:
1. How do I make sure I get the results I want on DIFFERENT display densities, which is not even the issue I am having at the moment since I have the same density.
2. How do I scale properly for the different size screens, which appears to be my immediate problem.
For math purposes at the moment (I can adjust as needed after I get an answer) let's say I want 50px of the fragment showing from the bottom when it is in the home position and 300px showing up from the bottom when extended.
What is the correct way to do this?
Thanks!
Mike

Related

Why my Canvas is not on same positions as on my device?

I hope I am not too boring because again I have one dumb question.
I have made my game near till end but now I have one big problem. My images , text etc in my Canvas panel are not display correctly on all devices.
I made the game and it looks perfect on unity. Then I build the same game to my Galaxy S8 Device and i realized that some images are out of the screen in other words I can not see some images in corners or some text .. That means my canvas settings are not correct ..
This is my canvas settings.
When I change UI scale mode to constant pixel or constant physical size It doesn't show properly even in unity or on phone seems like he zoom in automaticlly too much. I made the best settings for UI SCALE MODE - > Scale with screen size, but on some devices it doesn't show up correctly ( it shows with little errors like corner text is not shown because it looks like he is outside of screen)
I hope someone has solution for this.
Here is my general settings of canvas, which i always use and never got any issue in positioning.
Also when you put any object, RectTransform's value(marked in following image) is not set properly then it will go outside of screen.
For more details see : https://docs.unity3d.com/Manual/class-RectTransform.html
Also you can check different screen ratio from unity and even add new to it and test.

How to setup a shopping based UI for different screen sizes in unity?

I am trying to set up a shopping based UI for different screen sizes.In the canvas settings inside the Inspector I have given a reference resolution of 750 x 1334(Iphone 6)
UI scale mode - Scale with screen size
Match(Width-Height) - 0.5 (Which I change to one can see them in the images)
Somehow I placed the Images and text according to given design.It looks ok in the Iphone resolution.But in Ipad the buttons and text gets mixed up.
Now I change the Match(Width-Height) - 1 .The result is it looks okay but in the ipad view it looks small and there is plenty of space along the two sides.
How to get a matching view/look for all the different screen sizes.
Images are given below
Actually, u don't need to change the match size.
what u actually have to use are anchors. If u use anchors no matter how the size of the screen changes the UI element will resize with it.
see this video from unity officials. It will definitely solve ur issue.
https://www.youtube.com/watch?v=FeheZqu85WI&list=PLX2vGYjWbI0Qp0sD8_RKgbWul7z_eyNAv&index=2
thank you.
U can accept this answer if this solves ur issue.

Positioning Unity Admob Banner at the Bottom on a Device with a Display Cutout

I'm trying to position my ad banner (generated via the official Admob package for Unity) at the very bottom of the screen, but it doesn't seem to work very well with devices with a notch.
bv = new BannerView(adUnitId, adSize, AdPosition.Bottom);
This line of code positions the banner at the very bottom perfectly on notch-less devices (such as Pixel, Pixel XL, Pixel 2 & 2 XL), but look like this when the device have a notch at the top:
(The demo photo is taken from this Github Issue. Ignore the visible navigation bar.)
the space between the banner and the bottom of the screen is exactly the height of the notch. I tested it with multiple notch heights.
In order to position the banner at the very bottom, I think the best solution is to get the height of the notch and then use the following line of code:
new BannerView(adUnitId, adSize, 0, (int)ConvertPixelsToDP(Screen.height - adHeight + notchHeight));
But I couldn't find any way to get the cutout height. I tried using Screen and Display classes properties, but none of the ways helped me get the real resolution of the screen, including the notch, so I could subtract the safeArea height - and get the exact height of the notch.
Is there any way to get this real screen resolution? or any other possible solution to this problem?
From the main GitHub issue thread about this the AdMob Unity plugin developers stated "Will be prioritizing notch compatibility for the next release." back in October, indicating they are aware of the bug, and they posted on January 22nd saying "This work got pushed back but will be making it into the next release. No ETAs yet but should be soon." So who knows when the issue will ever get fixed.
But to anyone who is wrestling with this issue: I found a workaround. In my case it's a workaround for getting the ad to appear at the bottom of the screen, but I will also mention how you can probably get it to display at the top properly. I still hope for a release that just fixes this soon, but here is an option for those who don't want to wait around...
I discovered this workaround because I first started with the obvious solution: compute the y position manually via the obvious formula: int yDP = DensityIndependentPixels(Mathf.RoundToInt(Screen.safeArea.y + Screen.safeArea.height) - ScreenPixels(adSize.Height)); This would work, except for the fact that as of Unity 2018.3.5 safeArea always has 0, 0 for x and y, and while the width and height are usable to detect that there's a notch when compared to Display.main.systemHeight (although as far as I can tell, Screen.height == safeArea.height and same for width, so safeArea is entirely useless right now, since it only conveys information you can get from Screen.height and Screen.width), you can't actually detect where the notch is... this means in this workaround I assume that the notch is at the top of the screen (a safe assumption, but some phones have two notches, one on top and one on bottom, and for those devices my workaround will leave the ad partially covered by the bottom notch... if safeArea ever gets useful values, my workaround can account for that... anyway, I digress.)...
With that assumption made we can use a slightly modified formula: int yDP = DensityIndependentPixels(Screen.height - ScreenPixels(adSize.Height));
But frustratingly while I was logging values I'd expect for the y position... it was still showing up in the same weird offset position! I started manually increasing the y position from 0 incrementally and confirmed that at a certain y coordinate, even if you increase the value, the position it would appear in would be the same! And then I discovered that if you add a fair bit more to the y value, it would inexplicably pop back up at the top of the screen and you could continue incrementing the y position to bring it back down the screen, except this time it didn't get stuck at the weird offset position! After much experimentation I found that the formula for this inexplicable extra wrap-around y offset is: (DensityIndependentPixels(Display.main.systemHeight) + adSize.Height) and when added to intendedDensityIndependentPixelPosition... you now have the banner in the y position you were expecting!
Once you simplify the math, the manual y position that is a functional workaround for placing the banner at the bottom on a notched device is the shockingly simple:
int yDP = DensityIndependentPixels(Screen.height + Display.main.systemHeight);
I've tested this with all the simulated notches in Android 9 and it works (with the caveat that the double notch partially covers the ad still, but that's better than the ad covering the UI of the app), but be warned that I haven't yet tested this on actual notched devices!
Note that you only need to do this when Screen.height != Display.main.systemHeight... otherwise you're on a notchless device and should use AdPosition.BOTTOM.
For those who want your banner to appear at the top, the manual computation for y position is even simpler. Under the same assumption that notches are always on top, the y position of the ad should be set to DensityIndependentPixels(Display.main.systemHeight - Screen.height) with no bizarre inexplicable wrap-around offset necessary. Note that I haven't tested displaying the banner at the top given that the banner in my app is always displayed at the bottom.
The x position manual formula to make sure the ad is centered is exactly as you'd expect: int xDP = Mathf.RoundToInt(DensityIndependentPixels(Display.main.systemWidth - ScreenPixels(adSize.Width)) / 2f); Nothing particularly weird there.
One final note, I noticed that after I started manually specifying the ad position, I couldn't call Show() after calling Hide() on the BannerView... it would get in a weird state where it was invisible yet clickable; to fix this simply Destroy() and create a new AdRequest instead of calling Show()... I've seen some statements on Google support forums that say this is better practice anyway.
I hope the day I lost diving into this bizarre issue and finding this workaround helps someone here.
Unfortunately this is an issue that is caused by admob not accounting correctly for the top notch on Android. Note on iOS the ads code seems to acknowledge the existence of the notch and add extra 10 units of padding under it, which is weird.
I just spent a day or so trying to figure out very similar issue with the banner.
There are several ways to fix this:
Option 1. Create new java plugin and add the code below or from C# call the equivalent of this code:
public int getDisplayRealHeightPixels() {
Point realSize = new Point();
Display display = getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 17) {
display.getRealSize(realSize);
}
else {
display.getSize(realSize);
}
return realSize.y;
}
Then use getDisplayRealHeightPixels() to position the banner. That's what I currently do.
Option 2. Enable painting in cutout area: create a new java plugin, in onCreate add:
protected void onCreate(Bundle savedInstanceState) {
...
// uncomment to allow painting in notch area;
WindowManager.LayoutParams attributes = getWindow().getAttributes();
attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(attributes);
...
I'll use this option once I adapt my app to support cutouts properly.
Option 3: Wait for Unity 2018.3 to support notches properly
According to https://unity3d.com/unity/beta/2018.3:
"Android: Added notch support for Android."
Gotchas:
None of the above fixes are perfect (perhaps option 3? but I haven't tried it.) Make sure to test on iOS (iPhone X) because Ads behaves differently there than Android.
On Android Ads, y==0 is the top of the screen, while on iPhone X y==0 renders the banner about 10 units below the notch.
For iOS I just hardcode the "notch size" to 30 and draw my app in the notch area.
Android split screen is a pain - I haven't tested completely there, my banner flies around the screen in this case. I just decided to fix it later.

Horizontal Scroll Bar in Oxyplot WPF

I'm trying to implement a utility for showing throughput over time in a system, and am using Oxyplot to visualise the data.
Currently, zoom and pan are working as expected, but I would like some visual indication to the user which clearly shows whether the graph can be zoomed or panned.
After ditching the idea of using a scroll bar (being neither able to accurately get the position of the visible section of the graph, nor correctly position the thumb of the scroll bar releative to the chart), I have settled on using icons to show whether there is any data on the chart which is hidden to the left or rightmost side.
I would like these icons to work as buttons which allow the user to page left and right on the graph, however as with all things OxyPlot related, the implementation is far more complex than it first seems.
I'm using the WPF implementation, which uses a ViewModel representing the overall data set, with each series item represented by its own model.
This effectively renders almost every tutorial useless as the WPF implementation is significantly different to the basic OxyPlot package.
Currently, the code behind in the view handles the click on the page left/right buttons. I cannot put this in my ViewModel as it must interract directly with the PlotControl object.
private void btnPageRight_Click(object sender, RoutedEventArgs e) {
CategoryAxis axis = (CategoryAxis)PlotControl.ActualModel.Axes[0];
double xAxisMin = axis.ActualMinimum;
double xAxisMax = axis.ActualMaximum;
double visibleSpan = xAxisMax - xAxisMin;
double newMinOffset = xAxisMax + visibleSpan;
PlotControl.Axes[0].Minimum = newMinOffset;
PlotControl.Axes[0].Maximum = newMinOffset + visibleSpan;
PlotControl.ActualModel.InvalidatePlot(true);
}
As it stands, the above code throws no errors, but it does not work either.
If anybody can advise a possible way to make OxyPlot scroll to a given position using just code behind, I would be grateful.
As a last resort, I have pondered trying to simulate a mouse drag event to make this finicky beast behave.
I find the need to work around the problem in that way quite offensive, but desparation leads to odd solutions...
In case anybody else runs into this issue, the following snippet will scroll the graph in pages based on the number of columns visible on the graph at the time.
The snippet takes the number of visible columns as the viewport, and will move the visible area by the viewport size.
Although this applies to the WPF implementation, the only way I could find to make this work was to run this method from the code behind in the View containing the OxyPlot chart.
This should work correctly regardless of the zoom amount at the time.
The CategoryAxis reference must be obtained from the ActualModel as the WPF.Axis does not provide the ActualMinumum and ActualMaximum needed to calculate the viewable area.
The visibleSpan in this case represents the number of columns, with panStep denoting the amount to pan by in pixels.
private void ScrollInPages() {
//To zoom on the X axis.
CategoryAxis axis = (CategoryAxis)PlotControl.ActualModel.Axes[0];
double visibleSpan = axis.ActualMaximum - axis.ActualMinimum;
double panStep = 0;
//Scrolling the chart - comment out as appropriate
//Scroll right one page
panStep = axis.Transform(0 - (axis.Offset + visibleSpan));
//Scroll left one page
panStep = axis.Transform(axis.Offset + visibleSpan);
axis.Pan(panStep);
PlotControl.InvalidateFlag++;
}

Calculating image width when zoomed in C# Winforms

I'm working on a Winforms app that contains a large map image (5500px by 2500px). I've set it up so the map starts in full size, but the user can zoom out to a few different scales to see more of the map. The user is able to drag the map around to shift what they are looking at (like Google Maps, Bing Maps, Civilization, etc.).
When the map is full sized (scale = 1.0), I am able to prevent the user from scrolling past the borders of the image. I do this by calculating if they are trying to move past 0, or past the image width - current window size, similar to this:
if (_currHScroll <= 0) {
_currHScroll = 0;
}
This all works just fine. But, when I zoom out on the map (thus, making the image smaller), the limits for the bottom and right of the map break down. I know why this happens--because the Transform that is performed basically "compresses" the map a little bit, and so what used to be a 5000 px image is now smaller, depending on the scale. But, my limiters are based on the image size.
So, the user can scroll past the end of the map, and just sees white space. Worse things happen, I realize, but if possible I'd like to keep them from doing that.
I'm sure there is a straight-forward way to do this, but I haven't figured it out yet. I've tried simply multiplying my calculation by the scale, but that didn't seem to work (seems to under-estimate the size initially, then over-estimate on the smallest sizes). I've tried calculating the transform location of the bottom right of the image, and using that, but it turns out, that number is inverted, and I can't find what it relates to.
I'm including my transform point method here. It works just fine. It tells me, regardless of zoom level, what pixel was clicked on the original image. Thus, if someone clicks on point 200, 200 but the image is scaled at .5, it will show something like 400,400 as what was clicked (but, as I said, I don't think the scale value is a multiplier--using this just for demonstration purposes).
public Point GetTransformedPoint(Point mousePoint) {
Matrix clickTransform = _mapTransform.Clone();
Point[] xPoints = { new Point(mousePoint.X, mousePoint.Y) };
clickTransform.Invert();
clickTransform.TransformPoints(xPoints);
Debug.Print("Orig: {0}, {1} -- Trans: {2}, {3}", mousePoint.X, mousePoint.Y, xPoints[0].X, xPoints[0].Y);
return xPoints[0];
}
Many thanks in advance. I'm sure it's something relatively easy that I'm overlooking, but after several hours, I'm just not finding it.
If i understand right, you can calculate the maximum with your method GetTransformedPoint by using width and height from your Image as Point. The result can then be used inside your check...
And by the way, you are right, the scale value is a multiplier used as a factor. The only thing is, you have to cast the result to an integer.

Categories

Resources