1

I am drawing image on canvas which in turn in fullscreen, it is drawn behind navigation and status bars.

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.background_try9);
    bgTrans = Bitmap.createScaledBitmap(b, canvas.getWidth(), canvas.getHeight(), false);

    canvas.drawBitmap(bgTrans, 0, 0, paint);
}

Now I want to move this outside onDraw method.

I know I can use DisplayMetrics like this

DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;

But I have read that sometimes it can report wrong/null value. Also after checking it out, it seem heightPixels does not count navigation bar height. Is there way to get canvas sizes before entering onDraw?

  • Why not use "windowManager.getDefaultDisplay().getRealSize()" method? It counts even the navogation/status bar. It's available from SDK 17 (or from SDK 14 using Reflection) – emandt Aug 02 '18 at 12:49
  • @emandt this is a custom view, and I cannot access windowManager outside activity/fragment – Akaki Gabisonia Aug 02 '18 at 12:56
  • You just need a Context as you already done in your Code. A Context could be retrieved from a Service or the Base context of the Application. However you can retrieve screen size at the beginning (if you don't want to support split-screen) – emandt Aug 02 '18 at 16:20
  • @emandt I have a Context, but I cannot simply cast it to Activity. I'm just wanted some clean solution – Akaki Gabisonia Aug 02 '18 at 23:33

1 Answers1

0

Get the height of the navigation bar and subrtact it from screen's height!

Try below code:

Resources resources = context.getResources();

int navBarId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
int statusBarId = resources.getIdentifier("status_bar_height", "dimen", "android");

int navBarHeight = 0;
int statusBarHeight = 0;

if (resourceId > 0) {
    navBarHeight = resources.getDimensionPixelSize(navBarId);
    statusBarHeight = resources.getDimensionPixelSize(statusBarId);
}

DisplayMetrics displayMetrics = resources.getDisplayMetrics();
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;

height = height + navBarHeight + statusBarHeight;

This code is not tested but i think it works! I remember faced this problem and i used this approach.

An alternative to get the screen dimensions is:

// Inside an Activity or if you have a reference of activity
Display display = getWindowManager().getDefaultDisplay(); 
Point size = new Point(); 
display.getSize(size); 
int width = size.x; 
int height = size.y;
Roberto Manfreda
  • 2,345
  • 3
  • 25
  • 39
  • actually I needed fullscreen, so `height = height + dimBar` works for me, but why is that? should not `DisplayMetrics` be returning already real height? like you expected in your code – Akaki Gabisonia Aug 02 '18 at 12:28
  • As you can see in [docs](https://developer.android.com/reference/android/util/DisplayMetrics) `displayMetrics.heightPixels` is the absolute height of the available display size in pixels. So get height and subtract navBar and statusBar. – Roberto Manfreda Aug 02 '18 at 12:31
  • Yeah I looked into it, but you don't understand. `displayMetrics.heightPixels` is returning value without `navBarHeight`. So to achieve what I need I'm doing `height = height + navBarHeight`. I'm really curious why is that – Akaki Gabisonia Aug 02 '18 at 12:37
  • OOps! I don't know why. Maybe he takes dimen from the layout. Anyway you can try this code to get the real width and height: `Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int width = size.x; int height = size.y;` – Roberto Manfreda Aug 02 '18 at 12:44
  • `getWindowManager()` will require me to be inside activity, and since I'm just extending `View`, I want to avoid that. I think for now I'm gonna stick with `height+navBarHeight` which is kind of weird but don't see other solution for now – Akaki Gabisonia Aug 02 '18 at 12:48
  • Yes you need a context to call getWindowManager() – Roberto Manfreda Aug 02 '18 at 12:51
  • Are you sure? context.getWindowManager() does not work. This is simple extended `View`. Edit: just double checked, it is an activity method – Akaki Gabisonia Aug 02 '18 at 12:53
  • Look at this https://stackoverflow.com/questions/7378644/how-to-call-getwindow-outside-an-activity-in-android#7378652 – Roberto Manfreda Aug 02 '18 at 12:55
  • I feel little dirty using this kind of hack. I mean passing `Activity` around. – Akaki Gabisonia Aug 02 '18 at 12:58
  • Use the singleton pattern to start the app. So you will have the currentActivity reference always. I have a github [project](https://github.com/RobertoManfreda/android-base-template) that illustates it. Take a look! You'll can get an activity reference from everywhere using Application.getInstance().getCurrentActivity(); – Roberto Manfreda Aug 02 '18 at 13:00
  • That sound better way, since the previous one requires to "start up" a view after passing activity. perhaps this will work, I just wonder about concurrency, since I had similar problem before when using such approach. I will try it now. Thanks a lot. – Akaki Gabisonia Aug 02 '18 at 13:07
  • This is near an Hack and could not work in future as when we use Hidden API via Reflection. It could work on most of devices but maybe not works in someone... – emandt Aug 02 '18 at 16:23
  • What are you speaking about? :) – Roberto Manfreda Aug 02 '18 at 16:28
  • @emandt you mean "navigation_bar_height" can be null on some devices right? That is what I was thinking – Akaki Gabisonia Aug 02 '18 at 23:30
  • Of course. Accessing a String parameter could returns a NULL value on some Android versions. It's unpredictable as when a developer uses hidden API via Reflection. It could be works for years but starting from one time it could be stop work. Using Reflection is needed sometimes and cannot be avoided, but in this specific case there could be other solutions. – emandt Aug 03 '18 at 01:41