Soft input keyboard moves my static bottom view up Android Kotlin - android

I have a Fragment with a static top view,a static bottom view and a ViewPager2 in the middle of those 2 views.(Look for Picture1 in the link provided). I have a problem when the keyboard shows up my bottom static view moves up. I tried all of android soft input methods and some code linked with that, some other code in stackoverflow but it doesn't work.
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" //does not work
What i'm trying to do is hide that bottom static view like in Picture 2:
I archived what I was looking with this code:
binding.parentConstrint.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
binding.parentConstrint.getWindowVisibleDisplayFrame(r)
val screenHeight = binding.parentConstrint.rootView.height
val keypadHeight = screenHeight - r.bottom
if (keypadHeight > screenHeight * 0.15) {
if (!isKeyboardShowing) {
isKeyboardShowing = true
binding.bottomView.gone()
}
}else {
if (isKeyboardShowing) {
isKeyboardShowing = false
binding.bottomView.visible()
}
}
}
But this kinda refreshes my whole View when that bottom view appears and disappears and i can see that refresh happening with my eyes. Any ideas how to stop that refresh or to do this in another way?

Remove the layout listener and use:
android:windowSoftInputMode="stateHidden|adjustNothing"
Otherwise try to remove this last line too from manifest

Related

How to hide footer component that appear on keyboard's top when editText gets focused in fragment?

Fragment layout
Actually the footer is set inside an activity class and the edittext is placed inside a fragment.
manifest file
<activity
android:name="HomeController"
android:label="#string/app_name"
android:windowSoftInputMode="stateHidden|adjustPan"/>
Inside my fragment class I added
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
These are the code snippet that I used, but it won't work!
Note: in Fragment UI, the whole screen has a scroll view,
Don't know why it is happening like this?Actually I don't want my footer on the keyboard's top.
Any suggestions on how to solve this behavior? And its appriciatble for the replies :)
Add this to your activity.
I did not test, but this might work. it is a bad way though(
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
View rootView = getWindow().getDecorView().getRootView();
rootView.getWindowVisibleDisplayFrame(r);
int screenHeight = rootView.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;
Log.d(TAG, "keypadHeight = " + keypadHeight);
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
//set bottom navigation(footer) bar to View.GONE
}
else {
// keyboard is closed
//set bottom navigation bar(footer) to View.VISIBLE
}
}
});
Use android:windowSoftInputMode="hidden" in your parent layout in the xml file. also in case it has layoutAbove property then try to remove it.
Try to add the following in manifest file:
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
Also remove the following from fragment:
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

How to place a layout completely on top of keyboard in bottom sheet dialog fragment

I have a bottom sheet dialog fragment in an Activity. When the softkeyboard is shown I need to push the complete dialog fragment layout to the top of keyboard.
I have tried various ways like using GRAVITY.TOP , bottomMargin for the dialog increasing the height etc.
None of the above ways are working. I want to make the top of bottom sheet dialog fragment align with the parent i.e top of phone.
Since I am using Framelayout to add Bottom Sheet Dialog fragment in activity I am unable to set alignParentTopAttribute . Please let me know if there are any ways of doing this or suggestions to achieve this.
Please find below code that I have tried till now:
view?.viewTreeObserver?.addOnGlobalLayoutListener {
var r = Rect()
view?.getWindowVisibleDisplayFrame(r)
var screenHeight = view?.rootView?.height
var initialHeight = rootLayout.height
var keyPadHeight = screenHeight?.minus(r.bottom)
var layoutParams: Frame.LayoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
if (keyPadHeight!! > screenHeight?.times(0.15)!!) {// 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
}
var window: Window? = dialog?.window
var windowManagerLayoutParams: WindowManager.LayoutParams? = window?.attributes
//Tried this
windowManagerLayoutParams.gravity = GRAVITY.TOP
window.attributes = windowManagerLayoutParams
//Tried this
layoutParams.gravity = Gravity.TOP
rootLayout.layoutParams = layoutParams
} else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
}
}
}
I have also tried adjustResize and stateVisible in manifest. adjustResize will not push complete layout to the top of soft keyboard, there will be a scroll behind the soft keyboard, user will have to scroll to see the complete layout.
But I do not want to have the scroll, user should see the complete layout on top of the soft keyboard as soon as it is visible.

Why does the fragment get padding on top and bottom when it resizes when the keyboard is shown?

