Android rotate imageview in layout file - android

In my app each of the screens has a background image. I want to use the same image for portrait and landscape, but to make it look decent I need to rotate the image 90 degrees when in landscape so that it does not get stretched to fill the screen.
My solution was to just create two copies of the image one for portrait that I put in drawable-port and one for landscape that I put in drawable-land. Now that I have many different backgrounds my solution of just embedding a second copy of the image in my apk is causing the apk size to be much larger then needed.
How can I support rotated images, preferably in pure XML. In code I suppose you could just rotate the image before onStart and it would work, but I would really rather keep it in the XML if possible.
Thanks for the help!

I can't think of a way to do this in XML. But if you created a custom class that inherited from whichever view you're applying the background to (say, RelativeLayout), then you could do something like
#Override
protected void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight) {
if (newWidth > newHeight) { // landscape
// rotate the background
}
}
This way, you only have to implement the rotation once and all of your views would auto-rotate their backgrounds.

Related

How do you add a trimmed circular button image to your android drawable folder?

I'm trying to make a basic media player. I downloaded a free .png from a website for the circular play button but when I just copy and paste it into the drawable folder and add it as my ImageButton I can't scale it down to be the size of my other buttons and the background is gray.
How would I scale the button down and trim out the gray background?
1. You can scale the image so that it works on multiple devices by doing something like this:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Image img = yourImage.getScaledInstance((width * .10), (height * .10), Image.SCALE_DEFAULT);)
This is just an example, but it would resize the image so that it is close to a tenth of the size.
2. Another method would be to simply resize the image with a program like paint, and have the image much smaller. Although this is an immediate easy fix, the image size is not responsive to actual screen size.
3. ScaleType attribute is also a means to change size depending on how you are using the image asset in your code. (thank Parth Patel)
I used an ImageView instead which can basically do anything a button can and scaled it down. Looks great, thank you to #ParthPatel for giving me the answer.

Always have reliable orientation

Basically my goal is to set some custom View size exactly to 1/3 of the screen for portrait orientation and 1/6 for landscape
The first thought that came to my mind is to simply calculate some mSize variable and set it to the View in OnMeasure like this:
mSize = (AContext.getScreenSize().x / (orientation == Configuration.ORIENTATION_PORTRAIT ? 3 : 6)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(mSize|MeasureSpec.EXACTLY, mSize|MeasureSpec.EXACTLY);
}
And it's working just fine, till i rotate the screen. The thing is that when screen is rotating View initialization and sizing are called before the orientation value will actually change, so the result is that it goes one third to landscape also, if it was opened with portrait orientation firstly, and other way around.
I'm aware that i can do something like :
android:configChanges="orientation|screenSize"
In AndroidManifest for my Activity and override onConfigurationChanged to handle the rotation and change mSize value there, but, it disables auto choosing between portrait and landscape layouts(from .xml files on inflating). So i'm ending up with the same xml file for both orientations.
Is there a way to keep orientation value from context.getResources().getConfiguration().orientation consistent?
Or i need to do some workaround with onConfigurationChange to enable layout choosing?(i don't want to do it maually in code thou)
Or is there a better way to achieve my goal, and i'm just doing it wrong from the start?
Please help me.
first I would say to not use android:configChanges="orientation|screenSize" on this situation. It makes no sense such a thing on a custom view.
Secondly I believe the main mistake is the way you're capturing the 3, or 6 values. As you can achieve it much simpler using XML.
res/values/integers.xml
<integer name="view_fraction">3</integer>
res/values-land/integers.xml
<integer name="view_fraction">6</integer>
Then during your view constructor you simply call:
int val = context.getResources().getInteger(R.integer.view_fraction)
Furthermore, I will offer some other suggested improve on your view size calculation by suggesting you to simply use code that Google provides us, instead of trying to re-code it. Using the classes from android.support.percent
If your custom view extends from FrameLayout or RelativeLayout I would suggest you to instead extend from their percent counterpart PercentFrameLayout and PercentRelativeLayout.
If the custom view does not extends from one of those, you can use their helper PercentLayoutHelper following the guide on their page.
That way you can easily dinamically assing percentage of view size on your XML layout

How to use PrepareBitmap method for all the different sizes

The question is this: I have a picture I want to use it in a costum view, so I have to use the Preparebitmap methode where I have to specify the picutres which I want to draw and the Width/Height that the picture will take.
I created the image for all the sizes, I mean there's the same picture with different resulotion (I placed them in the drawable folders (ldpi, mdpi...)); so the main question is how to draw the bitmap to be shown perfectly with all the screen, maybe the following example will clear my problem:
appLogo = prepareBitmap(getResources().getDrawable(R.drawable.applogo), 100, 100);
the bitmap will be drawn in 100X100 space, so in bigger screens, the image will be small, even if it exist in the xx-hdpi folder. Is there any way how to get the real size of the image whatever the screen was ? I want something like:
appLogo = prepareBitmap(getResources().getDrawable(R.drawable.applogo), Height, Width);
with Height/Width are the real Height/Width of the image.
Thank you

android background image slows down app

I am using a viewpager to swipe amongst fragments in my app. I define the background in the XML, so
android:background="#drawable/bg_final"
If I use a simple background color, my app works very smooth. If I use it with this background image, fps decreases and my app becomes only passable. It is not slow, just not so smooth, however on weaker devices it could work laggy. Is it a bad way to apply a background image? The whole image is a 480x800 png with the size of 14.7kB. What might be the problem?
(the backgrounds of the fragments are transparent, the viewpager is in a main.xml which has its background with this image)
There are lots of answers out there that point to pre-scaling your bitmap. This is very imporant and you should do it if you can, however after trying several different things, the biggest performance gain I experienced was to create a view and override the onDraw method.
The class could be as simple as this:
public class DTImageView extends View {
public Bitmap imageBitmap;
public DTImageView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(imageBitmap != null)
canvas.drawBitmap(imageBitmap, 0, 0, null);
}
}
Invoke the code using a prescaled bitmap:
DTImageView bgImageView = new DTImageView(context);
bgImageView.imageBitmap = Bitmap.createScaledBitmap(bitmap,width,height,true);
At this point you can add this view to the view hierarchy where it belongs. In my case, my view hierarchy had a bgImage, a middle ground where all the other functionality happened, and fgImage.
Use the android sdk tool Hierarchy Viewer to profile the app and see how fast each view is taking to draw. My app spent 30-40ms drawing the bgImage and fgImage. Pre-scaling and overriding onDraw reduced that 30-40ms to about 1.5ms.
Here is a screenshot of the Draw performance for one of my views before and after:
BEFORE:
AFTER:
I'm a bit late, but this just bit me, and when running the GPU debugger, I noticed that the system scaled up my image! I had a 1920x1080 image, and it showed up as a 3780x6720 texture!
Ideally, you should have textures for each density in the respective folder (res/drawable-mdpi, res/drawable-hdpi, etc).
However, if you think your one texture is fine, put it into res/drawable-nodpi, not res/drawable. If you put it into res/drawable-nodpi, the system won't scale it up based on the dpi.
In my case, it changed a simple UI from 10fps on a Pixel XL to the full frame rate of 60fps.
I had a background image, not big in size, but with weird dimensions - therefore the stretching and bad performance. I made a method with parameters Context, a View and a drawable ID(int) that will match the device screen size. Use this in e.g a Fragments onCreateView to set the background.
public void setBackground(Context context, View view, int drawableId){
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId);
int width = Resources.getSystem().getDisplayMetrics().widthPixels;
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap);
view.setBackground(bitmapDrawable);
}
The reason for this could be that the image is being stretched, and Android has performance issues with stretching background images.
Instead, you should either replace the background image with either a background color or see this answer to have the image repeat instead of stretch.
I had the same problem and I resolved it by using this method:
Add your image to the mipmap folder which is located under the res directory. It will add the image according to it's density.
Create add only one background image with size 1080x1920 and put it in drawable-nodpi folder and that solved this problem

