I've been trying to figure out how to do it, I have the size of the screen and the size of the emulator I use, how do I change the size to fit all devices (Including tablets and phones) and also position them correctly because it seems like the X and Y on a tablet is different than one that is on the phone.
EDIT:
I tried converting pixels to DPI that way:
public CreatorView(Context c) {
super(c);
this.c=c;
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
this.screenw= display.getWidth();
this.screenh=display.getHeight();
this.PixelDetect = BitmapFactory.decodeResource( getResources(), R.drawable.custom_pixel);
this.smallpixel = Bitmap.createScaledBitmap(PixelDetect, (int)getPixelsFromDip(3,c), (int)getPixelsFromDip(3,c), false);
this.grass=BitmapFactory.decodeResource(getResources(), R.drawable.block_grass);
this.grassSide=BitmapFactory.decodeResource(getResources(), R.drawable.block_grassside);
this.grassTop=BitmapFactory.decodeResource(getResources(), R.drawable.block_grasstop);
this.orange=BitmapFactory.decodeResource(getResources(), R.drawable.block_cube1);
this.dirt=BitmapFactory.decodeResource(getResources(), R.drawable.block_dirt);
this.dirt2=BitmapFactory.decodeResource(getResources(), R.drawable.block_dirt2);
this.dirt3=BitmapFactory.decodeResource(getResources(), R.drawable.block_dirt3);
this.arrowno=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_noclick);
this.arrown=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_normal);
this.arrowl=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_left);
this.arrowr=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_right);
this.arrowu=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_up);
this.arrowd=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_down);
this.arrowul=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_upperleft);
this.arrowur=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_upperright);
this.arrowdl=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_downleft);
this.arrowdr=BitmapFactory.decodeResource(getResources(), R.drawable.arrow_downright);
this.arrowno=Bitmap.createScaledBitmap(arrowno, arrowno.getWidth()*3, arrowno.getHeight()*3, false);
this.save=BitmapFactory.decodeResource(getResources(), R.drawable.button_save);
this.bin_Empty=BitmapFactory.decodeResource(getResources(), R.drawable.bin_empty);
this.bin_Full=BitmapFactory.decodeResource(getResources(), R.drawable.bin_full);
this.bin_Empty=Bitmap.createScaledBitmap(bin_Empty, bin_Empty.getWidth()*3, bin_Empty.getHeight()*3, false);
this.bin_Full=Bitmap.createScaledBitmap(bin_Full, bin_Full.getWidth()*3, bin_Full.getHeight()*3, false);
this.arrown=Bitmap.createScaledBitmap(arrown, arrown.getWidth()*3, arrown.getHeight()*3, false);
this.arrowl=Bitmap.createScaledBitmap(arrowl, arrowl.getWidth()*3, arrowl.getHeight()*3, false);
this.arrowr=Bitmap.createScaledBitmap(arrowr, arrowr.getWidth()*3, arrowr.getHeight()*3, false);
this.arrowu=Bitmap.createScaledBitmap(arrowu, arrowu.getWidth()*3, arrowu.getHeight()*3, false);
this.arrowd=Bitmap.createScaledBitmap(arrowd, arrowd.getWidth()*3, arrowd.getHeight()*3, false);
this.arrowul=Bitmap.createScaledBitmap(arrowul, arrowul.getWidth()*3, arrowul.getHeight()*3, false);
this.arrowur=Bitmap.createScaledBitmap(arrowur, arrowur.getWidth()*3, arrowur.getHeight()*3, false);
this.arrowdl=Bitmap.createScaledBitmap(arrowdl, arrowdl.getWidth()*3, arrowdl.getHeight()*3, false);
this.arrowdr=Bitmap.createScaledBitmap(arrowdr, arrowdr.getWidth()*3, arrowdr.getHeight()*3, false);
Menu_Add(arrowno,0,true,"arrows");
Menu_Add(bin_Empty,1,false,"bin");
Menu_Add(save,2,false,"save");
Menu_Add(grassTop,1,true,"grasstop");
Menu_Add(grassSide,2,true,"grassside");
Menu_Add(grass,3,true,"grass");
Menu_Add(dirt,4,true,"dirt");
Menu_Add(orange,5,true,"orange");
arrowsp=new Point();
arrowsp.x=0;
arrowsp.y=0;
}
private void Menu_Add(Bitmap b,int order,boolean vertical,String name)
{
Point p=new Point();
if(order==0){
p.x=0;
p.y=0;
MenuButton m=new MenuButton(order,b , vertical, p,name);
menuButtonList.add(m);
}
else{
for (MenuButton m : menuButtonList) {
if((m.isVertical()==vertical||order==1)&&m.getOrder()+1==order ){
if(vertical){
p.x=0;
p.y=m.getP().y+m.getBit().getHeight()+(int)getPixelsFromDip(2,c);
}
else{
p.x=m.getP().x+m.getBit().getWidth()+(int)(getPixelsFromDip(2,c));
p.y=0;
}
MenuButton m2=new MenuButton(order,b , vertical, p,name);
menuButtonList.add(m2);
return;
}
}
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paintAlpha = new Paint();
paintAlpha.setAlpha(200);
canvas.drawARGB(255, 86, 194, 243);
for(MenuButton m : menuButtonList){
switch(m.getName()){
case "bin":
if(bin_isEmpty){
canvas.drawBitmap(bin_Empty, getPixelsFromDip(m.getP().x,c), getPixelsFromDip(m.getP().y,c),paintAlpha);
}
else{
canvas.drawBitmap(bin_Full, getPixelsFromDip(m.getP().x,c), getPixelsFromDip(m.getP().y,c),paintAlpha);
}
break;
case "arrows":
canvas.drawBitmap(m.getBit(),getPixelsFromDip(m.getP().x,c),getPixelsFromDip(m.getP().y,c),paintAlpha);
switch (arrowcheck) {
case "normal":
canvas.drawBitmap(arrown, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "left":
canvas.drawBitmap(arrowl, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "right":
canvas.drawBitmap(arrowr, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "down":
canvas.drawBitmap(arrowd, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "up":
canvas.drawBitmap(arrowu, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "upleft":
canvas.drawBitmap(arrowul, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "upright":
canvas.drawBitmap(arrowur, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "downleft":
canvas.drawBitmap(arrowdl, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
case "downright":
canvas.drawBitmap(arrowdr, getPixelsFromDip(arrowsp.x,c), getPixelsFromDip(arrowsp.y,c),paintAlpha);
break;
}
break;
default:
canvas.drawBitmap(m.getBit(),getPixelsFromDip(m.getP().x,c),getPixelsFromDip(m.getP().y,c),paintAlpha);
break;
}
}
}
public static float getPixelsFromDip(float dip,Context context)
{
//TODO move this to aplication class?
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, context.getResources().getDisplayMetrics());
}
this is how it shows in the emulator (correct):
http://puu.sh/ehhHp/05c1530218.png
this is how it shows in my phone:
http://puu.sh/ehhKX/b28ee357e3.png
please help :(
What you don't want to do is to use pixels. What you most probably also don't want to do is to speficy the width/height using dps unless you're prepared to set different values for your different resolution devices (by specifying the values in #dimen and overriding them for different sizes).
If you know approximately how much of the screen width (or height) you would like your ImageView to occupy, the easiest thing you can do to achieve it is to use weights within a LinearLayout.
An example would be this (handwritten and missing all the NS prefixes)
<LinearLayout
...
...
orientation=vertical>
<some empty filler here with weight=1 and width="match_parent"/>
<ImageView
...
...
width="match_parent"
scaleType=fitCenter (or whatever works for your images)
weight=1 />
<some empty filler here with weight=1 width="match_parent"/>
</LinearLayout>
What this would do is to make sure your ImageView takes 1/3rd of the screen width as determined by weights. You then control the image scaling by setting the correct scaleType. This will work universally across all phone sizes and tablets and will always take 1/3rd of the width of the screen regardless of the resolution or the orientation of the device (which may or may not be what you want).
You can also play around with the weights if you want more/less than 1/3rd of the screen width for your images.
Other solutions (using dp for instance) are already mentioned but they're a bit more involved in that you have to override them for different resolutions as described above.
Why not use percents?
As example - percent_x = device.widht / 100;
And begin draw image in this position * percent_x?
In every device if should be look similar, but with streches.
use dp to define width and height of image. Or we can calculate the percentage of image size of our screen.
ok if you use an xml layout just defing layout_width and layout_hight using density pixel value "10dp" for example. those scale with the screen size so you get the same result according to screen size.
if you use canvas then when you set the hight and width of an objecs use the following method:
/**
* get width or hight as density independent pixels and return the real
* amount of pixels requiered for the current screen
* used to programaticlly set width and hight using dip
* #param dip - the amount of dip
* #param context - the activity used in
* #return - return the real amount of pixels required for the current screen
*/
public static float getPixelsFromDip(float dip,Context context)
{
//TODO move this to aplication class?
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, context.getResources().getDisplayMetrics());
}
another option is to calculate max screen size, and the precent from it you need
here is the method for the max size:
/**
* get maximum width and hight as dp avaliable in the screen
* #param context
* #return
*/
public static float[] getMaxPixels(Context context)
{
//TODO move this to application class
float result[]=new float[2];
DisplayMetrics displayMetrics=context.getResources().getDisplayMetrics();
float screenWidthInDp=displayMetrics.widthPixels/displayMetrics.density;
float screenHeightInDp=displayMetrics.heightPixels/displayMetrics.density;
result[0]=screenWidthInDp;
result[1]=screenHeightInDp;
return result;
}
last but not least rule of thumb density is:mdpi=1, hdpi=1.5 and ldpi is 0.75
so once you get the pixels for one screen size you can multiply by those values to get a rough estimate for the value in the other
enjoy.
Positioning in terms of pixels will definitely differ as there are different type of devices with different DPI.
So declaring Imageview with widht, height in dp should serve your problem. Coming to position, it should be maintained Relatively or through gravity.
We need your code to understand what exactly the problem is and what more you need.
EDIT:
Convert Dip to pixel and the apply it to your Bitmap size.
It will maintain physical size and gets resolution according to device.
public static int convertDipToPixels(float dips)
{
return (int) (dips * appContext.getResources().getDisplayMetrics().density + 0.5f);
}
Edit 2:
Just give a trail changing your loop with this code snippet and check it it replicates same on all devices
for (MenuButton m : menuButtonList) {
if((m.isVertical()==vertical||order==1)&&m.getOrder()+1==order ){
if(vertical){
p.x=0;
p.y=(int)getPixelsFromDip(100,c);
}
else{
p.x=m(int)(getPixelsFromDip(100,c));
p.y=0;
}
MenuButton m2=new MenuButton(order,b , vertical, p,name);
menuButtonList.add(m2);
return;
}
}
Related
Context & Goal
I'm building a real-time object detection app. To achieve this, I need a bitmap to send to the recognition algorithm. I have an activity displaying the camera output in full screen, but I'm trying to operate the recognition only on the central square of the screen. So I need a bitmap with those dimensions and position, corresponding to the the central square of the phone screen.
What I have tried
#Override
public void onPreviewSizeChosen(final Size size, final int rotation) {
/* some code... */
// Width of the screen (larger than the height), for my phone it's 4032
previewWidth = size.getWidth();
// Height of the screen, for my phone it's 1980
previewHeight = size.getHeight();
sensorOrientation = rotation - getScreenOrientation();
// The bitmap which will be used to the recognition, dimension : full screen of the phone
rgbFrameBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
// squared bitmap 320x320, required size for the recognition algorithm
croppedBitmap = Bitmap.createBitmap(cropSize, cropSize, Config.ARGB_8888);
// bitmap to croppedBitmap transform Matrix
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewWidth, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
cropToFrameTransform = new Matrix();
frameToCropTransform.invert(cropToFrameTransform);
trackingOverlay = (OverlayView) findViewById(R.id.tracking_overlay);
trackingOverlay.addCallback(
new DrawCallback() {
#Override
public void drawCallback(final Canvas canvas) {
tracker.draw(canvas, isDebug());
}
});
tracker.setFrameConfiguration(previewWidth, previewHeight, sensorOrientation);
}
#Override
protected void processImage() {
trackingOverlay.postInvalidate();
if (computingDetection) {
readyForNextImage();
return;
}
computingDetection = true;
// THE LINE I CAN'T FIGURE OUT
// I try to set width and height = previewHeight (1980 for my phone so a square)
// and to move it down by (previewWidth-previewHeight)/2 so it goes in the middle of the screen
rgbFrameBitmap.setPixels(getRgbBytes(), 0, previewWidth, 0, (previewWidth-previewHeight)/2, previewHeight, previewHeight);
readyForNextImage();
final Canvas canvas = new Canvas(croppedBitmap);
canvas.drawBitmap(rgbFrameBitmap, frameToCropTransform, null);
// Saved set to true, so I can check what the bitmap sent to the recognition algorithm looks like
if (SAVE_PREVIEW_BITMAP) {
ImageUtils.saveBitmap(croppedBitmap);
}
runInBackground(
new Runnable() {
#Override
public void run() {
// Here we send the bitmap to the recognition algorithm to perform real-time detection
final List<Classifier.Recognition> results = detector.recognizeImage(croppedBitmap);
/* some code ... */
}
If I replace the (previewWidth-previewHeight)/2 by 0 as the y parameter of rgbFrameBitmap.setPixels() function, I manage to perform real-time recognition in a square on top of the screen, as I want unless it's not centered. But as soon as I set the y parameter to (previewWidth-previewHeight)/2, this is the error I get when it tries to save the bitmap :
W/ImageReader_JNI: Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers
How can I get the bitmap to be centered in the middle of the screen ?
Self solved
There are two thing I misunderstood on the above code.
First, I mixed up the x and the y parameters of the rgbFrameBitmap.setPixels() function, but in any case this was just adding some black space to the bitmap. To obtain the center of the screen, the parameter to change is the offset, like this :
int x = (previewWidth-previewHeight)/2;
rgbFrameBitmap.setPixels(getRgbBytes(), x, previewWidth, 0, 0, previewHeight, previewHeight);
Besides, as we send the croppedBitmap to the recognition algorithm, which is the rgbFrameBitmap cropped to 320x320 thanks to the matrix frameToCropTransform, I had to update this :
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewWidth, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
into this :
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewHeight, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
as rgbFrameBitmap is now a square of dimensions previewHeightxpreviewHeight
Horizontal Screen
To get the central square area of a screen, compare height and width of the screen in pixels. Usually for desktop systems width is bigger, and I will assume this is the case.
Get the difference width-height, divide by two and call it x.
Finally draw a rectangle from (x, 0) to (x+height, height).
More General
The side length of the square will be length = min(width,height)
The coordinates of the square will be
x = (width-length)/2
y = (height-length)/2
Finally draw a rectangle from (x, y) to (x+length, y+length).
I am trying to draw an image that is larger than the screen, and let the user scroll around it. The image is some graphs that are calculated by my code from some data. (This is in Android using Java).
What I want is a View (actually a SurfaceView) that can be scrolled by the user. I have tried putting a SurfaceView inside a ScrollView but the whole image drawn by the SurfaceView is very large and so (a) there are performance issues as my app is drawing the whole SurfaceView when it should only need to do the part that is in the viewport and (b) my app crashes with "dimensions too large... out of memory" errors.
It would be best for me if the View could implement scrolling (vertical only) and then pass the y-value to my code so it could draw the visible part of my image in the viewport.
Alternatively I could capture the 'mouse' events and calculate the y-value myself.
Does anyone have any code so that I can do this?
Update: I should clarify, the image is drawn by my program code using Canvas.drawLine() and the like. I can calculate which parts of the image fit within my viewport, provided I have the state of the scroll as a y-value, and I can calculate the absolute y-coordinate of each point by subtracting scroll y-value. What I need is something that works to find when the user scrolls the image and what the resulting y-value is. A scrollbar would also be nice.
Update: I am using SurfaceView so that I can update the image from another Thread and so improve user interface performance.
if you really have just a draw content... you don't need a scrollable client then...
have a model (x,y,lines, etc)
have a pan & zoom
draw a scaled/zoomed instance of the model
just draw the content (sorry - no scroller in this solution)
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean isProcessed = scaleGestureDetector.onTouchEvent(event);
if (isProcessed) {
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
start.set(event.getX(), event.getY());
tap( event.getX(), event.getY() );
mode = DRAG_OR_TAP;
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG_OR_TAP) {
doPan(event.getX() - start.x, event.getY() - start.y);
start.set(event.getX(), event.getY());
}
break;
}
}
myView.scale(currentPan, currentScaleFactor);
invalidate();
return true;
}
private void doPan(float panX, float panY) {
currentPan.x = currentPan.x + panX;
currentPan.y = currentPan.y + panY;
}
private void tap(float x, float y) {
...
}
and last not least use the scaleListener
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
float value = detector.getScaleFactor();
currentScaleFactor = currentScaleFactor * value;
// don't let the object get too small or too large.
boolean doesntMatch = false;
if (currentScaleFactor < 1f || currentScaleFactor > 20f){
currentScaleFactor = Math.max(1f, Math.min(currentScaleFactor, 20f));
doesntMatch = true;
}
if(!doesntMatch){
//scale the viewport as well
currentPan.x = currentPan.x*value;
currentPan.y = currentPan.y*value;
}
return true;
}
}
you can simply use a WebView to display an image
provides pan
provides zoom
no library required
has a scrollbar
Android: Easiest way to make a WebView display a Bitmap?
i'm not sure if i really hit your question...
The view got pixilated during animation I just wanted to attain a little tilt while the I try to scroll. I am using the Universal-Image-Library to hanle the animation. I'd like to attain a 3D look when tilting the view.
The first picture, is what I want.
But this picture below, I what I have. The View below got pixilated.
private void rotateLeftFrag(View af) {
if (af != null) {
ObjectAnimator.ofFloat(af, "rotationY", 5, 0)
.setDuration(100).start();
}
}
ObjectAnimator com.nineoldandroids.animation.ObjectAnimator.ofFloat(Object target, String
propertyName, float... values)
Are there any resolve to this to attain smooth animation or titling of the view? Thanks
Update:
float density = getResources().getDisplayMetrics().density;
float scale = getResources().getDisplayMetrics().density;
af.setCameraDistance(density * scale);
ObjectAnimator.ofFloat(af, "rotationY", .5f, 0).setDuration(500).start();
I think this video could help you:
http://www.youtube.com/watch?v=pMcu35-tVls
At 2:10 the guy talks about adding 1 extra transparent pixel to each side of a rotating rectangle. That should help smoothing out the edges because they would be inside the rectangle, not on the border.
Link to the source code is below the video.
In case you can't see it:
http://developer.android.com/shareables/devbytes/CardFlip.zip
Class you want to see is CardView, method bitmapWithBorder:
private static final int ANTIALIAS_BORDER = 1;
/**
* Adding a 1 pixel transparent border around the bitmap can be used to
* anti-alias the image as it rotates.
*/
private BitmapDrawable bitmapWithBorder(BitmapDrawable bitmapDrawable) {
Bitmap bitmapWithBorder = Bitmap.createBitmap(bitmapDrawable.getIntrinsicWidth() +
ANTIALIAS_BORDER * 2, bitmapDrawable.getIntrinsicHeight() + ANTIALIAS_BORDER * 2,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmapWithBorder);
canvas.drawBitmap(bitmapDrawable.getBitmap(), ANTIALIAS_BORDER, ANTIALIAS_BORDER, null);
return new BitmapDrawable(getResources(), bitmapWithBorder);
}
Please try to turn off hardware rendering
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
mHeaderImage.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
I am a beginner who is learning to write games in JAVA.
In the game I am writing, I am trying to get it to support multiple displayModes. First let me tell you a little about how I'm setting the display setting in the first place.
In the beginning of the code, I have an list of display modes I wish to support
//List of supported display modes
private static DisplayMode modes[] = {
new DisplayMode(640, 480, 32, 0),
new DisplayMode(1024, 768, 32, 0),
};
I then get a list of supported display Modes from the Video Card, comparing the list and use the first matching display mode.
/////////////////////////////////////////////
////Variable Declaration
/////////////////////////////////////////////
private GraphicsDevice vc;
/////////////////////////////////////////////
//Give Video Card Access to Monitor Screen
/////////////////////////////////////////////
public ScreenManager(){
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
vc = e.getDefaultScreenDevice();
}
/////////////////////////////////////////////
//Find Compatible display mode
/////////////////////////////////////////////
//Compare Display mode supported by the application and display modes supported by the video card
//Use the first matching display mode;
public DisplayMode findFirstCompatibleMode(DisplayMode modes[]){
DisplayMode goodModes[] = vc.getDisplayModes();
for(int x=0; x<modes.length; x++){
for(int y=0; y<goodModes.length; y++){
if (displayModesMatch(modes[x], goodModes[y])){
return modes[x];
}
}
}
return null;
}
/////////////////////////////////////////////
//Checks if two Display Modes match each other
/////////////////////////////////////////////
public boolean displayModesMatch(DisplayMode m1, DisplayMode m2){
//Test Resolution
if (m1.getWidth() != m2.getWidth() || m1.getHeight() != m2.getHeight()){
return false;
}
//Test BitDepth
if (m1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI
&& m1.getBitDepth() != m2.getBitDepth()){
return false;
}
//Test Refresh Rate
if (m1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN &&
m2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN &&
m1.getRefreshRate() != m2.getRefreshRate()){
return false;
}
return true;
}
Currently, I am only supporting two resolutions, 640x480 and 1024x768.
In order to have every element of my game available in both resolutions, first I find how much the screen is resized and store this value in a variable called resizeRatio
private void getResizeRatio(){
resizeRatio = (double)1024/(double)s.getWidth();
//s.getWidth() returns the current width of the screen.
}
And with every image I import, i would divide the image height and width by this resizeRatio.
/////////////////////////////////////////////
//Scale the image to the right proportion for the resolution
/////////////////////////////////////////////
protected Image scaleImage(Image in){
Image out = in.getScaledInstance((int)(in.getWidth(null)/resizeRatio), (int)(in.getHeight(null)/resizeRatio), Image.SCALE_SMOOTH);
return out;
}
This is all fine and good, until my application grew bigger and bigger. Soon I realize I forgot to resize some of the icons, and they are all at the wrong place when resolution is 640x480.
Additionally, I realize I must scale, not just the size of all my images, but all the movement speed, and all the positions as well, since having my character move at 5px per refresh makes him move significantly faster when displayed at 640x480 than when displayed at 1024x768
So my question is, instead of individually scaling every image, every icon, and every movement, is there a way to scale everything all at once? Or rather, there must be another way of doing this so could someone please tell me?
Thank you for reading and any help would be much appreciated.
In the paintComponent(Graphics g) or paint method you can do with Graphics2D.scale:
private double scale = 0.75;
#override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g; // The newer more ellaborate child class.
g2.scale(scale, scale);
...
g2.scale(1/scale, 1/scale);
}
How can I check if the Android phone is in Landscape or Portrait?
The current configuration, as used to determine which resources to retrieve, is available from the Resources' Configuration object:
getResources().getConfiguration().orientation;
You can check for orientation by looking at its value:
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// In landscape
} else {
// In portrait
}
More information can be found in the Android Developer.
If you use getResources().getConfiguration().orientation on some devices you will get it wrong. We used that approach initially in http://apphance.com. Thanks to remote logging of Apphance we could see it on different devices and we saw that fragmentation plays its role here.
I saw weird cases: for example alternating portrait and square(?!) on HTC Desire HD:
CONDITION[17:37:10.345] screen: rotation: 270 orientation: square
CONDITION[17:37:12.774] screen: rotation: 0 orientation: portrait
CONDITION[17:37:15.898] screen: rotation: 90
CONDITION[17:37:21.451] screen: rotation: 0
CONDITION[17:38:42.120] screen: rotation: 270 orientation: square
or not changing orientation at all:
CONDITION[11:34:41.134] screen: rotation: 0
CONDITION[11:35:04.533] screen: rotation: 90
CONDITION[11:35:06.312] screen: rotation: 0
CONDITION[11:35:07.938] screen: rotation: 90
CONDITION[11:35:09.336] screen: rotation: 0
On the other hand, width() and height() is always correct (it is used by window manager, so it should better be). I'd say the best idea is to do the width/height checking ALWAYS. If you think about a moment, this is exactly what you want - to know if width is smaller than height (portrait), the opposite (landscape) or if they are the same (square).
Then it comes down to this simple code:
public int getScreenOrientation()
{
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = Configuration.ORIENTATION_UNDEFINED;
if(getOrient.getWidth()==getOrient.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
} else{
if(getOrient.getWidth() < getOrient.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else {
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
return orientation;
}
Another way of solving this problem is by not relying on the correct return value from the display but relying on the Android resources resolving.
Create the file layouts.xml in the folders res/values-land and res/values-port with the following content:
res/values-land/layouts.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="is_landscape">true</bool>
</resources>
res/values-port/layouts.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="is_landscape">false</bool>
</resources>
In your source code you can now access the current orientation as follows:
context.getResources().getBoolean(R.bool.is_landscape)
A fully way to specify the current orientation of the phone:
public String getRotation(Context context) {
final int rotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getOrientation();
switch (rotation) {
case Surface.ROTATION_0:
return "portrait";
case Surface.ROTATION_90:
return "landscape";
case Surface.ROTATION_180:
return "reverse portrait";
default:
return "reverse landscape";
}
}
Here is code snippet demo how to get screen orientation was recommend by hackbod and Martijn:
❶ Trigger when change Orientation:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int nCurrentOrientation = _getScreenOrientation();
_doSomeThingWhenChangeOrientation(nCurrentOrientation);
}
❷ Get current orientation as hackbod recommend:
private int _getScreenOrientation(){
return getResources().getConfiguration().orientation;
}
❸There are alternative solution for get current screen orientation ❷ follow Martijn solution:
private int _getScreenOrientation(){
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
return display.getOrientation();
}
★Note:
I was try both implement ❷ & ❸, but on RealDevice (NexusOne SDK 2.3) Orientation it returns the wrong orientation.
★So i recommend to used solution ❷ to get Screen orientation which have more advantage: clearly, simple and work like a charm.
★Check carefully return of orientation to ensure correct as our expected (May be have limited depend on physical devices specification)
Hope it help,
int ot = getResources().getConfiguration().orientation;
switch(ot)
{
case Configuration.ORIENTATION_LANDSCAPE:
Log.d("my orient" ,"ORIENTATION_LANDSCAPE");
break;
case Configuration.ORIENTATION_PORTRAIT:
Log.d("my orient" ,"ORIENTATION_PORTRAIT");
break;
case Configuration.ORIENTATION_SQUARE:
Log.d("my orient" ,"ORIENTATION_SQUARE");
break;
case Configuration.ORIENTATION_UNDEFINED:
Log.d("my orient" ,"ORIENTATION_UNDEFINED");
break;
default:
Log.d("my orient", "default val");
break;
}
Some time has passed since most of these answers have been posted and some use now deprecated methods and constants.
I've updated Jarek's code to not use these methods and constants anymore:
protected int getScreenOrientation()
{
Display getOrient = getWindowManager().getDefaultDisplay();
Point size = new Point();
getOrient.getSize(size);
int orientation;
if (size.x < size.y)
{
orientation = Configuration.ORIENTATION_PORTRAIT;
}
else
{
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
return orientation;
}
Note that the mode Configuration.ORIENTATION_SQUARE isn't supported anymore.
I found this to be reliable on all devices I've tested it on in contrast to the method suggesting the usage of getResources().getConfiguration().orientation
Use getResources().getConfiguration().orientation it's the right way.
You just have to watch out for different types of landscapes, the landscape that the device normally uses and the other.
Still don't understand how to manage that.
Check screen orientation in runtime.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
There is one more way of doing it:
public int getOrientation()
{
if(getResources().getDisplayMetrics().widthPixels>getResources().getDisplayMetrics().heightPixels)
{
Toast t = Toast.makeText(this,"LANDSCAPE",Toast.LENGTH_SHORT);
t.show();
return 1;
}
else
{
Toast t = Toast.makeText(this,"PORTRAIT",Toast.LENGTH_SHORT);
t.show();
return 2;
}
}
The Android SDK can tell you this just fine:
getResources().getConfiguration().orientation
Tested in 2019 on API 28, regardless of the user has set portrait orientation or not, and with minimal code compared to another, outdated answer, the following delivers the correct orientation:
/** #return The {#link Configuration#ORIENTATION_SQUARE}, {#link Configuration#ORIENTATION_PORTRAIT}, {#link Configuration#ORIENTATION_LANDSCAPE} constants based on the current phone screen pixel relations. */
private int getScreenOrientation()
{
DisplayMetrics dm = context.getResources().getDisplayMetrics(); // Screen rotation effected
if(dm.widthPixels == dm.heightPixels)
return Configuration.ORIENTATION_SQUARE;
else
return dm.widthPixels < dm.heightPixels ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
Just simple two line code
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// do something in landscape
} else {
//do in potrait
}
such this is overlay all phones such as oneplus3
public static boolean isScreenOrientationPortrait(Context context) {
return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
}
right code as follows:
public static int getRotation(Context context) {
final int rotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getOrientation();
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
return Configuration.ORIENTATION_PORTRAIT;
}
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
return Configuration.ORIENTATION_LANDSCAPE;
}
return -1;
}
I think this code may work after orientation change has take effect
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = getOrient.getOrientation();
override Activity.onConfigurationChanged(Configuration newConfig) function and use newConfig,orientation if you want to get notified about the new orientation before calling setContentView.
i think using getRotationv() doesn't help because
http://developer.android.com/reference/android/view/Display.html#getRotation%28%29
getRotation() Returns the rotation of the screen from its "natural" orientation.
so unless you know the "natural" orientation, rotation is meaningless.
i found an easier way,
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
if(width>height)
// its landscape
please tell me if there is a problem with this someone?
Old post I know. Whatever the orientation may be or is swapped etc. I designed this function that is used to set the device in the right orientation without the need to know how the portrait and landscape features are organised on the device.
private void initActivityScreenOrientPortrait()
{
// Avoid screen rotations (use the manifests android:screenOrientation setting)
// Set this to nosensor or potrait
// Set window fullscreen
this.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
DisplayMetrics metrics = new DisplayMetrics();
this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// Test if it is VISUAL in portrait mode by simply checking it's size
boolean bIsVisualPortrait = ( metrics.heightPixels >= metrics.widthPixels );
if( !bIsVisualPortrait )
{
// Swap the orientation to match the VISUAL portrait mode
if( this.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT )
{ this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ); }
}
else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); }
}
Works like a charm!
Use this way,
int orientation = getResources().getConfiguration().orientation;
String Orintaion = "";
switch (orientation)
{
case Configuration.ORIENTATION_UNDEFINED: Orintaion = "Undefined"; break;
case Configuration.ORIENTATION_LANDSCAPE: Orintaion = "Landscrape"; break;
case Configuration.ORIENTATION_PORTRAIT: Orintaion = "Portrait"; break;
default: Orintaion = "Square";break;
}
in the String you have the Oriantion
there are many ways to do this , this piece of code works for me
if (this.getWindow().getWindowManager().getDefaultDisplay()
.getOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
// portrait mode
} else if (this.getWindow().getWindowManager().getDefaultDisplay()
.getOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
// landscape
}
Simple and easy :)
Make 2 xml layouts ( i.e Portrait and Landscape )
At java file, write:
private int intOrientation;
at onCreate method and before setContentView write:
intOrientation = getResources().getConfiguration().orientation;
if (intOrientation == Configuration.ORIENTATION_PORTRAIT)
setContentView(R.layout.activity_main);
else
setContentView(R.layout.layout_land); // I tested it and it works fine.
I think this solution easy one
if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
user_todat_latout = true;
} else {
user_todat_latout = false;
}
It's also worth noting that nowadays, there's less good reason to check for explicit orientation with getResources().getConfiguration().orientation if you're doing so for layout reasons, as Multi-Window Support introduced in Android 7 / API 24+ could mess with your layouts quite a bit in either orientation. Better to consider using <ConstraintLayout>, and alternative layouts dependent on available width or height, along with other tricks for determining which layout is being used, e.g. the presence or not of certain Fragments being attached to your Activity.
You can use this (based on here) :
public static boolean isPortrait(Activity activity) {
final int currentOrientation = getCurrentOrientation(activity);
return currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT || currentOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
public static int getCurrentOrientation(Activity activity) {
//code based on https://www.captechconsulting.com/blog/eric-miles/programmatically-locking-android-screen-orientation
final Display display = activity.getWindowManager().getDefaultDisplay();
final int rotation = display.getRotation();
final Point size = new Point();
display.getSize(size);
int result;
if (rotation == Surface.ROTATION_0
|| rotation == Surface.ROTATION_180) {
// if rotation is 0 or 180 and width is greater than height, we have
// a tablet
if (size.x > size.y) {
if (rotation == Surface.ROTATION_0) {
result = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
result = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
} else {
// we have a phone
if (rotation == Surface.ROTATION_0) {
result = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else {
result = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
}
}
} else {
// if rotation is 90 or 270 and width is greater than height, we
// have a phone
if (size.x > size.y) {
if (rotation == Surface.ROTATION_90) {
result = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
result = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
} else {
// we have a tablet
if (rotation == Surface.ROTATION_90) {
result = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
} else {
result = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
}
}
return result;
}
I think this solution easy one to check is Landscape
public static boolean isLandscape(Context context) {
final int rotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
return false;
}
return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
}