animating xml elements in java code in dps (android studio) - android

I'm using android studio to design a game.
I used the 'dp' unit in my 'xml' file for defining my elements.
In java code, I want to move those elements by function animate() like image_button_red1.animate().xBy(first value).yBy(second value);
this function only takes float value, But the animation is different in each device.
I want to use the 'dp' unit to solve this problem.
Is there a function that takes another unit like 'dp'?

I've found an answer.
I designed my layout in pixels and when I used, for example, animate().xby(10.0f), the translation was right in each device. The equation between the pixel and dp is: px = dp * (dpi / 160);
Then I used dp instead of px and used the function Resources.getSystem().getDisplayMetrics().density to get the density of each screen which is running the code.
So I used a float variable instead of 10.0f which this value calculated from the noted equation. My object size was 360 dp, and the equation changed to px = 2.25*dpi.
And in my case, I used a variable like this:
float House_size = 2.25f * 14.44f * Resources.getSystem().getDisplayMetrics().density;
then I used animate().xby(House_size);
And now the result works properly on every single device.

Related

Android GestureOverlayView parameters

I started experimenting with Custom Gestures and the GestureOverlayView and noticed a few variables where I am not sure what they are for and what range of values can and should be assigned, the docs seem to be somewhat vague on those:
//Minimum curve angle a stroke must contain before it is recognized as a gesture.
android:gestureStrokeAngleThreshold
I assumed this is in degrees and when I add "25" here, a sharp edge must be contained in the gesture, but actually it still is detected ifI draw a circle or a perfect square.
//Minimum length of a stroke before it is recognized as a gesture.
android:gestureStrokeLengthThreshold
Is this in dp ? Because it seems like on smaller screens it is harder to trigger the gesture...
//Squareness threshold of a stroke before it is recognized as a gesture.
android:gestureStrokeSquarenessThreshold
what is this?
EDIT:
Ok I just realized that every prediction has a score value, which should be used to find out if the gesture performed actually meets the requirements, so I added a check if the prediction's score is greater than 1.
Still I am curious what those variables in GestureOverlayView are doing, so enlighten me :)
gestureStrokeLengthThreshold definitely is not density independent but apparently uses pixels. If you want to set a density independent threshold you can calculate the gestureStrokeLengthThreshold at runtime, like that:
DisplayMetrics metrics = getResources().getDisplayMetrics();
float normalizedScreenSize = (metrics.heightPixels + metrics.widthPixels) / 2.0f;
return normalizedScreenSize * GESTURE_LENGTH_THRESHOLD;
GESTURE_LENGTH_THRESHOLD would be a value representing how long the gesture should be. A value of 1.0 would roughly be the size of the screen (averaged from screen width and height)
Still I am interested in what those other variables in GestureOverlayView do, so if you know more - enlighten me :)

Same translation Y on different Screen sizes

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());
}
});

Android - Google Maps - Projection - toPixels() - Is it device independent pixels?

I am using the Map View Projection to obtain the screen pixels like
currentPixelLocation = businessMapMv.getProjection().toPixels(tappedLocation, null);
Then I am using this to do some manipulation on the screen like centering a balloon tip.
So what I do is
currentPixelLocation.y = currentPixelLocation.y - 100
This works fine. Are the pixel locations returned by the toPixels method device independent ?
Will my manioulation like the above code work for all screen resolutions ?
I think there is a misunderstanding in device independent pixels on your site. If you declare your layout in device independent pixels (dip), the framework itself calculates the correct Veiw size - based on device display density - for the device it running on at runtime. After the framework calculates the View dimension, the View has its dimension set in pixels.
So therefore, getProjection().toPixels() gives you the position relative to the underlaying MapView in pixels. Those pixels are device independent.
What seems wrong to me is you calculation currentPixelLocation.y = currentPixelLocation.y - 100 What does the 100 stand for? These 100 are definately device dependent. If you want to subtract 100 pixels, just use this calculation currentPixelLocation.y = currentPixelLocation.y - 100 * getResources().getDisplayMetrics().density + 0.5f. It ensures, that the 100 pixels are calculated device *in*dependent.
They are device independent, but they depend on the tile size that is defined for the tile layer. On regular maps the default tile size is 256 x 256 pixels.

Custom rendered Android app widget

