I have an animation using ViewCompat.animate() on one of my Screen that uses FrameLayout and it looks fine on the test phone.
But of course, once running on the test tablet (Nexus 7 2013), the animation isn't the same.
So I'm searching a way to get the same displayed translation Y, on different screen sizes without using different dimens resource files.
Surely there is a way to calculate it at Run time and sort it out by itself.
I tried: float px = -182 * (getResources().getDisplayMetrics().densityDpi / 160f);
But the distance traveled by the view on the 2 screens are not the same.
Saw this post but didn't provide the solution: android animation in different screen sizes
Anyone has an idea?
Cheers
So here is what I tried, getting the height dpi of the device and use it to convert a dp value (182) into pixels.
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
float yDpi = displayMetrics.ydpi;
float px = 182 * (yDpi / 160);
While the result of the px value is different with every devices, the translation still doesn't travel the same distance on different screens
So I sorted it out doing this:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
float translationY = displayMetrics.heightPixels * 0.40f;
Got the Screen Height and used to calculate the distance to travel equal to 40% of the device screen height.
So now, whatever the used device, the animation is the same and travels the same distance.
Also, the float value used can be very precise. I used 0.40f but you can do something like 0.398f
In order to avoid any extra unnecessary math it is easier to get the metrics from the view already displayed on the screen. The only thing needed is to have a post in onCreate, in case of activity. In case of fragment you can simply to things directly in onViewCreated without any post
View settingsView = findViewById(R.id.settings_layout);
View youtubeView = findViewById(R.id.youtubeLink);
settingsView.post(new Runnable() {
#Override
public void run() {
//metrics already calculated
settingsView.animate().translationX(youtubeView.getWidth());
}
});
Related
In an application, let suppose we have an image of a car onto which we have mark a damage point. We can mark this point anywhere of the image as shown below.
Suppose we have marked this point on a device of screen size “5 inches” and then we calculated the coordinates of this point and sent it to the server.
Now the user is using another device of screen size “8 inches”. User wants to see those marked points in his new device. But he is not able to see the appropriate position of the points after fetching the actual value from the server.
I think the coordinates depend on the device's screen dpi. Assume your server always store the coordinates in mdpi. Then you should get the correct coordinates at device at different dpi like this:
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
float screenAdjust = (float) dm.densityDpi / 160f;
int x = (int) (x_value_from_server) * screenAdjust);
int y = (int) (y_value_from_server) * screenAdjust);
Get the height and width of the screen
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
Then calculate the coordinates of the image, I assume you are currently doing this in the form of an [x,y] array
Then simply find the ratio across all screen sizes by doing:
float x_ratio = coordinatesArray[0]/width
float y_ratio = coordinatesArray[1]/height
This will result in something along the lines of 0.25 and 0.34 (or something like that depending on the screen size)
You then simply create an array including these two floats and pass this along to the server.
I have two image views that the user can move around on the screen:
<ImageView
android:layout_width="35dp"
android:layout_height="match_parent"
android:id="#+id/leftRulerView"/>
<ImageView
android:layout_width="35dp"
android:layout_height="match_parent"
android:id="#+id/rightRulerView"/>
The are initialized in the following way:
mLeftRuler = (ImageView) view.findViewById(R.id.leftRulerView);
mRightRuler = (ImageView) view.findViewById(R.id.rightRulerView);
When either is moving, I am calculating the actual physical distance between the two views (this will be used for measuring real-world objects). rightRulerView is ALWAYS to the right of the left, and so the distance between them is from the right edge of the left-most view to the left edge of the right view. Refer to the following image:
First, het the pixel separation of the two views:
float distance = mRightRuler.getX() - (mLeftRuler.getX() + mLeftRuler.getWidth());
This works out because the getX() returns the x-position of the left-side of the view. I AM interested in the left side of the right ruler, but I need to add the width of the left ruler to get the location of the right side of it. Then, just subtract the two for the pixel count between the two. This works great and gives the pixel count between the views just fine.
To convert this to inches, I do the following:
DisplayMetrics mDisplayMetrics = getResources().getDisplayMetrics();
float mDPI = (float) mDisplayMetrics.densityDpi;
float measurement = distance / mDPI;
This all works fairly well, but it is not perfect. When is says "1.00 inches" between the two views, it is actually just under 1 1/8 inches (measured with a ruler on the physical screen). The inaccuracy propagates to larger distances (i.e. "3.00 inches" in the app is actually measured to a little over 3 1/4 inches with a ruler on the screen).
There are ruler apps out there, that are accurate to real-world rulers, so how can I convert the pixel distance between the two views into an accurate measurement?
there is to my knowledge at least no way to get a precise physical size without any userinput. what i did , is make a popup where the user has to input the diameter for example and then use some 7th grade math and get to the physical size of the Screen edges, assuming they are squares. and then you have smthing like "0.1mm/pixel" and then you could obviously keep on going with your method.
In DisplayMetrics you can use
mDisplayMetrics.xdpi The exact physical pixels per inch of the screen in the X dimension.
mDisplayMetrics.ydpi The exact physical pixels per inch of the screen in the Y dimension.
Then you can do some simple math to get the real distance
In API 17 getRealMetrics() has been introduced. It should give you accurate values in xdpi and ydpi.
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
However, if you need to support lower API versions there is no way you can achieve your goal without user input and calibration.
I have a simple function that increases the speed of my object in the screen:
float Velocity = 10;
float MaxVelocity = 100;
float VelocityGiven = 0;
RectF position = new RectF(ScreenHeight/2, ScreenWidth,0,0);
public void update()
{
if(VelocityGiven < MaxVelocity)
{
Position.left -= Velocity;
VelocityGiven += Velocity;
}
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(Bitmap,Position,null);
}
But depending on the phone screen size, or pixel density, this function moves the object too fast or too slow.
if I try that on a galaxy S4, witch has a really big screen resolution, the object goes slowly.
But if I try it on a low end device (small screens), the object goes very fast,
What can I do to avoid that?
I already have my FPS controlled, on every phone, this runs at 30 FPS. so it's not about the update ratio.
It depends on what you wish to do exactly. One simple approach would be to make everything proportional to screen size. For instance:
Position.left -= Velocity * getWidth() / REFERENCE_WIDTH;
where REFENRENCE_WIDTH corresponds to a screen resolution where your app behaves as you like.
You need to work with density independent units. That way it moves the same relative amount no matter what the pixel size is. To do this, decide how "big" your area is going to be. For example, to fix your width at a logical 1000 units:
float scaleWidth = (screenWidth / 1000);
float velocity = 10 * scaleWidth;
float maxVelocity = 100 * scaleWidth;
This would mean that no matter how wide the display actually is, at max velocity it would take 10 movements to go all the way across.
You are probably best to move your objects based on a grid system independent of the screen size. You could you meters, feet, or what ever works as your unit. Then get the screen size and screen resolution of the device and figure out what the relationship is. If your object moves one foot then how many pixels is that on the device. Based on resolution.
Here is a very general overview on screen sizes for android:
http://developer.android.com/guide/practices/screens_support.html
There are probably a lot more, and better, places to look for getting the device resolution and size.
Hope that at least gets you started :)
I am trying to build a game and was wondering how would one go about supporting different resolution and screen sizes. For position of sprite I've implemented a basic function which sets the position according to a certain ratio, which I get by getting the screen width and height from sharedDirector's winSize method.
But this approach is not tested as I have yet to develop something to calculate the scaling factor for sprites depending upon the resolution of device. Can somebody advise me some method and tips by which I can correctly calculate the scaling of sprite and suggest a system to avoid the pixelation of sprites if I do apply any such method.
I searched on Google and found that Cocos2d-x supports different resolutions and sizes but I am bound to use Cocos2d only.
EDIT: I am bit confused as this is my first game. Please point out any mistakes that I may have made.
Okay I finally did this by getting the device display denitiy like
getResources().getResources().getDisplayMetrics().densityDpi
and based on it I am multiplying by PTM ratio by 0.75,1,1.5,2.0 for ldpi,mdpi,hdpi,and xhdpi respectively.
I am also changing the scale of sprites accordingly. And for positioning I've kept 320X480 as my base and then multiplying that with a ratio of my current x and y in pixels with my base pixels.
EDIT: Adding some code for better understanding:
public class MainLayer extends CCLayer()
{
CGsize size; //this is where we hold the size of current display
float scaleX,scaleY;//these are the ratios that we need to compute
public MainLayer()
{
size = CCDirector.sharedDirector().winSize();
scaleX = size.width/480f;//assuming that all my assets are available for a 320X480(landscape) resolution;
scaleY = size.height/320f;
CCSprite somesprite = CCSprite.sprite("some.png");
//if you want to set scale without maintaining the aspect ratio of Sprite
somesprite.setScaleX(scaleX);
somesprite.setScaleY(scaleY);
//to set position that is same for every resolution
somesprite.setPosition(80f*scaleX,250f*scaleY);//these positions are according to 320X480 resolution.
//if you want to maintain the aspect ratio Sprite then instead up above scale like this
somesprite.setScale(aspect_Scale(somesprite,scaleX,scaleY));
}
public float aspect_Scale(CCSprite sprite, float scaleX , float scaleY)
{
float sourcewidth = sprite.getContentSize().width;
float sourceheight = sprite.getContentSize().height;
float targetwidth = sourcewidth*scaleX;
float targetheight = sourceheight*scaleY;
float scalex = (float)targetwidth/sourcewidth;
float scaley = (float)targetheight/sourceheight;
return Math.min(scalex,scaley);
}
}
I am trying to build a game and was wondering how would one go about supporting different resolution and screen sizes. For position of sprite I've implemented a basic function which sets the position according to a certain ratio, which I get by getting the screen width and height from sharedDirector's winSize method.
But this approach is not tested as I have yet to develop something to calculate the scaling factor for sprites depending upon the resolution of device. Can somebody advise me some method and tips by which I can correctly calculate the scaling of sprite and suggest a system to avoid the pixelation of sprites if I do apply any such method.
I searched on Google and found that Cocos2d-x supports different resolutions and sizes but I am bound to use Cocos2d only.
EDIT: I am bit confused as this is my first game. Please point out any mistakes that I may have made.
Okay I finally did this by getting the device display denitiy like
getResources().getResources().getDisplayMetrics().densityDpi
and based on it I am multiplying by PTM ratio by 0.75,1,1.5,2.0 for ldpi,mdpi,hdpi,and xhdpi respectively.
I am also changing the scale of sprites accordingly. And for positioning I've kept 320X480 as my base and then multiplying that with a ratio of my current x and y in pixels with my base pixels.
EDIT: Adding some code for better understanding:
public class MainLayer extends CCLayer()
{
CGsize size; //this is where we hold the size of current display
float scaleX,scaleY;//these are the ratios that we need to compute
public MainLayer()
{
size = CCDirector.sharedDirector().winSize();
scaleX = size.width/480f;//assuming that all my assets are available for a 320X480(landscape) resolution;
scaleY = size.height/320f;
CCSprite somesprite = CCSprite.sprite("some.png");
//if you want to set scale without maintaining the aspect ratio of Sprite
somesprite.setScaleX(scaleX);
somesprite.setScaleY(scaleY);
//to set position that is same for every resolution
somesprite.setPosition(80f*scaleX,250f*scaleY);//these positions are according to 320X480 resolution.
//if you want to maintain the aspect ratio Sprite then instead up above scale like this
somesprite.setScale(aspect_Scale(somesprite,scaleX,scaleY));
}
public float aspect_Scale(CCSprite sprite, float scaleX , float scaleY)
{
float sourcewidth = sprite.getContentSize().width;
float sourceheight = sprite.getContentSize().height;
float targetwidth = sourcewidth*scaleX;
float targetheight = sourceheight*scaleY;
float scalex = (float)targetwidth/sourcewidth;
float scaley = (float)targetheight/sourceheight;
return Math.min(scalex,scaley);
}
}