Inconsistency between px and dp in android - java

OK, so here's a wobbly one... Before asking my question, I'll point out that I have read this:
What is the difference between "px", "dp", "dip" and "sp" on Android?
So here's my problem, I have some squares on screen (EditText) which I define in my XML using dp units, and identifying them square1, square2 etc., and they are positioned in a FrameLayout (since absolute layout is deprecated and that I don't see any other layout that would suit my purposes;
I want to control the position of the squares on screen by programming, soI use
square1.setX(cc1x);
square1.setY(cc1y);
square2.setX(cc2x);
square2.setY(cc2y);
and so on, and where cc1x, cc1y, cc2x, cc2y are int variables that change according to the logic of the app. The problem is that the java syntax doesn't allow adding a unit to this integer value of the variables, so on some screens my app works just perfectly, but on screens with a different density, everything is either too far apart, either overlapping...
And finally the question(s):
Is there a way of "forcing" the units into the setX / setY statements?
or
Is there a way to get the density of the screen of the device where my app will run? (in which case I could recalculate the X/Y coordinates accordingly)
(I didn't do research on this second possibility yet, as I just thought of it whilst writing this, so please accept my apologies if it is a duplicate of some other question).
Thanks in advance for your thoughts.

You can add this method to easily convert between DP on the screen and PX of the device
public static float convertDpToPx(Context context, int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

I wanted to update on this thread, since I've found a far better solution to the problem, though the answers you guys (& girls?) really did teach me a lot, for which my gratitude. Finally, njzk2's answer has made me reconsider the whole approach to what I wanted to do. So, instead of moving my boxes around, which resulted in the dimensioning problems, now I just move the content of the boxes around, leaving the boxes nicely positioned in place, which is by far more easy. Anyway, I hope this will result usefull to other starters like me.

Related

Android - Set Canvas to always be 1920x1080p?

Im developing a mobile game in Java on a canvas. But when I use different sized phones, the alignments are wrong and the hard coded offset values to correctly place buildings don't match with the new canvas proportions. Also, the UI elements are wrong size now and dont match the screenheight. Feeling kind of lost on how to best solve this issue.
I know that hard-coding the game to always be 1080x1920p will probably lead to black bars on some phones, something I'd also want to avoid if possible.
Canvas.scale did not do the trick, it only achieved crashes.
Anybody got experience in this? Thanks!

How can I make the width of a Constraint Layout negative?

I'm not sure if this is possible, or If I am approaching this challenge wrong. I am making a 2D Platformer, so when you hit the edge of the screen(Width), a new portion of the map would appear. Currently, I made single Images for each Portion of the map. Problem is, on larger devices, this would leave a lot of blank screen, and the Image would only fit a specific device.
Now I am wondering, can I make my ImageView (MAP) at a negative X value then when the character hits the edge, the map would move right (X would go higher).
I am using XML (Java is also fine), and I have NO CLUE how to approach this.
Since you are using constraint layout, you need to set android:layout_width="0dip".
This will fit any image to its screen width.(Image width should be greater than screen horizontal width).
Apply some conditions something like,
If image width < screen width then call next image to remaining screen, else call next image for entire screen.
Hope it helps for code-flow.
:)
You could use android:translationX or Android:translationY which actually support negative values. But in your particular case I think you are trying to use a nail clipper to cut your hair... You are using stuff that are not designed for that purpose. Using multiple big Image views can become a performance issue (I don't know about your particular case), I recommended you instead to be brave and make your own wiew and paint it dynamically (it can sound difficult but I'm sure will be easier than what you are trying), or make a comprehensive googling for a view meant for what you want.
Specifically for games you should try andengine lib or something like that, believe me... It would be easier in the end and you may earn something new :)
An alternative solution is to draw a layout (e.g. RelativeLayout) larger than your screen size, with an equal amount of padding on all sides.
For example, if you want to make a 50dp x 50dp ImageView appear from off the right hand side of the screen, your RelativeLayout would be 100dp taller and wider than your screen (50dp on each side). You could then position your ImageView at the far right of the RelativeLayout, and move it onto the visible area at will. So drawing something at -20dp, would actually be drawing it at 30dp in this example.
Programmatically getting the screen size and resizing a layout is very straightforward, and this approach would let you control your map loading in the manner you described.

