I have a BottomSheetBehavior in my main activity to constantly show a bottom drawer.
When I open and then close the keyboard (when pressing an EditText and then pressing Back), the method "OnSlide" gets triggered:
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset)
{
// my code
}
}
I have code in this function that runs when the user slides the drawer up and down with his finger. I don't want this code to be run when the keyboard comes up and back down. It doesn't make sense that it's being called. How can I prevent keyboard changes from running the code in this function ?
I tried:
Changing in my AndroidManifest android:windowSoftInputMode="adjustResize" to android:windowSoftInputMode="adjustNothing" which essentialy does what I want, but removes useful functionalities which I had added (enabling scroll while keyboard is up).
Listening to soft keyboard changes to only execute code when changes are not occuring which doesn't work since OnSlide is called after keyboard is fully hidden (see code below).
Keyboard change listener:
mContentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
Rect r = new Rect();
mContentView.getWindowVisibleDisplayFrame(r);
int screenHeight = mContentView.getRootView().getHeight();
// r.bottom is the position above soft keypad or device button.
// if keypad is shown, the r.bottom is smaller than that before.
int keypadHeight = screenHeight - r.bottom;
// 0.15 ratio is perhaps enough to determine keypad height.
mKeyboardIsOpen = keypadHeight > screenHeight * 0.15;
}
});
I have a activity that has the "adjustPan" option set and it pans my view up just fine when a EditText receives focus and the soft keyboard is shown, but my problem is that there are UI elements below my EditText that needs to be visible also when the keyboard is shown and it is not on smaller screens. Can I some how tell the view to always pan so that those UI elements are visible by linking them to the EditText or something, or do I have to take control of the panning manually and calculate height and all, or what is the good solution here?
What you can do is you can use ViewTreeObserver to pan your content l'il bit more.
I did this is my app.
int edtHeight = 0;
// llContent is the Viewgroup layout which is inside a ScrollView.
ViewTreeObserver viewTreeObserver1 = llContent.getViewTreeObserver();
viewTreeObserver1.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
// Here edtHeight will get the height of edittext as i wanted my view to scroll that much bit more
edtHeight = edtTemprature.getHeight();
ViewTreeObserver obs = llContent.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
});
//llMain is the parent View Group of my XML layout
llMain.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
Rect r = new Rect();
// r will be populated with the coordinates of your view
// that area still visible.
llMain.getWindowVisibleDisplayFrame(r);
int heightDiff = llMain.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100)
{ // if more than 100 pixels, its probably a keyboard...
if(edtTemprature.hasFocus()){
llContent.scrollTo(0, (int) (edtHeight * 1.5));
}else{
llContent.scrollTo(0, 0);
}
}
else
{
llContent.scrollTo(0, 0);
}
}
});
Use stateHidden in Android manifestfile which class you need ..
android:windowSoftInputMode="stateHidden"
or else,
In Activity,
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
what i'm trying to do sounds really simple. Resize my GridView when SoftKeyboard is open. Put it back on place(resize height) where it belongs if SoftKeyboard dissapears.
For this i did following:
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
if(gv != null && searchbar != null) {
root.getWindowVisibleDisplayFrame(r);
if(screenHeight > r.bottom) {
RelativeLayout.LayoutParams myLayoutParams = (android.widget.RelativeLayout.LayoutParams) gv.getLayoutParams();
myLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
gv.setLayoutParams(myLayoutParams);
int gvHeight = screenHeight - r.bottom - searchbar.getLayoutParams().height;
gv.getLayoutParams().height = gvHeight;
}else {
RelativeLayout.LayoutParams myLayoutParams = (android.widget.RelativeLayout.LayoutParams) gv.getLayoutParams();
myLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
gv.setLayoutParams(myLayoutParams);
}
}
}
});
Where gv is my GridView. If i start my app, and click in my searchbar, the softkeyboard appears and this method is firing all the time.(Even if the layout isn't changing or even that i don't click anything). Therefore it blocks my UI. Did i do something wrong?
Also, does someone have a better idea implementing this function.(Resizing my Grid when Softkeyboard appears and vice versa).
Any help is appreciated.
Notice
Working with onFocusChange sounds not good to me. Because on my device. I can Close the SoftKeyboard with a backPress without loosing Focus
Have you tried using View.OnLayoutChangeListener available for API 11+ instead?
Otherwise you have to remove the listener when it fires after checking for a large enough height difference (see this). Don't forget to add the listener back in any click listener that fires up the keyboard.
#Override
public void onGlobalLayout() {
int heightDiff = root.getRootView().getHeight() - root.getHeight();
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
... rest of your code
}
}
I have a CordovaWebView that presents some html forms. When i focus on an input field, the Android's soft keyboard pops up and, for certain fields, according to their position, it gets on top of it. Basically, it is not resizing the layout of CordovaWebView.
Whatever i do, i can't change this, and it is said that it is related to the fact that the CordovaWebView is in fullscreen mode.
How can i accomplish to resolve this?
PS: is it, or not, a bug?
Thank you all!
In fact, it is a well know bug, as #user2493245 said. But I found a workaround, at least regarding my specific case.
on WebView, just check for the coordinates for the View's visible area.
final View activityRootView = this.root;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if(heightDiff != lastValue) {
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
appView.sendJavascript("onKeyBoardShow(" + r.bottom + ");");
} else {
appView.sendJavascript("onKeyBoardHide();");
}
lastValue = heightDiff;
}
}
});
As you can see, I send that information to the WebView. On HTML, I have this two methods to handle the issue:
function onKeyBoardShow(bottom) {
var diff = ($('input[type=text]:focus').offset().top - bottom) + 50;
if(diff > 0) {
$('body').css("top", (diff * -1) + "px");
}
};
function onKeyBoardHide() {
$('body').css("top", "0px");
};
Basically, onKeyBoardShow, it gets the input field focused and calculates the amount of pixels that will be necessary to move the body, allowing the user to see the input field. onKeyBoardHide, simply puts the body to its original position.
PS: This only functions when the viewport targets devicedpi, as we need to modify the way we get the dif regarding the dpi of the device.
PS2: First amount of code is not mine, I only edited to fill my needs. I saw that on a SO question, but unfortunatelly now i can't find it. If i find it, i'll post the link here.
I have the same problem and i found out it is a well known bug.
A workaround could be that u write a plugin that disables the fullscreen just before the softkeyboard pops up and reenables it afterwards.
Remove android:theme="#android:style/Theme.NoTitleBar.Fullscreen" from manifest, and add these 2 lines of code:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
Make sure your onCreate method looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.yourLayout);
// Your code ...
}
And everything will work :D.
Is there a way to know the size of the keyboard that is shown in the screen?
I am using Cocos2dx for programming, but I want to know the height of the keyboard shown in screen in the part of Android or the part of Cocos, it does not matter.
I know that Keyboard has a getHeight() method but I don't want to create new keyboards, i want to use the default one.
We did it with this
myLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
parent.getWindowVisibleDisplayFrame(r);
int screenHeight = parent.getRootView().getHeight();
int heightDifference = screenHeight - (r.bottom - r.top);
Log.d("Keyboard Size", "Size: " + heightDifference);
}
});
We only resize views with the keyboard, so we could use this.
Rect r = new Rect();
View rootview = this.getWindow().getDecorView(); // this = activity
rootview.getWindowVisibleDisplayFrame(r);
Result of this is the amount of space your application uses on screen (works even when activity is not resized). Obviously remaining screen space will be used by the keyboard ( if its visible)
Found id up here: https://github.com/freshplanet/ANE-KeyboardSize/blob/master/android/src/com/freshplanet/ane/KeyboardSize/getKeyboardY.java
if your activity is not fullscreen, using code below:
content.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
if (keyBoardHeight <= 100) {
Rect r = new Rect();
content.getWindowVisibleDisplayFrame(r);
int screenHeight = content.getRootView()
.getHeight();
int heightDifference = screenHeight
- (r.bottom - r.top);
int resourceId = getResources()
.getIdentifier("status_bar_height",
"dimen", "android");
if (resourceId > 0) {
heightDifference -= getResources()
.getDimensionPixelSize(resourceId);
}
if (heightDifference > 100) {
keyBoardHeight = heightDifference;
}
Log.d("Keyboard Size", "Size: " + heightDifference);
}
// boolean visible = heightDiff > screenHeight / 3;
}
});
If you want to calculate the Virtual Keyboard height while your activity does not change in size (adjustPan) then you can use this sample:
https://github.com/siebeprojects/samples-keyboardheight
It uses a hidden window in order to calculate the height difference between the window and the root view of the activity.
You can't tell. No, really: you simply can't tell.
The keyboard does not need to be any particular shape. It does not have to be placed at the bottom of the screen (many of the most popular options are not), it does not have to keep its current size when you change text fields (almost none do depending on the flags). It does not even have to be rectangular. It may also just take over the entire screen.
I know this is an old post, but I noticed that the chosen solution for me did not work on all devices. There seemed to be a discrepancy and so I implemented this and it seems to be a catch all:
final int[] discrepancy = new int[1];
discrepancy[0] = 0;
// this gets the height of the keyboard
content.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
View rootview = activity.getWindow().getDecorView(); // this = activity
rootview.getWindowVisibleDisplayFrame(r);
int screen_height = rootview.getRootView().getHeight();
int keyboard_height = screen_height - (r.bottom + r.top) - discrepancy[0];
if (discrepancy[0] == 0) {
discrepancy[0] = keyboard_height;
if (keyboard_height == 0) discrepancy[0] = 1;
}
int margin_bottom = keyboard_height + Helper.getDp(10, activity);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) carousel_container.getLayoutParams();
params.setMargins(0, 0, 0, margin_bottom);
//boolean visible = heightDiff > screenHeight / 3;
}
});
When the listener is first called it measures the screen without a keyboard and if there is a discrepancy I account for it the next time around. If there is no discrepancy I set the discrepancy to 1 just so it is no longer 0.
After 2020, if your min SDK large or equal then 21, you can check the visibility and height of IME by below functions:
fun isKeyboardVisible(attachedView: View): Boolean {
val insets = ViewCompat.getRootWindowInsets(attachedView)
return insets?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
}
fun getKeyboardHeight(attachedView: View): Int {
val insets = ViewCompat.getRootWindowInsets(attachedView)
return insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
}
Ref: Animating your keyboard (part 1). New WindowInsets APIs for checking theā¦ | by Chris Banes | Android Developers | Medium
in cocos2d-x we have got CCEditBox.
Inside Extensions->GUI->CCEditBox, you can find the class CCEditBox.
The beauty is that it hides the keyboard of tapping somewhere else on the scene. and automatically moves the keyboard up incase your edit box was placed too low on the scene.
If you are using cocos2d-x v2.1.3 then you can navigate to sample Project by going to
samples->cpp->TestCpp->Classes->ExtensionTest->EditBoxTest.
I'm just going to use it instead of CCTextField from now on. just came across it yesterday :)
After hours of searching I found a solution if you want to set windowSoftInput="adjustPan"
Here is the code snippet:
final View root = findViewById(android.R.id.content);
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
Rect r = new Rect();
{
root.getWindowVisibleDisplayFrame(r);
}
#Override
public void onGlobalLayout() {
Rect r2 = new Rect();
root.getWindowVisibleDisplayFrame(r2);
int keyboardHeight = r.height() - r2.height();
if (keyboardHeight > 100) {
root.scrollTo(0, keyboardHeight);
}
else {
root.scrollTo(0, 0);
}
}
});
In this code, after I found the keyboard height I scroll the view up to not covered by the keyboard which is the main reason for finding the keyboard height.
According to the docs :
void getWindowVisibleDisplayFrame(Rect outRect) : Retrieve the overall visible display size in which the window this view is attached to has been positioned in.
The ROOT_VIEW of an android display screen can be visualized as being a single screen view with VISIBLE DISPLAY FRAME which displays your activity's view.
This VISIBLE DISPLAY FRAME is adjusted when SOFT KEYBOARD is displayed or hidden from the screen.
NOTE : Please look at the two images by clicking on the links given below for better understanding
So the ROOT VIEW of a display screen can be visualized as :
RootView of display screen
The adjustment of VISIBLE DISPLAY FRAME with the opening and closing of SOFT KEYBOARD can be visualized as :
VISIBLE_DISPLAY_SCREEN adjustment
This adjustment of the VISUAL DISPLAY FRAME can be very well used to find out the height of the keyboard as :
(when the soft keyboard is open)
SOFT_KEYBOARD_HEIGHT = ROOT_VIEW_HEIGHT - (VISUAL_DISPLAY_FRAME_HEIGHT + EXTRA_SCREEN_HEIGHT)
The code to achieve the above is :
int mExtraScreenHeight=-1, mKeyboardHeight=-1;
boolean mKeyboardOpen;
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int rootViewHeight, visibleDisplayFrameHeight, fakeHeight;
/* (rootViewHeight - visibleDisplayFrameHeight) is not the real height of the keyboard
it is the fake height as it also consist of extra screen height
so FAKE_HEIGHT = KEYBOARD_HEIGHT + EXTRA_SCREEN_HEIGHT
To get keyboard height extra screen height must be removed from fake height
*/
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
rootViewHeight = rootView.getRootView().getHeight();
visibleDisplayFrameHeight = rect.height();
fakeHeight = rootViewHeight-visibleDisplayFrameHeight;
if (mExtraScreenHeight == -1){
mExtraScreenHeight=fakeHeight;
}
/* Suppose the soft keyboard is open then the VISIBLE_DISPLAY_FRAME is in reduced size
due to the space taken up by extra screen and the keyboard but when the soft keyboard closes
then KEYBOARD_HEIGHT=0 and thus FAKE_HEIGHT = EXTRA_SCREEN_HEIGHT
*/
else if (fakeHeight <= mExtraScreenHeight){
mExtraScreenHeight=fakeHeight;
mKeypadOpen=false;
}
else if (fakeHeight > mExtraScreenHeight){
mKeypadHeight=fakeHeight-mExtraScreenHeight;
mKeypadOpen=true;
}
}
});
NOTE : The onGlobalLayout() function will be called only when the global layout changes like when the soft keyboard opens. So the soft keyboard must be open at least once to get the soft keyboard height.
It worked for me ;)
Sorry for not being able to comment, two or three of the answers helped me solve my issue and they were related to using the AddOnGlobalLayoutListener and then determining the remaining height before and after a keyboard showed up.
The solution I used was based off of Rudy_TM's answer.
HOWEVER, one thing that I had to find was that in order for that method to work, you must have the following line somewhere
Window.SetSoftInputMode(SoftInput.AdjustResize);
Before I had SoftInput.AdjustNothing (or something like that) and it would not work. Now it works perfect. Thanks for the answers!
Complete answer & worked perfectly for me:
Rect r = new Rect();
View rootview = this.getWindow().getDecorView(); // this = activity
rootview.getWindowVisibleDisplayFrame(r);
int keyboardHeight = rootview.getHeight() - r.bottom;