I'm making an app widget for Android, which due to being composed of custom elements such as graphs, must be rendered as a bitmap.
However, I've run into a few snags in the process.
1) Is there any way to find the maximum available space for an app widget? (OR: Is it possible to calculate the dimensions correctly for the minimum space available in WVGA (or similar wide) cases?
I don't know how to calculate the maximum available space for an app widget. With a conventional app widget it is possible to fill_parent, and all the space will be used. However, when rendering the widget as a bitmap, and to avoid stretching, the correct dimensions must be calculated. The documentation outlines how to calculate the minimum dimensions, but for cases such as WVGA, there will be unused space in landscape mode - causing the widget to look shorter than other widgets which stretch naturally.
float density = getResources().getDisplayMetrics().density;
int cx = ((int)Math.ceil(appWidgetInfo.minWidth / density) + 2) / 74;
int cy = ((int)Math.ceil(appWidgetInfo.minHeight / density) + 2) / 74;
int portraitWidth = (int)Math.round((80.0f * cx - 2.0f) * density);
int portraitHeight = (int)Math.round((100.0f * cy - 2.0f) * density);
int landscapeWidth = (int)Math.round((106.0f * cx - 2.0f) * density);
int landscapeHeight = (int)Math.round((74.0f * cy - 2.0f) * density);
Calculating cx and cy gives the number of horizontal and vertical cells. Subtracting - 2 from the calculated dpi (e.g. 74 * cy - 2) is to avoid cases where the resulting number of pixels is rounded down. (For example in landscape mode on Nexus One, the height is 110, not 111 (74 * 1.5).
2) When assigning a bitmap to an ImageView which is used as part of the RemoteViews to view the image, there are 2 methods:
2.1) By using setImageViewUri, and saving the bitmap to a PNG file. The image is then served using an openFile() implementation in a ContentProvider:
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
// Code to set up imageFileName
File file = new File(getContext().getCacheDir(), imageFileName);
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
This works, and it's the approach I'm currently using. However, if I set the scaleType of the ImageView to "center", which by the documentation is supposed to "Center the image in the view, but perform no scaling.", the image is incorrectly scaled. Setting the density of the bitmap to DENSITY_NONE or getResources().getDisplayMetrics().densityDpi doesn't make any difference when saving the bitmap to PNG, it seems to be ignored when the file is loaded by the ImageView. The result is that the image is scaled down, due to some dpi issue. This seems to describe the case:
http://code.google.com/p/android/issues/detail?id=6957&can=1&q=widget%20size&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
Because it is not possible to use scaleType:center, the only way I've found to work is to set the layout_width and layout_height of the ImageView statically to a given number of dpis, then rendering the bitmap to the same dpi. This requires the use of scaleType:fitXY. This approach works, but it is a very static setup - and it will not work for resizable 3.1 app widgets (I haven't tested this yet, but unless onUpdate() is called on each resize, this is true).
Is there any way to load an image to an ImageView unscaled, or is this impossible due to a bug in the framework?
2.1) By using setImageViewBitmap directly. Using this method with the Bitmap.DENSITY_NONE setting on the bitmap, the image can be shown without scaling correctly. The problem with this approach is that there is a limitation to how large images can be set through the IPC mechanism:
http://groups.google.com/group/android-developers/browse_thread/thread/e8d84920b999291f/d12eb1d0eaca93ac#01d5c89e5e7b4060
(not allowed more links)http://groups.google.com/group/android-developers/browse_thread/thread/b11550601e6b1dd3#4bef4fa8908f7e6a
I attempting a bit of a hack to get past this issue, by splitting the widget into a matrix of images which could be set in 100x100 pixel blocks. This did allow for larger widgets to work, but ended up being very heavy and failed on large widgets (4x4).
Sorry for a very long post. I've tried to explain a few of the different issues when attempting to use a bitmap rendered app widget. If anyone has attempted the same and have found any more solutions to these issues, or have any helpful comments, this will be highly appreciated.
An approach that worked for us for a similar situation was to generate our graph as a 9-patch png, with the actual graph part as the scalable central rectangle, and the caption text and indication icons (which we did not want all stretched out of shape) and border effects, placed on the outer rectangles of the image.

Android: Convert points to pixels

I have been using the pt unit in XML files. Now I need to set the width of an element at runtime. How can I set the width by points so that it is the same unit I have been using everywhere else. I assume I will need to multiply by resolution and dpi. A code sample would be best.
First you should really read the following in-depth article from the Android Developer Documentation :
http://developer.android.com/guide/practices/screens_support.html
Right in the middle you'll find the following under the title :
Do not use hard-coded pixel values in your code
// Convert the dps to pixels
final float scale = getContext().getResources().getDisplayMetrics().density;
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);
You can use dip instead of pt

Categories

Resources