5

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.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Jas
  • 3,207
  • 2
  • 15
  • 45
  • I think your problem is that `densityDpiValue` is not guaranteed to be exactly equal to one of the densities specified by `DisplayMetrics` constants. Let's say you will get density equal to `321` - it will not trigger any of the cases. Consider check for the ranges. – Dmitry Zaytsev Jun 27 '16 at 11:24
  • As a side question - what problem are you trying to solve with such `switch`? Why not use `dp` values instead? – Dmitry Zaytsev Jun 27 '16 at 11:25
  • @DmitryZaitsev Yes. I updated my code like checking for range. The problem got solved in Samsung Note 5 and Galaxy S6 Edge. But the problem still exists in S6 Edge +. Please see my updated code in question. – Jas Jun 27 '16 at 11:29
  • Now it checks for intermediate densities like 420, 560 etc. – Jas Jun 27 '16 at 11:31
  • which branch is being triggered for S6 Edge? – Dmitry Zaytsev Jun 27 '16 at 11:35
  • I want to draw the zoom bar based on device density. As density of device increases, I want the zoom bar to be bigger – Jas Jun 27 '16 at 11:35
  • `}else if (metrics.densityDpi <= DisplayMetrics.DENSITY_XXXHIGH){ zoomBarParams = new LinearLayout.LayoutParams(60, LayoutParams.FILL_PARENT);` This is triggered in S6 Edge – Jas Jun 27 '16 at 11:42
  • 1
    So, what is not working exactly? How did you expected it to work? – Dmitry Zaytsev Jun 27 '16 at 12:30

3 Answers3

2

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

Community
  • 1
  • 1
TapanHP
  • 5,969
  • 6
  • 37
  • 66
2

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.

Rohit Arya
  • 6,751
  • 1
  • 26
  • 40
1

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 :)

Neo
  • 3,546
  • 1
  • 24
  • 31