Scale drawable in Android to support multiple screens

Currently I seek a solution to simple situation, which appeares to become tricky. I need 7 togglebuttons in android app, which are a simple black circles, but I need them to be in the row and fill parent (screen) horizontally. As a resource I use big .jpeg image of a circle. To make them fill all screens in the same mode, I put them into LinearLayout with
#android:layout_width = "fill_parent";
#android:layout_height = "wrap_content";
#android:weight="70";
Weight is 70, so each button received 10. The problem is that source image is too big, which unfortunately results in...this:
(because I dont have enough reputation for posting images, here is the link
http://postimg.org/image/f8wvs5si1/ )
Sorry for small amount of code and this picture taken via phone, I do not have an internet access on the computer with eclipse and this project for some time. I tried of course to change layout_height on other possibilites, but it didnt work. I could put a weight sum also on the vertical position, but on different screens it wouldn't look same.
I also tried to change the height programmatically in onCreate method,
buttonX.setHeight(buttonX.getWidth());
or do the same with a layout, but nothing helped
Perhaps the question is dumm, but I would be glad to hear some ideas.
This is due to screen density variations. There are several things you can do to fix this:
Use different images for each density (but I'm assuming you're looking for another solution)
Use DisplayMetrics to get the actual width of the screen and then set width/height accordingly.
This code:
buttonX.setHeight(buttonX.getWidth());
probably doesn't work because you are calling it before the layout is drawn, and therefore the width is not the drawn width. You can fix this using ViewTreeObserver like here:
How can you tell when a layout has been drawn?
Use an XML attribute like scaleType="centerFit" Personally, I find these confusing because scaleType attributes don't always seem to behave the same way to me. You might have to try different ones, but sometimes they come in handy if you need an XML only solution.

How to remove gaps between tiled textures?

I'm using LibGDX to make a platformer. I'm using square tiles for the platforms but when they are drawn some of them have gaps between them. When I zoom in/out or move the camera around the gaps move position.
More details:
Tiles are 32x32 and I have tried both 32x32 and 64x64.
Tiles are lined up 32 pixels apart (e.g. first tile would be x=0 y=0, second x=32 y=0, and so on in both x and y directions).
The gaps are not texture artifacts as I have checked this.
I use the TexturePacker with padding.
My best guess is that it is a problem when converting the textures to screen coords but have no idea how to fix this and I couldn't find any solution. I have checked and double-checked my precision with tile sizes and lining them up.
Has anyone had the same problem or know how it fix it?
I got it fixed by setting the duplicatePadding field of the TexturePacker.Settings class to true.
Example code:
import com.badlogic.gdx.tools.texturepacker.TexturePacker;
import com.badlogic.gdx.tools.texturepacker.TexturePacker.Settings;
Settings settings = new Settings();
settings.maxWidth = 1024;
settings.maxHeight = 1024;
settings.duplicatePadding = true;
TexturePacker.process(settings, "source", "destination", "name");
Well, I'm here to save your day!
The solution is called "Edge padding". Now if you are working with tilesets, I can assure you that this will work.
Personally I'm using Tiled which allows me to adjust margin and spacing in my tilesets. The only downside by this is that you'll have to use GIMP with this plugin: http://registry.gimp.org/node/26044
This plugin will let you apply edge padding to your tileset and voila! No more ugly artifacts.
Bleeding
Gaps
The short answer is that it may be your filter, which likely needs to be set to NEAREST.
Might also want to check out the working tutorials at Libgdx.
It's called "texture bleeding". You need to add padding to your tiles so that when the texture bleeds, it can collect the correct pixel data to fill the gap.
I know it's a bit late to answer on this post, but when I was looking for a solution I came here.
However, for me I found a much easier way to get rid of the flickering or gaps that appear randomly between the tiles.
I simply added a cast to the very long decimals I got for the player's position:
camera.position.set((int)robot.position.x, (int)robot.position.y, 0);
That made the player move very weirdly and to make him move smoothly again I added a cast to its render method aswell:
batcher.draw(robotSprite, (int)robot.position.x, (int)robot.position.y, 16, 16);
Et voilĂ ! Working perfectly for me.
I would post my solution here and what I had tried for Libgdx about this problem.
--
T1. Make original spritesheet (no atlas file) that downloaded from somewhere to padding 2.
A1. This would be impossible for repacking the spritesheet that have no atlas, even if you find a slice/splitter tool, it should be a bunch of images that need to be repack properly for TiledMap(.tmx)
A1(Updated). Script that provided by #Nine Magics would be the best way to do this! (I use this as my final solution)
--
T2. Use TiledMapPacker that provided by libgdx-nighty or gdx-toolg, The batch code should be:
java -classpath "gdx.jar";"gdx-natives.jar";"gdx-backend-lwjgl.jar";"gdx-backend-lwjgl-natives.jar";"gdx-tiled-preprocessor.jar";"extensions/gdx-tools/gdx-tools.jar" com.badlogic.gdx.tiledmappacker.TiledMapPacker "PathToYourProject\android\assets\RawMap" "PathToYourProject\android\assets\Map" --strip-unused
A2. The output .tmx that could not be readable by Tiled If you are using complex folder path to category your .png files. And the output file could be possibly failed to load by AtlasTmxMapLoader.
--
T3. Camera position correction, make camera position to integer. The code liked #Julian or #strangecat from libgdx tiledmap flicker with Nearest filtering
A3. I use this solution for no problem, and also post my code that different from them.
float cameraX = (int)(mainCamera.position.x * Game.PPM_X) / Game.PPM_X;
float cameraY = (int)(mainCamera.position.y * Game.PPM_X) / Game.PPM_X;
float cameraZ = mainCamera.position.z;
mainCamera.position.set(cameraX, cameraY, cameraZ);
And also load it with TmxMapLoader.Parameters
TmxMapLoader.Parameters params = new TmxMapLoader.Parameters();
params.textureMinFilter = Texture.TextureFilter.Linear;
params.textureMagFilter = Texture.TextureFilter.Nearest;
params.generateMipMaps = true;
assetManager.load(TILED_MAP_SETS.FIRST_MAP, TiledMap.class, params);
If you used PPM and want to move pixel by pixel, you could use this integer correction for your game, If not you could just convert the position to integer.
I almost wasted whole day to slove this, hope these investigation could help every game developers :)
Edit(2018/04/21)
I found out that Unity is also having the same problem, but I haven't tested If Libgdx have 2x Anti-Alias setting by default. Libgdx might fix the issue as Unity by turning off the Anti-Alias.

how to create universal UI design?

I would like to learn from experienced developers Android, as you develop a UI for different screens? For example, now I have this problem:
I have an element (TextView), which should be placed as nearly aligned to the left, but not back to back, but with a slight indentation. Accordingly, the bigger the screen, so this should become more padding. If it is set fixed (px / dp), as layout_marginLeft, it will remain so for all screens.
Or, like I have a button, which should take approximately the width of the percent of 60, while the remaining 40 percent are left blank. How can this be done without specifying a fixed size?
Is it possible to design a universal screen, which will stretch to compress the distance between the elements (as in my case), and do other similar things? Or is it necessary for each screen to create a resource directory and a separate design for each screen? How do you usually do that?
Thank you in advance for your reply, it is very important to me.
Some tips :
Use RelativeLayout when you want Views to be aligned with respect to each other.
Use LinearLayout with weight when you want that 60% - 40% thing
Use Custom Layouts when none of the above layouts work for you, i.e you want to customize its look and feel
It is alright to use different layouts for different screen sizes
Always use dip, - device independant pixels - instead of px
Read this article - Think like a web designer
Lastly read this article about supporting multiple screens.

Categories