We're working on the Android version of one of our games and we're having a problem with a background image. On iOS, it's really easy to scale the image down to the appropriate width and configure it to stretch vertically.
However, on Android, we can't figure out a way to do this. Basically, because of the myriad screen sizes and resolutions, we'd like to have our background image (which frames the play area) scale down to fit the width of the screen. Then, the bottom and top portions of the image should have the right aspect ratio but the middle part should tile (or stretch even) to fill the rest of the area.
We tried this with a nine-patch file but nine-patches don't scale down. We've tried it with LayerDrawables which works well except that it won't tile the middle as the size of the layout changes; it just stretches the entire image instead.
Is there any way to get a drawable to scale to fit horizontally and then tile a section to grow vertically?
Related
I have to display a splash image which has a round shaped object (a Ball). The Layout for splash is a simple linear layout with just a single Image view to occupy the full screen.
Image : single image with the size of 1280 x 720.
When my splash screen is shown in the App, The round object is shown in different shape in different screen sizes. I hope the aspect ratio and the resolution is the cause for these elongated images.
Could you please suggest an idea / approach to solve this ?
Do I need to consider the aspect ratio or the resolution or both ?
Finally the ball should look like a ball in all the devices :)
Thanks in Advance.
1) Yes, by default Android will scale your image down to fit the ImageView, maintaining the aspect ratio. However, make sure you're setting the image to the ImageView using android:src="..." rather than android:background="...". src= makes it scale the image maintaining aspect ratio, but background= makes it scale and distort the image to make it fit exactly to the size of the ImageView. (You can use a background and a source at the same time though, which can be useful for things like displaying a frame around the main image, using just one ImageView.)
2)You should also see android:adjustViewBounds to make the ImageView resize itself to fit the rescaled image. For example, if you have a rectangular image in what would normally be a square ImageView, adjustViewBounds=true will make it resize the ImageView to be rectangular as well. This then affects how other Views are laid out around the ImageView.
You can change the way it default scales images using the android:scaleType parameter. By the way, the easiest way to discover how this works would simply have been to experiment a bit yourself! Just remember to look at the layouts in the emulator itself (or an actual phone) as the preview in Eclipse is usually wrong.
Reference : How to scale an Image in ImageView to keep the aspect ratio
set imageView property
scaleType="centerInside"
Add scaled versions of the image with the same file name under folders 'res->drawable','res->drawable-ldpi','res->drawable-hdpi' and under xhdpi "http://developer.android.com/guide/practices/screens_support.html#DesigningResources"
I've tried as many permutations of scaleType and fillViewport and adjustViewBounds and layout_* as I can think of and none of them do what I want. They either fill the screen but lose the aspect ration (fillXY), cut off a portion of the image (centerCrop), or scale the image down so it doesn't fill the width of the screen (centerInside, fitStart, fitCenter, center, matrix).
Here is one specific example:
Source image is 222x470 pixels.
Emulator screen is 480x800hdpi in portrait orientation.
I want the ScrollView to fill the entire screen.
I want the ImageView to scale the image so it fills the width of the screen (stretching the source image from 222 wide to 480 wide).
I want the ImageView to preserve the aspect ratio of the source image, meaning its height will have to scale from 470 pixels to approximately 1016 pixels.
Since that won't fit on the screen (it is only 800 pixels high), the ScrollView should kick in. By default the top of the image should show and the ScrollView should allow scrolling down to see the rest of the image.
This is just one example. Ideally I'd like this to work regardless of image size and screen size.
Extra credit if you know a way to do it all within the XML layout.
And before y'all come down on me like a ton of bricks (or bricked cellphones?), I'm aware there are several similar questions on this site (see here, here, here, here, and here) but they are either unanswered or the answers are unacceptable ("use fitXY", which does not preserve aspect ratio, or require specifying exact pixel width/height in the ImageView which is not a general purpose solution to the problem). It'd be nice to get a solid answer to this documented and out there.
Answering my own question in the hopes it helps someone else.
I found a simple functional answer here. The AspectRatioImageView class works where all my XML scaling attempts failed.
Consider the above image.
- The dotted line demarcates the 9-Patch png I will slice out of a photoshop file. I need it to create a popup box.
- The box incorporates a dropShadow as shown by the measuring tool in this photo.
- The pink lines are there to show how I will use the draw9Patch tool to create the 9-Patch.
My question is: If I have a View "Container" with the 9-Patch for a background I need to ensure its children views are always inside the white box. I was going to use padding for this. I was going to set the padding to equal the measuring tool. So if it is 30px in photoshop I'll set layout_paddingLeft"=30dp" for the container. (The design is at MDPI so I assume this conversion is okay). However how do screens of different densities handle the 9path. For instance will the measured area be 30px or 30dip ?
Via the draw9patch tool you can define:
vertical stretching: the black pixels on the left side
horizontal stretching: the black pixels on the top side
vertical content: the black pixels on the right side
horizontal content: the black pixels on the bottom
Note that stretching pixels don't have to be contiguous, so you can exclude some specific slice from stretching (look at the popup arrow above). At he same time you can make a reasonable idea of where your content will be placed just taking a look at the preview on the right, with the violet areas in. As you can suppose, this way you don't have to specify any padding in your layout: the view will take into account those values using the 9patch you set as background.
The no-stretching areas scale with the pixel density. So, if you set the 9patch above as an mdpi asset, the top-leftmost slice is rendered in a 50x40 pixels area #mdpi, and in 100x80 pixels area #xhdpi. The leftmost stretching areas instead arrange their width according to dpi, while height is arranged according to content. Other stretching slices work in similar way.
In both cases, dealing with a "low resolution" 9patch can lead to ugly pixelation artifacts. A possible solution is to provide a different 9patch for each supported dpi, or to define only the higher ones (xhdpi) and let Android scale them down accordingly.
The content bounds are handled as dp too, so they scale according to pixel density. For example: a left padding defined in the original 9patch as 40px#mdpi, will be translated in 80px#xhdpi, so the content will never flow out the given bounds. Note you can even override the content bounds specified in 9patch via the padding* properties in your layout.
I would like to know why do we use nine-patch ? I know is to shrink or stretch images but if I want to resize an image can't we just do it on a dedicated image editor like gimp for example ?
What is 9-Patch?
9-Patch images are stretchable, repeatable images reduced to their smallest size; users draw a right and bottom, solid black 1 pixel border to tell the system how to place the content within the image.
The 9-Patch is a PNG image with an added extension to the file name (filename.9.png), which allows the Android system to determine how the image can be stretched and contorted to meet the specific layout constraints.
The Android operating system reads the borders of these images to understand how to properly stretch the image itself and the content within the image such as text and effects.
9-Patch Theory
9-Patch gets its name from the fact that the overlay created breaks the image up into nine defined regions. Each region has specific stretch properties:
Corner Regions (1, 3, 7, 9)
These regions are fixed and nothing inside them will stretch.
Horizontal Sides (4, 6)
The pixels in these region will stretch vertically when necessary.
Vertical Sides (2, 8)
The pixels in these region will stretch horizontally when necessary.
Center (5)
The pixels in this region will stretch in both horizontal and vertical directions equally.
here is Google docs
Nine patch image is very useful because it reduces your resource and one can maintain the curve shape which get stretch in normal .png.
Reduces resource : One can make a small NinePatch image and can stretch it as more as he can by repeating Pixel
Maintained border corner even if display size changes.
No need to give padding programmatically, you can reserve text area in NinePatch directly.
The top and left pixel border define the stretchable area. The bottom and right, however, define the CONTENT area. If you want the padding to go away, you need to make the bottom and right bar extend all the way to the edge of the artwork (not all the way to the corner pixels, though!). Basically, the right and bottom pixel border define your padding.
http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
http://www.developer.com/ws/android/programming/Working-with-NinePatch-Stretchable-Graphics-in-Android-3889086.htm
The advantage of using 9-patch images is that when using it as a background, for instance, the image won't stretch and loose proportions in different screen sizes. the center 'patch' will remain as is and the 'borders' patches will be stretched to fit the screen/view size.
one more and biggest advantage is memory. Same small size memory can be reused for different screen size devices.Well-designed 9-patch images are less error-prone and have high reusability. I had hard time optimizing the UI for different resolutions until I knew that Android supports 9-patch.
For padding as #hotveryspicy said you can use the padding box ( where your text button will be filled) to define your paddig values and they are defined like this:
padding-top: distance between the top edge of the padding box and the
top edge of your button
padding-bottom: distance between the buttom edge of the padding box and
the buttom edge of your button
padding-right: distance between the right edge of the padding box and
the right edge of your button
padding-left: distance between the left edge of the padding box and the
left edge of your button
Hope this will help you to have a clear idea and how important 9-patch drawable are
Nine-patch is used for dynamic stretching and shrinking of an image at runtime. That's the reason why it cannot be compared to statically resizing an image using an image editor.
Nine-patch is used for things like borders that dynamically size according to the content, so they have to stretch dynamically.
9-patch images aren't just scaled up; they're "stretched" in a defined way. The classic case is a button with rounded corners. If the button was just scaled, the radius of the corners would be enlarged too. With 9-patch images, the corners can be defined to stay the same size while the lengths of the edges are increased.
have you worked with css. if not then there is one property called repeat which gives you ability to repeat 1px image in to the width of 1040 and even more with out starching
9 path do the same, some time due to the different resolution of the images rather creating separate image for each phone create 9 patch image
Hope that help
Nine-patch allow you to strech just a part of an image, and not the whole image. It can be useful to design for example custom buttons, EditTexts, etc...
You can lean more here: http://developer.android.com/tools/help/draw9patch.html
Nine-patch is to do the stretching on the run time... If you use an Button with a custom background for example and say width-> fill_parent... there is a lot of different devices out there with different resolution how are you going to prepare images for all of them... you give a nine patch and its stretch on the run.
I have an application that needs to scale an image in relation to another image due to different screen size, I have an image that is essentially a background that matches the width of the screen and another image in a relative layout that is aligned so it fits on my phone in 2.2 but when seen on 2.1
Or ... i could just use something that scales the image as a percentage. Suggestions?
edit:
I guess all i need is to know how i can keep an image in a spot relative to another using relative layout and scale it through a percentage, different screen size will scale the other image but not this one because the other image fills the parent so when the screen size is smaller it just scales it down, however the one i need to scale does not because it doesn not fill the parent.