I have an activity that hosts a fragment, and several others.
This activity already has fitsSystemWindows=false so that it will extend it's boundaries towards the very bottom of the screen, I am hiding the Navigation Bar btw.
The problem is, it has a fragment that has a RichEditor view inside it which means users should be able to put multiple lines of text inside that fragment. SO I made that fragment fitsSystemWindows=true so that when users start clicking on the RichEditor and types, the adjustResize flag, which I have set in the styles, will fire up and allow the user to scroll the page.
It resizes and allows the user to scroll yes.
The only problem is, when the fragment resizes, it gets additional padding on the top and bottom and since I have a custom toolbar on the main activity, it is very awkwardly visibly being added on screen. The funny thing is, the top padding is exactly the same as the height of the device's status bar and the bottom padding is exactly the same as the height of the Navigation Bar.
I tried making the clipToPadding attribute in the fragment's layout into true and false but it does not stop the fragment from getting the additional paddings. I also searched around but I can't get anything useful to get around this as most of the questions I encounter are about how to ALLOW the resize to happen and not anything about how to remove or stop the padding.
Is there even any way to know when the fragment has been resized or the resize has been triggered? If ever I can use that listener to remove the additional paddings as needed.
Any thoughts on this?
EDIT
I already tried putting fitsystemwindows=true in the main activity, but it gets some padding on the bottom for the navigation bar. And I need the activity to fill the whole screen as the navigation bar is hidden
I have solved this by following Matej Snoha's comment. This method attaches a listener to the fragment and when it sees the heightDifference, which is the size of the keyboard as well, is more than the height of the navigation bar, it puts a padding to the bottom of the view thus allowing it to scroll while the keyboard is open.
public class FragmentResizeUtil {
public static void setListenerforResize(final View root, Fragment fragment) {
final int navigationbarHeight = getNavigationBarHeight(fragment);
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
Rect r = new Rect();
root.getWindowVisibleDisplayFrame(r);
int screenHeight = root.getRootView().getHeight();
int heightDifference = screenHeight - (r.bottom - r.top);
if (heightDifference > navigationbarHeight) {
root.setPadding(0, 0, 0, heightDifference);
} else {
root.setPadding(0, 0, 0, 0);
}
}
});
}
private static int getNavigationBarHeight(Fragment fragment) {
Resources resources = fragment.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return resources.getDimensionPixelSize(resourceId);
}
return 0;
}
}

Force EditText to lose focus when back pressed

I'm trying to force the EditText control to lose focus when the user presses the back button to hide the keyboard. There are many questions similar to this already, but after several hours, I haven't been able to make it work.
First, just a little bit of context. I have a ListView with custom items. Each item has several TextViews and one EditText. I have an AfterTextChanged() method saving edited values. I have a style set up to highlight the field if it has focus. Unfortunately, it is now much more obvious that the EditText doesn't actually lose focus when you hide the (soft) keyboard, and I think it's confusing. I would like the EditText to not be focused if there's no keyboard.
The solution that seemed the most reasonable is to override OnBackPressed() in the activity as described here. Unfortunately, it doesn't appear that my method is being called. I.e. the field is still focused, and a breakpoint in the function doesn't fire.
Similarly, an OnKeyUp() listener on the activity doesn't fire, and Xamarin doesn't appear to support the OnKeyUp handler for the EditText control.
I'm not trying to suppress the keyboard on creation, or anything, so using any of the invisible control tricks don't help either.
It's obvious that a lot of people have this problem. I'm sure one of you has solved it! Can you please share your solution?
Thank you so much!
-Karen
P.S. I do not need to know how to hide the keyboard. I need to take an action when the user hides the keyboard with the back button. Thanks :)
In my experience onBackPressed() (at least the default #Override one in an activity) will not normally fire when pushing the back button to close the keyboard. As far as I know it will only fire when a Back press would initiate a finish() on the current activity.
Below is a kind of "hacky" way to know when the keyboard is shown/hidden by monitoring the change in the view size. You must also set the Activity to android:windowSoftInputMode="adjustResize" in the AndroidManifest.xml.
final View activityRootView = findViewById("Your main View");
activityRootView.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.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
//Keyboard is shown
}
if(heightDiff <= 100) {
//Keybaord not shown
}
}
});
With sincere thanks to #Shadesblade (and Xamarin's sample code), my EditTexts now unfocus! Here's the Xamarin-ized solution:
To your activity, add this class:
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
Action on_global_layout;
public GlobalLayoutListener (Action onGlobalLayout)
{
on_global_layout = onGlobalLayout;
}
public void OnGlobalLayout ()
{
on_global_layout ();
}
}
Add a class variable to hold the View so that the delegate can access it:
View _rootview;
In your OnCreate() add:
GlobalLayoutListener gll = new GlobalLayoutListener(
delegate {
Android.Graphics.Rect r = new Android.Graphics.Rect();
_rootView.GetWindowVisibleDisplayFrame(r);
int heightDiff = _rootView.RootView.Height - (r.Bottom - r.Top);
if (heightDiff < 100)
{
if (Window.CurrentFocus != null)
Window.CurrentFocus.ClearFocus();
}
});
_rootView = FindViewById<View>(Resource.Id.relativeLayoutOrder);
_rootView.ViewTreeObserver.AddOnGlobalLayoutListener(gll);
I expect to need to dork around with the heightDiff level and/or have to add some rotation checking, but I haven't done any rotation support at this point, so I can punt that until later.
Thank you again! *happy dance*
adding on to Shadesblade's answer, if you are using a scrollview, his answer needs a change to work, because not all of the scrollview is showing on screen.
so instead of doing
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
you should do
int heightDiff = Utils.getScreenHeight(SearchActivity.this) - (r.bottom - r.top);
where Utils.getScreenHeight is this:
public static int getScreenHeight(Context c) {
if (screenHeight == 0) {
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenHeight = size.y;
screenWidth = size.x;
}
return screenHeight;
}

Getting the dimensions of the soft keyboard

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;

Categories

Resources