Skip to content

Instantly share code, notes, and snippets.

@grennis
Created April 27, 2017 14:36
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save grennis/2e3cd5f7a9238c59861015ce0a7c5584 to your computer and use it in GitHub Desktop.
Save grennis/2e3cd5f7a9238c59861015ce0a7c5584 to your computer and use it in GitHub Desktop.
public class SoftInputAssist {
private View rootView;
private ViewGroup contentContainer;
private ViewTreeObserver viewTreeObserver;
private ViewTreeObserver.OnGlobalLayoutListener listener = () -> possiblyResizeChildOfContent();
private Rect contentAreaOfWindowBounds = new Rect();
private FrameLayout.LayoutParams rootViewLayout;
private int usableHeightPrevious = 0;
public SoftInputAssist(Activity activity) {
contentContainer = (ViewGroup) activity.findViewById(android.R.id.content);
rootView = contentContainer.getChildAt(0);
rootViewLayout = (FrameLayout.LayoutParams) rootView.getLayoutParams();
}
public void onPause() {
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeOnGlobalLayoutListener(listener);
}
}
public void onResume() {
if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
viewTreeObserver = rootView.getViewTreeObserver();
}
viewTreeObserver.addOnGlobalLayoutListener(listener);
}
public void onDestroy() {
rootView = null;
contentContainer = null;
viewTreeObserver = null;
}
private void possiblyResizeChildOfContent() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow;
rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
rootView.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
}
@phucnv-2558
Copy link

I have a view that is constanted to the container but when resizing the root view, that view disappears

@sab60-bit
Copy link

it does not work to me i has error at line : private ViewTreeObserver.OnGlobalLayoutListener listener = () -> possiblyResizeChildOfContent();
please how can i resolve it . thanks

@hasanaga
Copy link

Thanks. It works perfectly.

@hasanaga
Copy link

hasanaga commented Nov 19, 2021

it does not work to me i has error at line : private ViewTreeObserver.OnGlobalLayoutListener listener = () -> possiblyResizeChildOfContent(); please how can i resolve it . thanks

Use like this

    private ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            possiblyResizeChildOfContent();
        }
    };

@mirkamalg
Copy link

This gist is over 3 years old and hacking around limitations in the framework at the time. I am not surprised to hear it doesn’t work properly anymore. I believe similar functionality is now available in androidx libs. I should probably just delete this.

Actually it works, it just flickers when keyboard size or visibility is changes.

@PriyaSindkar
Copy link

I am able to implement this and the status bar is not flickering anymore, need to let it run in Handler when calling "possiblyResizeChildOfContent". Not sure whether this works on anyone else, but give it a try. The code below is in Kotlin.

class SoftInputAssist(activity: Activity) {
    private var contentContainer: ViewGroup?
    private var rootView: View?
    private val rootViewLayout: FrameLayout.LayoutParams?

    private val contentAreaOfWindowBounds: Rect = Rect()
    private var viewTreeObserver: ViewTreeObserver? = null
    private var usableHeightPrevious = 0

    private val listener = OnGlobalLayoutListener {
        possiblyResizeChildOfContent()
    }

    init {
        contentContainer = activity.contentRootView as? ViewGroup
        rootView = contentContainer?.getChildAt(0)
        rootViewLayout = rootView?.layoutParams as? FrameLayout.LayoutParams
    }

    fun onPause() {
        if (viewTreeObserver != null && viewTreeObserver!!.isAlive) {
            viewTreeObserver?.removeOnGlobalLayoutListener(listener)
        }
    }

    fun onResume() {
        viewTreeObserver = rootView?.viewTreeObserver

        if (viewTreeObserver != null) {
            viewTreeObserver?.addOnGlobalLayoutListener(listener)
        }
    }

    fun onDestroy() {
        contentContainer = null
        rootView = null
        viewTreeObserver = null
    }

    private fun possiblyResizeChildOfContent() {
        runOnMainThread {
            contentContainer?.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
            val usableHeightNow: Int = contentAreaOfWindowBounds.bottom

            if (usableHeightNow != usableHeightPrevious) {
                rootViewLayout?.height = usableHeightNow

                rootView?.layout(
                    contentAreaOfWindowBounds.left - (contentContainer?.x?.toInt() ?: 0),
                    contentAreaOfWindowBounds.top - (contentContainer?.y?.toInt() ?: 0),
                    contentAreaOfWindowBounds.right - (contentContainer?.x?.toInt() ?: 0),
                    contentAreaOfWindowBounds.bottom - (contentContainer?.y?.toInt() ?: 0)
                )

                rootView?.requestLayout()
                usableHeightPrevious = usableHeightNow
            }
        }
    }
}

val Activity.contentRootView: View?
    get() = window?.decorView?.findViewById(android.R.id.content) ?: findViewById(android.R.id.content)

private object ContextHandler {
    val handler = Handler(Looper.getMainLooper())
}

fun runOnMainThread(action: () -> Unit) {
    ContextHandler.handler.post {
        action()
    }
}

For me this solution worked perfectly with windowSoftInputMode= adjustPan and then adjusting my NestedScrollView's parent's top, start, end, and bottom constraints with the parent with 0dp height

@SANDY-9
Copy link

SANDY-9 commented Apr 1, 2023

thanks.

@Twodies
Copy link

Twodies commented May 3, 2023

Worked for me after I have replaced

int usableHeightNow = contentAreaOfWindowBounds.height();

with

int usableHeightNow = contentAreaOfWindowBounds.bottom;

otherwise I had a large gap at the bottom of the screen.

Thanks Bro it was a problem for me. But a little bit problem while launching the activity, splash like problem. If you found an answer please email me. twodiesdeveloper@gmail.com. I'll be waiting to your answer.

@benardelia
Copy link

Can this be used in fragment...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment