Android如何在软键盘可见时以全屏模式调整布局
我已经研究了很多调整软键盘是活跃的布局,我已经成功实现它,但是当我在清单文件中使用android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
。
为此,我使用了android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"
不同的选项,但没有运气。
之后,我以编程方式实现了FullScreen
并尝试使用FullScreen
各种布局,但都是徒劳的。
我提到这些链接,并在这里看到很多与这个问题有关的post:
http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html
http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/
这里是xml代码:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/masterContainerView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:background="#ffffff"> <ScrollView android:id="@+id/parentScrollView" android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/setup_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Setup - Step 1 of 3" android:textColor="@color/top_header_txt_color" android:textSize="20dp" android:padding="8dp" android:gravity="center_horizontal" /> <TextView android:id="@+id/txt_header" android:layout_width="fill_parent" android:layout_height="40dp" android:text="AutoReply:" android:textColor="@color/top_header_txt_color" android:textSize="14dp" android:textStyle="bold" android:padding="10dp" android:layout_below="@+id/setup_txt" /> <EditText android:id="@+id/edit_message" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Some text here." android:textSize="16dp" android:textColor="@color/setting_editmsg_color" android:padding="10dp" android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header" android:gravity="top" android:scrollbars="vertical" android:maxLength="132" /> <ImageView android:id="@+id/image_bottom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/edit_message" /> </LinearLayout> </ScrollView> <RelativeLayout android:id="@+id/scoringContainerView" android:layout_width="fill_parent" android:layout_height="50px" android:orientation="vertical" android:layout_alignParentBottom="true" android:background="#535254"> <Button android:id="@+id/btn_save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginTop="7dp" android:layout_marginRight="15dp" android:layout_below="@+id/edit_message" android:text = "Save" /> <Button android:id="@+id/btn_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:layout_marginRight="10dp" android:layout_below="@+id/edit_message" android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" /> </RelativeLayout> </RelativeLayout>
当软键盘进入画面时,我希望底部的2个button应该向上。
– > https://groups.google.com/group/android-developers/msg/5690ac3a9819a53b?pli=1
– >全屏模式不会resize
基于yghm的解决方法,我编写了一个便利的类,使我可以用一行代码解决问题(将新类添加到我的源代码当然)。 单线是:
AndroidBug5497Workaround.assistActivity(this);
而实现类是:
public class AndroidBug5497Workaround { // For more information, see https://issuetracker.google.com/issues/36911528 // To use this class, simply invoke assistActivity() on an Activity that already has its content view set. public static void assistActivity (Activity activity) { new AndroidBug5497Workaround(activity); } private View mChildOfContent; private int usableHeightPrevious; private FrameLayout.LayoutParams frameLayoutParams; private AndroidBug5497Workaround(Activity activity) { FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { possiblyResizeChildOfContent(); } }); frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard/4)) { // keyboard probably just became visible frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } else { // keyboard probably just became hidden frameLayoutParams.height = usableHeightSansKeyboard; } mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); return (r.bottom - r.top); } }
希望这有助于某人。
既然答案已经被选中,而且问题已知是一个错误,我想我会添加一个“可能的解决办法”。
显示软键盘时,可以切换全屏模式。 这允许“adjustPan”正确地工作。
换句话说,我仍然使用@android:style / Theme.Black.NoTitleBar.Fullscreen作为应用程序主题的一部分,并将stateVisible | adjustResize作为活动窗口软input模式的一部分,但为了让它们一起工作,我必须切换全屏模式在键盘出现之前。
使用下面的代码:
closures全屏模式
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
打开全屏模式
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
注意 – 灵感来自: 以全屏模式隐藏标题
我也必须面对这个问题,并有一个工作,我检查了macros达电之一,银河s1,s2,s3,笔记和HTC的感觉。
把一个全局布局监听器放在你的布局的根视图上
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){ public void onGlobalLayout() { checkHeightDifference(); } });
在那里我检查了高度差,如果屏幕的高度差大于屏幕高度的三分之一,那么我们可以假定键盘是打开的。 把它从这个答案 。
private void checkHeightDifference(){ // get screen frame rectangle Rect r = new Rect(); mRootView.getWindowVisibleDisplayFrame(r); // get screen height int screenHeight = mRootView.getRootView().getHeight(); // calculate the height difference int heightDifference = screenHeight - (r.bottom - r.top); // if height difference is different then the last height difference and // is bigger then a third of the screen we can assume the keyboard is open if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) { // keyboard visiblevisible // get root view layout params FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams(); // set the root view height to screen height minus the height difference lp.height = screenHeight - heightDifference; // call request layout so the changes will take affect .requestLayout(); // save the height difference so we will run this code only when a change occurs. mLastHeightDifferece = heightDifference; } else if (heightDifference != mLastHeightDifferece) { // keyboard hidden PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden"); // get root view layout params and reset all the changes we have made when the keyboard opened. FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams(); lp.height = screenHeight; // call request layout so the changes will take affect mRootView.requestLayout(); // save the height difference so we will run this code only when a change occurs. mLastHeightDifferece = heightDifference; } }
这可能不是防弹的,也许在一些设备上它不会工作,但是它为我工作,并希望它也会帮助你。
只有使用android:windowSoftInputMode="adjustResize|stateHidden
因为你使用AdjustPan然后它禁用resize的属性
请注意,当为活动设置WindowManager.LayoutParams.FLAG_FULLSCREEN
时, android:windowSoftInputMode="adjustResize"
不起作用。 你有两个select。
-
为您的活动禁用全屏模式。 活动在全屏模式下不会重新resize。 您可以在xml中(通过更改活动的主题)或Java代码来完成此操作。 在onCreate()方法中添加以下行。
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
要么
-
使用另一种方式来实现全屏模式。 在你的onCreate()方法中添加下面的代码。
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); View decorView = getWindow().getDecorView(); // Hide the status bar. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions);`
请注意,方法2只适用于Android 4.1及以上版本。
要使其与FullScreen一起工作,请执行以下操作:
使用离子键盘插件。 这使您可以监听键盘何时出现并消失。
OnDeviceReady添加这些事件侦听器:
// Allow Screen to Move Up when Keyboard is Present window.addEventListener('native.keyboardshow', onKeyboardShow); // Reset Screen after Keyboard hides window.addEventListener('native.keyboardhide', onKeyboardHide);
逻辑:
function onKeyboardShow(e) { // Get Focused Element var thisElement = $(':focus'); // Get input size var i = thisElement.height(); // Get Window Height var h = $(window).height() // Get Keyboard Height var kH = e.keyboardHeight // Get Focused Element Top Offset var eH = thisElement.offset().top; // Top of Input should still be visible (30 = Fixed Header) var vS = h - kH; i = i > vS ? (vS - 30) : i; // Get Difference var diff = (vS - eH - i); if (diff < 0) { var parent = $('.myOuter-xs.myOuter-md'); // Add Padding var marginTop = parseInt(parent.css('marginTop')) + diff - 25; parent.css('marginTop', marginTop + 'px'); } } function onKeyboardHide(e) { // Remove All Style Attributes from Parent Div $('.myOuter-xs.myOuter-md').removeAttr('style'); }
基本上,如果他们的差异是减去那么这是键盘覆盖您的input像素的数量。 所以如果你调整你的父母div这应该抵消它。
增加超时的逻辑说300毫秒应该也优化性能(因为这将允许键盘时间出现。
我实施约瑟夫约翰逊解决scheme,它运作良好,我注意到使用这种解决scheme后,有时应用程序的抽屉将无法正常closures。 我添加了一个function来删除侦听器removeOnGlobalLayoutListener,当用户closures了edittexts位于的片段。
//when the application uses full screen theme and the keyboard is shown the content not scrollable! //with this util it will be scrollable once again //http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible public class AndroidBug5497Workaround { private static AndroidBug5497Workaround mInstance = null; private View mChildOfContent; private int usableHeightPrevious; private FrameLayout.LayoutParams frameLayoutParams; private ViewTreeObserver.OnGlobalLayoutListener _globalListener; // For more information, see https://code.google.com/p/android/issues/detail?id=5497 // To use this class, simply invoke assistActivity() on an Activity that already has its content view set. public static AndroidBug5497Workaround getInstance (Activity activity) { if(mInstance==null) { synchronized (AndroidBug5497Workaround.class) { mInstance = new AndroidBug5497Workaround(activity); } } return mInstance; } private AndroidBug5497Workaround(Activity activity) { FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); _globalListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { possiblyResizeChildOfContent(); } }; } public void setListener() { mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener); } public void removeListener() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener); } else { mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener); } } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard/4)) { // keyboard probably just became visible frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } else { // keyboard probably just became hidden frameLayoutParams.height = usableHeightSansKeyboard; } mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); return (r.bottom - r.top); } }
使用我的edittexts所在的类
@Override public void onStart() { super.onStart(); AndroidBug5497Workaround.getInstance(getActivity()).setListener(); } @Override public void onStop() { super.onStop(); AndroidBug5497Workaround.getInstance(getActivity()).removeListener(); }
我尝试了约瑟夫·约翰逊的解决scheme ,但是和其他人一样,我遇到了内容与键盘之间的问题。 发生此问题是因为在使用全屏模式时,软input模式始终处于平移状态。 当你激活一个被软input隐藏的input域时,这个平移会干扰Joseph的解决scheme。
当出现软input时,内容首先根据其原始高度进行平移,然后根据Joseph的解决scheme请求的布局resize。 resize和后续布局不能撤销平移,这会导致差距。 事件的完整顺序是:
- 全局布局侦听器
- 摇摄
- 内容布局(=实际调整内容大小)
禁用平移是不可能的,但是可以通过改变内容的高度来强制平移偏移量为0。 这可以在侦听器中完成,因为它在平移发生之前运行。 将内容高度设置为可用高度会导致平滑的用户体验,即不闪烁。
我也做了这些改变。 如果有任何这些介绍问题,请告诉我:
- 切换确定可用高度以使用
getWindowVisibleDisplayFrame
。 cachingRect
以防止一点点不需要的垃圾。 - 允许侦听器也被删除。 当您针对具有不同全屏要求的不同片段重复使用活动时,这非常有用。
- 不要区分显示或隐藏的键盘,但始终将内容高度设置为可见的显示帧高度。
它已经在Nexus 5上进行了testing,运行API级别为16-24的模拟器的屏幕尺寸从小到大。
该代码已经移植到Kotlin,但将我的更改移植回Java很简单。 让我知道如果你需要帮助:
class AndroidBug5497Workaround constructor(activity: Activity) { private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup private val rootView = contentContainer.getChildAt(0) private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams private val viewTreeObserver = rootView.viewTreeObserver private val listener = { possiblyResizeChildOfContent() } private val contentAreaOfWindowBounds = Rect() private var usableHeightPrevious = 0 // I call this in "onResume()" of my fragment fun addListener() { viewTreeObserver.addOnGlobalLayoutListener(listener) } // I call this in "onPause()" of my fragment fun removeListener() { viewTreeObserver.removeOnGlobalLayoutListener(listener) } private fun possiblyResizeChildOfContent() { contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds) val usableHeightNow = contentAreaOfWindowBounds.height() if (usableHeightNow != usableHeightPrevious) { rootViewLayout.height = usableHeightNow // Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge. rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom) rootView.requestLayout() usableHeightPrevious = usableHeightNow } } }
的确,软键盘的外观似乎不会以任何方式影响Activity
,无论我在FullScreen
模式下select的windowSoftInputMode
是什么。
虽然我找不到这个属性的很多文档,但我认为FullScreen
模式是专为游戏应用而devise的,不需要太多的软键盘使用。 如果您的活动需要通过软键盘进行用户交互,请重新考虑使用非全屏主题。 您可以使用NoTitleBar
主题closuresTitleBar。 你为什么要隐藏通知栏?
我尝试了约瑟夫·约翰逊的课程,它的工作,但并不完全符合我的需求。 而不是模拟android:windowSoftInputMode =“adjustResize”,我需要模拟android:windowSoftInputMode =“adjustPan”。
我正在使用这个全屏webview。 为了平移内容视图到正确的位置,我需要使用一个javascript接口,它提供了具有焦点的页面元素的位置的细节,因此正在接收键盘input。 我已经省略了这些细节,但提供了约瑟夫·约翰逊的课程的重写。 它将为您提供一个非常坚实的基础来实现自定义的泛与他的resize。
package some.package.name; import some.package.name.JavaScriptObject; import android.app.Activity; import android.graphics.Rect; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; //------------------------------------------------------- // ActivityPanner Class // // Convenience class to handle Activity attributes bug. // Use this class instead of windowSoftInputMode="adjustPan". // // To implement, call enable() and pass a reference // to an Activity which already has its content view set. // Example: // setContentView( R.layout.someview ); // ActivityPanner.enable( this ); //------------------------------------------------------- // // Notes: // // The standard method for handling screen panning // when the virtual keyboard appears is to set an activity // attribute in the manifest. // Example: // <activity // ... // android:windowSoftInputMode="adjustPan" // ... > // Unfortunately, this is ignored when using the fullscreen attribute: // android:theme="@android:style/Theme.NoTitleBar.Fullscreen" // //------------------------------------------------------- public class ActivityPanner { private View contentView_; private int priorVisibleHeight_; public static void enable( Activity activity ) { new ActivityPanner( activity ); } private ActivityPanner( Activity activity ) { FrameLayout content = (FrameLayout) activity.findViewById( android.R.id.content ); contentView_ = content.getChildAt( 0 ); contentView_.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { panAsNeeded(); } }); } private void panAsNeeded() { // Get current visible height int currentVisibleHeight = visibleHeight(); // Determine if visible height changed if( currentVisibleHeight != priorVisibleHeight_ ) { // Determine if keyboard visiblity changed int screenHeight = contentView_.getRootView().getHeight(); int coveredHeight = screenHeight - currentVisibleHeight; if( coveredHeight > (screenHeight/4) ) { // Keyboard probably just became visible // Get the current focus elements top & bottom // using a ratio to convert the values // to the native scale. float ratio = (float) screenHeight / viewPortHeight(); int elTop = focusElementTop( ratio ); int elBottom = focusElementBottom( ratio ); // Determine the amount of the focus element covered // by the keyboard int elPixelsCovered = elBottom - currentVisibleHeight; // If any amount is covered if( elPixelsCovered > 0 ) { // Pan by the amount of coverage int panUpPixels = elPixelsCovered; // Prevent panning so much the top of the element // becomes hidden panUpPixels = ( panUpPixels > elTop ? elTop : panUpPixels ); // Prevent panning more than the keyboard height // (which produces an empty gap in the screen) panUpPixels = ( panUpPixels > coveredHeight ? coveredHeight : panUpPixels ); // Pan up contentView_.setY( -panUpPixels ); } } else { // Keyboard probably just became hidden // Reset pan contentView_.setY( 0 ); } // Save usabale height for the next comparison priorVisibleHeight_ = currentVisibleHeight; } } private int visibleHeight() { Rect r = new Rect(); contentView_.getWindowVisibleDisplayFrame( r ); return r.bottom - r.top; } // Customize this as needed... private int viewPortHeight() { return JavaScriptObject.viewPortHeight(); } private int focusElementTop( final float ratio ) { return (int) (ratio * JavaScriptObject.focusElementTop()); } private int focusElementBottom( final float ratio ) { return (int) (ratio * JavaScriptObject.focusElementBottom()); } }
只要保持android:windowSoftInputMode="adjustResize"
。 因为只给出一个"adjustResize"
和"adjustPan"
(窗口调整模式用adjustResize或adjustPan指定,所以强烈build议您始终指定一个或另一个)。 你可以在这里find它: http : //developer.android.com/resources/articles/on-screen-inputs.html
这对我来说是完美的。
如果您使用系统UI方法( https://developer.android.com/training/system-ui/immersive.html ),我只是find了一个简单可靠的解决scheme。
它适用于使用View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
,例如,如果您正在使用CoordinatorLayout
。
它不适用于WindowManager.LayoutParams.FLAG_FULLSCREEN
(也可以在android:windowFullscreen
主题中设置),但是您可以通过SYSTEM_UI_FLAG_LAYOUT_STABLE
( 根据文档 “具有相同的视觉效果”)和解决scheme应该再次运作
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
我已经在运行棉花糖的设备上testing过了。
关键是软键盘也是系统窗口之一(如状态栏和导航栏),所以系统派发的WindowInsets
包含了准确可靠的信息。
对于我们试图在状态栏后面绘制的DrawerLayout
这样的用例,我们可以创build一个只忽略顶部插入的布局,并应用占用软键盘的底部插入。
这是我的自定义FrameLayout
:
/** * Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher, * except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not * and should not be set on this layout. */ public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout { public FitsSystemWindowsExceptTopFrameLayout(Context context) { super(context); } public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(Build.VERSION_CODES.LOLLIPOP) public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0); } else { return super.onApplyWindowInsets(insets); } } }
并使用它:
<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Your original layout here --> </com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>
This should theoretically work for any device without insane modification, much better than any hack that tries to take a random 1/3
or 1/4
of screen size as reference.
(It requires API 16+, but I'm using fullscreen only on Lollipop+ for drawing behind the status bar so it's the best solution in this case.)
You want the bottom bar to stick to the bottom of the view, but when the keyboard is displayed, they should move up to be placed above the keyboard, right?
You can try this code snippet:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ...> <RelativeLayout android:id="@+id/RelativeLayoutTopBar" ...> </RelativeLayout> <LinearLayout android:id="@+id/LinearLayoutBottomBar" android:layout_alignParentBottom = true ...> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="390dp" android:orientation="vertical" android:layout_above="@+id/LinearLayoutBottomBar" android:layout_below="@+id/RelativeLayoutTopBar"> <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:id="@+id/ScrollViewBackground"> ... </ScrollView> </LinearLayout> </RelativeLayout>
The BottomBar will stick to the bottom of the view and the LinearLayout containing the ScrollView will take what's left of the view after the top/bottom bar and the keyboard are displayed. Let me know if it works for you as well.
Thank you Joseph for your answer. However, in the method possiblyResizeChildOfContent(), the portion
else { // keyboard probably just became hidden frameLayoutParams.height = usableHeightSansKeyboard; }
was not working for me, as the lower portion of view became hidden. So I had to take a global variable restoreHeight, and in the constructor, I inserted the last line
restoreHeight = frameLayoutParams.height;
and then I replaced the former mentioned part with
else { // keyboard probably just became hidden frameLayoutParams.height = restoreHeight; }
But I have no idea why your code didn't work for me. It would be of great help, if someone can shed light on this.
I was only using full screen mode to hide the status bar. However, I want the app to resize when keyboard is shown. All of the other solutions (likely due to age of post) were complicated or not possible for my use (want to avoid change Java code for sack of PhoneGap Build).
Instead of using Full screen, I modified my configure for Android to be non-fullscreen:
<preference name="fullscreen" value="false" />
And added the cordova-plugin-statusbar
, via command line:
cordova plugin add cordova-plugin-statusbar
When app has loaded, I simple call a method on the plugin to hide itself, like:
if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar) window.StatusBar.hide();
This works like a charm. Only real downside is that the status bar is breifly visible while the app loads. For my needs, that wasn't an issue.
I have tried out all the possible answers from stackOverflow, finally i solved after a week Long search . I have used the coordinate layout and i changed this with linearLayout and my problem is fixed. I dont know possibly the coordinate layout has bugs or anything my mistake.
In my case, this issue started happening once I added Crosswalk to my Cordova application. My app is not used in fullscreen and android:windowSoftInputMode="adjustPan".
I already had the ionic keyboard plugin in the application, so detecting if the keyboard was up or down was easy thanks to it:
// Listen for events to when the keyboard is opened and closed window.addEventListener("native.keyboardshow", keyboardUp, false); window.addEventListener('native.keyboardhide', keyboardDown, false); function keyboardUp() { $('html').addClass('keyboardUp'); } function keyboardDown() { $('html').removeClass('keyboardUp'); }
I tried all of the fixes above but the simple line that ended up doing it for me was this bit of css:
&.keyboardUp { overflow-y: scroll; }
Hope this saves you the few days I spent on this. 🙂
I used Joseph Johnson created AndroidBug5497Workaround class but getting black space between softkeyboard and the view. I referred this link Greg Ennis . After doing some changes to the above this is my final working code.
public class SignUpActivity extends Activity { private RelativeLayout rlRootView; // this is my root layout private View rootView; private ViewGroup contentContainer; private ViewTreeObserver viewTreeObserver; private ViewTreeObserver.OnGlobalLayoutListener listener; private Rect contentAreaOfWindowBounds = new Rect(); private FrameLayout.LayoutParams rootViewLayout; private int usableHeightPrevious = 0; private View mDecorView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_up); mDecorView = getWindow().getDecorView(); contentContainer = (ViewGroup) this.findViewById(android.R.id.content); listener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { possiblyResizeChildOfContent(); } }; rootView = contentContainer.getChildAt(0); rootViewLayout = (FrameLayout.LayoutParams) rootView.getLayoutParams(); rlRootView = (RelativeLayout) findViewById(R.id.rlRootView); rlRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightDiff = rlRootView.getRootView().getHeight() - rlRootView.getHeight(); if (heightDiff > Util.dpToPx(SignUpActivity.this, 200)) { // if more than 200 dp, it's probably a keyboard... // Logger.info("Soft Key Board ", "Key board is open"); } else { Logger.info("Soft Key Board ", "Key board is CLOSED"); hideSystemUI(); } } }); } // This snippet hides the system bars. protected void hideSystemUI() { // Set the IMMERSIVE flag. // Set the content to appear under the system bars so that the content // doesn't resize when the system bars hide and show. mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } @Override protected void onPause() { super.onPause(); if (viewTreeObserver.isAlive()) { viewTreeObserver.removeOnGlobalLayoutListener(listener); } } @Override protected void onResume() { super.onResume(); if (viewTreeObserver == null || !viewTreeObserver.isAlive()) { viewTreeObserver = rootView.getViewTreeObserver(); } viewTreeObserver.addOnGlobalLayoutListener(listener); } @Override protected void onDestroy() { super.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; } else { this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); } } }
Add android:fitsSystemWindows="true"
to the layout, and this layout will resize.
Full screen please use
“`java
View decorView = getWindow().getDecorView(); int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions);
“`