I have countdown functionality in my app.
Every second a timer sets the current time to a TextView.
So strings are: "56:05","56:04","56:03","56:02"...
I want to make the text size as big as possible
Therefore I've written the following code.
private void measureAndSetText(String text) {
Paint pMeasure = new Paint();
Integer iWidth = _tvContent.getWidth();
Float maxTextSize = 1000f;
pMeasure.setTextSize(maxTextSize);
pMeasure.setFakeBoldText(true);
Float fCurrentWidth = pMeasure.measureText(text);
while (fCurrentWidth > iWidth) {
pMeasure.setTextSize(maxTextSize -= 1);
fCurrentWidth = pMeasure.measureText(text);
}
_tvContent.setText(text);
_tvContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);
}
This code seems to work on my Note2, Lg Optimus 4x HD, Galay ACE and some others.
But not on my Xperia Z in landscape mode.
I guess the reason is the Full Hd Display but I don't understand why.
On the Xperia Z just the ":" sign is displayed in landscape mode. So I think the text is wrapped but I don't know why.
It would make sense to me if the text size I set to it is higher than the screen height (in landscape mode this is actually screen width -> 1080) but this isn't the case.
When I try to set a longer text -> "asdfasd asdf" it is correctly displayed.
Can someone point me to the problem?
Cheers,
Stefan
UPDATE:
I figured out that my iWidth variable which holds the width of my TextView (_tvContent.getWidth()) has the value 1770.
How can that be since my Xperia Z has just 1920x1080???
So I thought that it may be a failure in TextView.getWidth() and added the following code:
Display display3 = getWindowManager().getDefaultDisplay();
Point size3 = new Point();
display3.getSize(size3);
int width = size3.x;
Display display1 = getWindowManager().getDefaultDisplay();
int width1 = display1.getWidth(); // deprecated
int height1 = display1.getHeight(); // deprecated
Display display = getWindowManager().getDefaultDisplay();
Integer iWidth = display.getWidth(); // deprecated
int height = display.getHeight(); // deprecated
Results:
Point(1080, 1776)
Display id 0: DisplayInfo{"Integrierter Bildschirm", app 1080 x 1776, real 1080 x 1920, largest app 1794 x 1701, smallest app 1080 x 1005, 60.0 fps, rotation 0, density 480, 442.451 x 443.345 dpi, layerStack 0, type BUILT_IN, address null, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=3.0, width=1080, height=1776, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}, isValid=true
Is this a Bug on site of Sony?
After I implemented my own TextView with its own OnDraw I've seen that there is an error in LogCat: ERROR/OpenGLRenderer(2503): Font size to large to fit in cache.
After a short research I figgured out that this is really a Bug in Android.
Addding this line to my custom TextView did the trick for me:
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Related
I have two bitmaps that I draw onto the center of a canvas:
One is only a background, it's a spirit level in top view which doesnt move. The second one is a bitmap looking like a "air bubble". When the user tilts the phone, the sensors read the tilt and the air bubble moves according to the sensor values along the x-axis. However, I need to make sure that the air bubble doesnt move too far, e.g out of the background-bitmap.
So I tried to which x coordinate the bubble can travel to,
before I have to set xPos = xPos -1 using trial and error
This works fine on my device.
To clarify: On my phone, the air bubble could move to the coordinate x = 50 from the middle of the screen. This would be the point, where the bitmap is at the very left of the background spirit level.
On a larger phone, the position x = 50 is too far left, and therefore looking like the air bubble travelled out of the water level.
Now I've tried following:
I calculated the area in % in which the air bubble can move. Let's say that
is 70% of the entire width of the bitmap. So I tried to calculate the two x boundary values:
leftBoundary = XmiddlePoint - (backgroundBitmap.getWidth() * 0.35);
rightBoundary = XmiddlePoint + (backgroundBitmap.getWidth() * 0.35);
...which doesnt work when testing with different screen sizes :(
Is it possible to compensate for different screen sizes and densities using absolute coordinates or do I have to rethink my idea?
If you need any information that I forgot about, please let me know. If this question has already been answered, I would appreciate a link :) Thanks in advance!
Edit:
I load my bitmaps like this:
private Bitmap backgroundBitmap;
private static final int BITMAP_WIDTH = 1898;
private static final int BITMAP_HEIGHT = 438;
public class SimulationView extends View implements SensorEventListener{
public SimulationView(Context context){
Bitmap map = BitmapFactory.decodeResource(getResources, R.mipmap.backgroundImage);
backgroundBitmap = Bitmap.createScaledBitmap(map, BITMAP_WIDTH, BITMAP_HEIGHT, true;
}
and draw it like this:
protected void onDraw(Canvas canvas){
canvas.drawBitmap(backgroundBitmap, XmiddlePoint - BITMAP_WIDTH / 2, YmiddlePont - BITMAP_HEIGHT / 2, null);
}
backgroundBitmap.getWidth() and getHeight() prints out the correct sizes.
Calculating like mentioned above would return following boundaries:
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
//which prints out width = 2392
xMiddlePoint = width / 2;
// = 1196
leftBoundary = xMiddlePoint - (BITMAP.getWidth()* 0.35);
// = 531,7
However, when I use trial and error, the right x coordinate seems to be at around 700.
I've come across a great explanation on how to fix my issue here.
As user AgentKnopf explained, you have to scale coordinates or bitmaps like this:
X = (targetScreenWidth / defaultScreenWidth) * defaultXCoordinate
Y = (targetScreenHeight / defaultScreenHeight) * defaultYCoordinate
which, in my case, translates to:
int defaultScreenWidth = 1920;
int defaultXCoordinate = 333;
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
displayWidth = displayMetrics.widthPixels;
leftBoundary = (displayWidth / defaultScreenWidth) * defaultXCoordinates
In our application, we need to determine screen width at startup. We have tried to get this width using a few different methods (see list below), but Samsung devices, especially their Galaxy devices, are sometimes giving us incorrect values.
We have a Galaxy s6 with a resolution of 1440 x 2560 pixels. Most of the time the device will report a width of 1440, but occasionally it will give us a width of 1080.
We have tried getting the width the following ways:
1)
getResources().getDisplayMetrics().widthPixels;
2)
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
3)
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
But in all cases we see an incorrect width being returned. We see incorrect values reliably when our application is launched for the very first time. Any help would be hugely appreciated.
Have you tried this?
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = metrics.widthPixels;
UPDATE
And a little bit hardcore.
You may find more here.
This is our getDeviceWidth() method for ages and we never had any trouble with it, but i guess it's your second version?! Please verify and comment. (Ensure you call this after your views are created.)
public static int getDeviceWidth(Activity activity) {
Display display = activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}
Otherwise i would try to get the y-position (or width) of an dummy layout which has sets its width to match_parent.
And test your getWidth on start and after app is running (f.e. on button click). Does it return wrong width during run time too?
In my method, I haven't run into any issues before in terms of not locating the right location of something or the exact size of any Android screen.
My method finds the screen size in inches and the screen height and width in pixels and inches
In my app this method is how I check if my app is being used by a tablet:
private void tabletChanges() {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int dens = dm.densityDpi;
double wi = (double)width/dm.xdpi;
double hi = (double)height/dm.ydpi;
double x = Math.pow(wi,2);
double y = Math.pow(hi,2);
double screenInches = Math.sqrt(x+y);
if(screenInches >= 7){
//Do certain things
}
}
Super simple question: what is the relationship of font size to screen resolution on adroid? AVD? E.g. if resolution width is 100px and a TextView has 10 monospaced chars in it, if text size is 10px, can i guarantee that the Text will occupy the full screen width?
My specific problem is that I need to scale 10 characters of text, using textSize, to use the full screen width (using textSize alone). If screen resolution is 100 x 100 and I want 10 characters to fully occupy the screen horizontally, why can't I just use:
DisplayMetrics metrics = getResources().getDisplayMetrics();
float pixelFontSize = metrics.widthPixels / 10f;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, pixelFontSize);
? In my testing, I get text that is way to small (uses about 1/3 the resolution) on a 280 x 280 wtih 280 dpi AVD, yet on another AVD 360 x 330 hdpi, the code above produce text way too big to fit on one line. ...I mean, sure I could see needing to subtract a small amount from the pixcelFontSize to account for text layout, but my results are all over the place. I must be missing something. First I was messing with density and the scaled measurement dp and sp, but logic would say that given my problem, density has nothing to do with it at all, right?
EDIT, to further show the problem, here is my solution to scale the text to fit the display, using font size, for 7 or 8 AVD's all wear, square round and chin
switch (metrics.widthPixels) {
case 280: //280 dpi
resolutionMultiplier = .4f;
ideoResolutionMultiplier = 0f;
break;
case 360: //hdpi
resolutionMultiplier = .5f;
ideoResolutionMultiplier = .0f;
break;
case 320: //works for round hdpi, chin tvdpi, but the res 320 square 280 dpi too tall....
if(metrics.xdpi == 280) {
resolutionMultiplier = .45f;
ideoResolutionMultiplier = 0f;
}
else {
resolutionMultiplier = .47f;
ideoResolutionMultiplier = 0f;
}
break;
case 400: //280 dpi
resolutionMultiplier = .55f;
ideoResolutionMultiplier = 0f;
break;
case 480: //360 dpi
resolutionMultiplier = .71f;
ideoResolutionMultiplier = 0f;
break;
}
if (mWzTheme.mWordArrays != null
&& mWzTheme.mWordArrays.isIdeographic()) {
pixelFontSize = (metrics.widthPixels / new Integer(Constants.MAX_LINE_LENGTH_CHINESE_WATCH).floatValue())
+ (new Integer(Constants.MAX_LINE_LENGTH_WATCH).floatValue() * ideoResolutionMultiplier);
}
else {
pixelFontSize = (metrics.widthPixels / new Integer(Constants.MAX_LINE_LENGTH_WATCH).floatValue())
+ (new Integer(Constants.MAX_LINE_LENGTH_WATCH).floatValue() * resolutionMultiplier);
}
Try this library:
https://github.com/AndroidDeveloperLB/AutoFitTextView
This will fit the text to the screen exactly. (Not sure if there were any issues with Android Wear target.)
Here is a simple solution:
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text,0,text.length(),bounds);
int height = bounds.height();
int width = bounds.width();
...but still need a guessing algorithm to go from screen resolution to the font size required to fill the screen with x characters...
In My app I have to do some resolution specific work and I have to get the resolution and send it to server accordingly. Now My server have images which entertains the following resolutions...
320 * 480
480 * 800
800 * 1200
720 * 1280
1080 * 1920
1440 * 2560
I am getting resolutions in the following way
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
so As we know there is so may resolutions so there would be some devices whose resolutions slightly different from the set of resolutions I have mentioned above such as I have a device which has 800px * 1172px
waht I want
So tell me how can I compare the device resolution with the set of
resolution and send the resolution which maintain the resolution
categorized images.
also if the device has resolution which is not exist in my pre determined set of resolutions , then I want to send the resolution closer to it.
Please help me , I do not know how to do it.
800px * 1172px
you are aware that this is actually a 800x1200 display? The way you get the screen dimensions takes the device's on-screen navigation bar into account. See this and similar questions if you need to take the navigation bar into account.
I want to send the resolution closer to it.
Possible solution that uses arrays of your supported dimensions and finds the closest value to your passed width/height:
final int[] supportedHeight = {320, 480, 720, 800, 1080, 1440};
final int[] supportedWidth = {480, 800, 1200, 1280, 1920, 2560};
public static int getClosest(int n, int[] values){
int dst = Math.abs(values[0] - n);
int position = 0;
for(int i = 1; i < values.length; i++){
int newDst = Math.abs(values[i] - n);
if(newDst < dst){
position = i;
dst = newDst;
}
}
return values[position];
}
Log.d("h", getClosest(1337, supportedHeight)+""); //1440
Log.d("w", getClosest(1172, supportedWidth)+""); //1200
I'm trying to dynamically build a layout, so it scales and looks more or less identical on all screen sizes and resolutions. I do this by programmatically placing my views inside a RelativeLayout and scaling everything according to a certain factor.
I noticed something strange when moving an ImageView around though, the bigger the values on margins get, the smaller the ImageView gets. This gets really annoying when trying to get things at right place and size.
private void initializeObjects() {
Display display = getWindowManager().getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
float scale = screenSize.x / ( (screenSize.x < screenSize.y) ? 480 : 800 ); // Scale according to Galaxy S II resolution
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.main_layout);
mRobotView = new ImageView(getApplicationContext());
mRobotView.setImageResource(R.drawable.soomla_logo_new); // a 743 x 720 png
mRobotView.setScaleX(scale * 100 / 743); // Make sure the image is 100 "units" in size
mRobotView.setScaleY(scale * 100 / 720);
mRobotView.setPivotX(scale * 100 / 743); // reset the image origin according to scale
mRobotView.setPivotY(scale * 100 / 720);
RelativeLayout.LayoutParams robotParams = new RelativeLayout.LayoutParams(743, 720);
robotParams.leftMargin = 0xDEADBEEF; // The bigger these get the smaller the view gets
robotParams.topMargin = 0xDEADBEEF;
screenLayout.addView(mRobotView, robotParams);
}
Any idea what's causing this?
Use
android:layout_height="720px"
android:layout_height="743px"
in the main_layout.xml to have the image not shrinked