Handling different screen resolutions for background images in Android

My Android app (a text-based game) uses background images a lot in order to provide a better visual ambiance. For example, if the action in the game takes you into a tavern, then you get a background image of a tavern in the game. This is a vast improvement, graphically, over the boring black background that you would otherwise get.
It is also a problem, however, since android:background always stretches to the dimensions of the screen. The result is that the background images look very bad if the player switches between portrait and landscape mode. And to make matters worse, many devices have very different aspect ratios (e.g., 320x480 mdpi, 480x800 hdpi, and 480x852 hdpi) and even more variations are coming.
How do others solve this problem? Having individual images for the main resolutions/orientations is not an option for me, as this would result in the apk growing too large.
The first step is to get the screen height and width of the device itself, then stretch/shrink or pad your bitmap as needed. This SO answer has source that should help, copied below. Props to Josef for original answer.
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Here's generic source on getting the orientation.
int orientation = display.getOrientation();
or some more involved source from here (a little messy but looks correct).
public int getscrOrientation()
{
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = getOrient.getOrientation();
// Sometimes you may get undefined orientation Value is 0
// simple logic solves the problem compare the screen
// X,Y Co-ordinates and determine the Orientation in such cases
if(orientation==Configuration.ORIENTATION_UNDEFINED){
Configuration config = getResources().getConfiguration();
orientation = config.orientation;
if(orientation==Configuration.ORIENTATION_UNDEFINED){
//if height and widht of screen are equal then
// it is square orientation
if(getOrient.getWidth()==getOrient.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
}else{ //if widht is less than height than it is portrait
if(getOrient.getWidth() < getOrient.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else{ // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
return orientation; // return value 1 is portrait and 2 is Landscape Mode
}
I would suggest you get the width and height of your current view. Right now I am not sure what functions will give you these values but I am sure it is possible. With that you can then calculate an aspect ratio. I'd make the images something like 1000x1000 and just show a certain part of the image, so that the aspect ratio will not be wrong.
I have the same problem with the camera. So my solution was to pick one of the two values, width or height, as fixed, and calculate the correct other value according to the aspect ratio. I'm not sure if there are functions already to just show a part of the image, but I am sure you could write something to copy just a part of the image and show that part.
The drawback is of course that you will be showing just a part of the background. Since the general aspect ratio of the phones is however somewhere between 1:1.3 and 1:1.8 I guess it wouldn't be a too big problem. I for one would rather see the part of an image in the correct way, than looking at an ugly stretched image.
Maybe you could create your background images as NinePatch images so that you are in better control of how it stretches?
Otherwise, you can just prevent your images from stretching (or at least keep the correct aspect ratio) by setting the scaleType attribute e.g. android:scaleType="center".

Categories

Resources