SpecialCyCi / AndroidResideMenu

The idea of ResideMenu is from Dribbble 1 and 2. It has come true and run in iOS devices. iOS ResideMenu This project is the RefsideMenu Android version. The visual effect is partly referred to iOS version of ResideMenu. And thanks to the authors for the above idea and contribution.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cutting Screen

ashishislive opened this issue · comments

Hello,
Residemenu measuring whole size of screen for rendering menu effect so it is not showing properly on those device have soft keys (home,back,recent) other then it is working as expected. I guess it is not excluding that extra space (soft key space)

check pull request.

You need to change in library source code

@Override
    protected boolean fitSystemWindows(Rect insets) {
        setMyPadding(insets);
        return true;
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            Rect rect = new Rect(
                    insets.getSystemWindowInsetLeft(),
                    insets.getSystemWindowInsetTop(),
                    insets.getSystemWindowInsetRight(),
                    insets.getSystemWindowInsetBottom()
            );
            setMyPadding(rect);
            return insets.consumeSystemWindowInsets();
        }
        return super.onApplyWindowInsets(insets);
    }

    private void setMyPadding(Rect rect) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (hasNavBar()) {
                WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
                switch (manager.getDefaultDisplay().getRotation()) {
                    case Surface.ROTATION_90:
                        rect.right += viewActivity.getPaddingRight() + getNavBarWidth();
                        break;
                    case Surface.ROTATION_180:
                        rect.top += viewActivity.getPaddingTop() + getNavBarHeight();
                        break;
                    case Surface.ROTATION_270:
                        rect.left += viewActivity.getPaddingLeft() + getNavBarWidth();
                        break;
                    default:
                        rect.bottom += viewActivity.getPaddingBottom() + getNavBarHeight();
                }
            }
        }
        setPadding(rect.left, rect.top, rect.right, rect.bottom);
    }

    private int getNavBarWidth() {
        return getNavBarDimen("navigation_bar_width");
    }

    private int getNavBarHeight() {
        return getNavBarDimen("navigation_bar_height");
    }

    private int getNavBarDimen(String resourceString) {
        Resources r = getResources();
        int id = r.getIdentifier(resourceString, "dimen", "android");
        if (id > 0) {
            return r.getDimensionPixelSize(id);
        } else {
            return 0;
        }
    }

    /**
     * check is system has navigation bar or not* http://stackoverflow.com/a/29120269/3758898
     *
     * @return true if navigation bar is present or false
     */
    boolean hasNavBar() {
        try {
            // check for emulator
            Class<?> serviceManager = Class.forName("android.os.ServiceManager");
            IBinder serviceBinder = (IBinder) serviceManager.getMethod("getService", String.class).invoke(serviceManager, "window");
            Class<?> stub = Class.forName("android.view.IWindowManager$Stub");
            Object windowManagerService = stub.getMethod("asInterface", IBinder.class).invoke(stub, serviceBinder);
            Method hasNavigationBar = windowManagerService.getClass().getMethod("hasNavigationBar");
            return (boolean) hasNavigationBar.invoke(windowManagerService);
        } catch (ClassNotFoundException
                | ClassCastException
                | NoSuchMethodException
                | SecurityException
                | IllegalAccessException
                | IllegalArgumentException
                | InvocationTargetException e) {

            boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
            boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);
            return !hasHomeKey && !hasBackKey;
        }

Still issue in larger screen. Please help!

Go to ResideMenu - > fitSystemWindows function
This lines is in comment,
just recomment it:

this.setPadding(viewActivity.getPaddingLeft() + insets.left, viewActivity.getPaddingTop() + insets.top,
viewActivity.getPaddingRight() + insets.right, viewActivity.getPaddingBottom() + insets.bottom);

I too was facing same issue with ResideMenu and tried different solutions.
Finally i have found a clean solution which works in devices with all types of navigations including gesture navigations.

However, the only limitation is that, some other activity should be shown before showing this home activity (in which ResideMenu is used) like some Splash screen

  1. When this splash screen is launched, find its total height dynamically and save in some shared pref.
private void setAppUsableHeight() {
        final View root = findViewById(android.R.id.content);
        if (root != null) {
            root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout()  {
                    root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    int height = root.getHeight();
                    GILog.d(TAG, "TDV height: " + height);
                    saveLastCalculatedValueForAppUsableHeight(height, SplashActivity.this);
                }
            });
        }
    }
  1. Change attachToActivity() method of ResideMenu as follows
public void attachToActivity(Activity activity, int customHeight) {
       // keep exiting implementation and add below lines to it
        if (customHeight > 0) {
            ViewGroup.LayoutParams params = viewActivity.getLayoutParams();
            if (params != null) {
                params.height = customHeight;
                viewActivity.setLayoutParams(params);
            }    
        }
    }
  1. Now, when Home screen (having reside menu) is launched, initialize ResideMenu as usual, adding these two extra lines
        resideMenu.setFitsSystemWindows(true);
        resideMenu.attachToActivity(this, getLastCalculatedValueForAppUsableHeight(this));
public static void saveLastCalculatedValueForAppUsableHeight(int height, Context context) {
        SharedPreferencesUtils.putSharedPreference(PREF_KEY_APP_USABLE_SCREEN_HEIGHT, String.valueOf(height), context);
    }

    public static int getLastCalculatedValueForAppUsableHeight(Context context) {
        String heightStr = SharedPreferencesUtils.getSharedPreference(PREF_KEY_APP_USABLE_SCREEN_HEIGHT, context);
        int height = 0;
        if (!TextUtils.isEmpty(heightStr)) {
            try {
                height = Integer.parseInt(heightStr);
            } catch (NumberFormatException e) {

            }
        }
        return height;
    }
  1. Also you should remove overriding implementation of public WindowInsets onApplyWindowInsets(WindowInsets insets) and protected boolean fitSystemWindows(Rect insets) methods in ResideMenu

Note: By doing this, the activity contents will not go behind the soft navigation bar. But the ResideMenu will still be behind the soft nav gar. But we can add an empty Menu item in the bottom to make sure all menu items are shown.
Also, as our app is restricted to be only in Portrait mode, orientation changes are not handled, but you can do it easily.