I want to draw a SeekBar
on canvas programmatically. I wrote code to set the LayoutParams of the SeekBar
based on device density. I am using switch case with device density like
final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
if(metrics.densityDpi <= DisplayMetrics.DENSITY_LOW){
zoomBarParams = new LinearLayout.LayoutParams(18,
LayoutParams.FILL_PARENT);
} else if (metrics.densityDpi <= DisplayMetrics.DENSITY_MEDIUM){
zoomBarParams = new LinearLayout.LayoutParams(24,
LayoutParams.FILL_PARENT);
}else if (metrics.densityDpi <= DisplayMetrics.DENSITY_HIGH){
zoomBarParams = new LinearLayout.LayoutParams(24,
LayoutParams.FILL_PARENT);
}else if (metrics.densityDpi <= DisplayMetrics.DENSITY_XHIGH){
zoomBarParams = new LinearLayout.LayoutParams(31,
LayoutParams.FILL_PARENT);
}else if (metrics.densityDpi <= DisplayMetrics.DENSITY_XXHIGH){
zoomBarParams = new LinearLayout.LayoutParams(60,
LayoutParams.FILL_PARENT);
}else if (metrics.densityDpi <= DisplayMetrics.DENSITY_XXXHIGH){
zoomBarParams = new LinearLayout.LayoutParams(60,
LayoutParams.FILL_PARENT);
} else {
zoomBarParams = new LinearLayout.LayoutParams(60,
LayoutParams.FILL_PARENT);
}
But this isn't working in high end devices like Samsung Note 5, Galaxy S6 Edge etc..I believe that these devices comes in the density range XXXHIGH, then why is this not working?? Is there any relation between device density and screen size while drawing on canvas? Any help will be greatly appreciated.
Why don't you try to get rid of all the if else
cases and make something generic? Since you need to put different pixel values depending on the screen size, you can use dp
instead.
You can get px
from dp
depending on the screen density of the device and use that in LayoutParams
.
public static float convertDpToPixel(float dp, Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); // You can cache "((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)" to avoid re-calculation.
return px;
}
So you will create the param
like this:
zoomBarParams = new LinearLayout.LayoutParams(convertDpToPixel(DP_VALUE, context),
LayoutParams.FILL_PARENT);
where DP_VALUE
will remain constant across all devices.
I hope this might solve your problem.
Problem is there is not any generic code for this problem.
If you want original density then you can use metrics.xdpi
and metrics.ydpi
for horizontal and vertical density respectively.
or go follow this code:
public static String getDensity(Resources resources) {
switch (resources.getDisplayMetrics().densityDpi) {
case DisplayMetrics.DENSITY_LOW:
return "ldpi";
case DisplayMetrics.DENSITY_MEDIUM:
return "mdpi";
case DisplayMetrics.DENSITY_HIGH:
return "hdpi";
case DisplayMetrics.DENSITY_XHIGH:
return "xhdpi";
case DisplayMetrics.DENSITY_XXHIGH:
return "xxhdpi";
case DisplayMetrics.DENSITY_XXXHIGH:
return "xxxhdpi";
case DisplayMetrics.DENSITY_TV:
return "tvdpi";
default:
return "unknown";
}
A very depth explanation of this topic is given by this guy here :
https://stackoverflow.com/a/33789580/5476209
also check DisplayMetrics section in Android developers documentation
If you are working on canvas, my recommendation to play with pixels only. In stead of dpi you can use percentage width and height according to your requirement. That will best suit and work on every device. For example if you need a seekbar of 600 x 128px
for the screen size 800 x 1280 px
. Then it is like 75% of width and 10% of height. Now apply this percentage by code-
DisplayMetrics dm = getResources().getDisplayMetrics();
int seekBarWidth= dm.widthPixels * 75 / 100;
int seekBarHeight= dm.heightPixels * 10 / 100;
And this will work for all screen sizes perfectly. Let me know in case of further assistance :)
来源:https://stackoverflow.com/questions/37988804/drawing-on-canvas-issue-in-high-end-devices