Ответ 1
- > https://groups.google.com/group/android-developers/msg/5690ac3a9819a53b?pli=1
- > полноэкранный режим не изменяет размер
Я много исследовал настройку макета, когда softkeyboard активна, и я успешно ее реализовал, но проблема возникает, когда я использую android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
this в своем теге активности в файле манифеста.
Для этого я использовал android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"
с разными параметрами, но не повезло.
После этого я реализовал FullScreen
программно и попробовал разный макет для работы с FullScreen
, но все тщетно.
Я ссылался на эти ссылки и смотрел много сообщений, связанных с этой проблемой:
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 кнопки поднимались вверх, когда на экран поступает экранная клавиатура.
- > https://groups.google.com/group/android-developers/msg/5690ac3a9819a53b?pli=1
- > полноэкранный режим не изменяет размер
Основываясь на обходном пути 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 как часть режим мягкого ввода окна активности, но чтобы заставить их работать вместе, я должен переключить полноэкранный режим до появления клавиатуры.
Используйте следующий код:
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);
Примечание - вдохновение исходило из: Скрытие заголовка в полноэкранном режиме
Я попробовал решение от Джозефа Джонсона, но, как и другие, я столкнулся с проблемой разрыва между контентом и клавиатурой. Проблема возникает из-за того, что режим мягкого ввода всегда используется для панорамирования при использовании полноэкранного режима. Это панорамирование мешает решению Джозефа, когда вы активируете поле ввода, которое будет скрыто с помощью мягкого ввода.
При появлении мягкого ввода содержимое сначала подкрашивается на основе его первоначальной высоты, а затем изменяется на макет, запрошенный решением Джозефа. Изменение размера и последующая компоновка не отменят панорамирование, что приводит к разрыву. Полный порядок событий:
Невозможно отключить панорамирование, но можно заставить сдвиг панорамирования быть 0, изменив высоту содержимого. Это можно сделать в прослушивателе, потому что он запускается до начала панорамирования. Установка высоты содержимого на доступную высоту приводит к плавному пользователю, т.е. Не мерцает.
Я также внес эти изменения. Если какой-либо из этих вопросов возникнет, сообщите мне:
getWindowVisibleDisplayFrame
. Rect
кэшируется, чтобы предотвратить небольшое количество ненужного мусора.Он был протестирован на Nexus 5 и эмуляторах с уровнями 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
}
}
}
Мне тоже пришлось столкнуться с этой проблемой, и у меня была работа, над которой я проверил HTC one, галактику 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;
}
}
это, вероятно, не доказательство пули, и, возможно, на некоторых устройствах это не сработает, но это сработало для меня и надеюсь, что это тоже поможет.
Я только что нашел простое и надежное решение, если вы используете системный интерфейс (https://developer.android.com/training/system-ui/immersive.html).
Это работает в случае, когда вы используете View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
, например, если вы используете CoordinatorLayout
.
Это не будет работать для WindowManager.LayoutParams.FLAG_FULLSCREEN
(тот, который вы также можете установить в теме с помощью android:windowFullscreen
), но вы можете добиться аналогичного эффекта с помощью SYSTEM_UI_FLAG_LAYOUT_STABLE
(который "имеет тот же визуальный эффект" в соответствии с документами), и это Решение должно работать снова.
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)
Я проверил это на своем устройстве под управлением Marshmallow.
Ключевым моментом является то, что программные клавиатуры также являются одним из системных окон (таких как строка состояния и панель навигации), поэтому отправляемые системой WindowInsets
содержат точную и надежную информацию о ней.
Для DrawerLayout
использования, такого как DrawerLayout
где мы пытаемся рисовать за строкой состояния, мы можем создать макет, который игнорирует только верхнюю вставку и применяет нижнюю вставку, которая отвечает за программную клавиатуру.
Вот мой пользовательский 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>
Теоретически это должно работать для любого устройства без безумной модификации, намного лучше, чем любой взлом, который пытается использовать в качестве эталона случайный размер экрана 1/3
или 1/4
.
(Требуется API 16+, но я использую полноэкранный режим только на Lollipop+ для рисования за строкой состояния, так что это лучшее решение в этом случае.)
Обратите внимание, что android:windowSoftInputMode="adjustResize"
не работает, если для активности задано WindowManager.LayoutParams.FLAG_FULLSCREEN
. У вас есть два варианта.
Либо отключите полноэкранный режим для своей деятельности. Активность не изменяется в полноэкранном режиме. Вы можете сделать это либо в 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 и выше.
Я реализовал решение Джозефа Джонсона, и он работал хорошо, я заметил, что после использования этого решения иногда ящик приложения не будет закрываться должным образом. Я добавил функциональность для удаления слушателя removeOnGlobalLayoutListener, когда пользователь закрывает фрагмент, где находятся 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();
}
Чтобы заставить его работать с 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');
}
В принципе, если они отличаются от минуса, то это количество пикселей, которые клавиатура покрывает ваш вход. Поэтому, если вы настроите свой родительский div на это, чтобы противодействовать ему.
Добавление тайм-аутов к логике означает, что 300 мс также должны оптимизировать производительность (поскольку это позволит отображать время клавиатуры.
используйте android:windowSoftInputMode="adjustResize|stateHidden
только в том случае, если вы используете параметр "Настройка", а затем отключите свойство изменения размера
Добавить android:fitsSystemWindows="true"
в макет, и этот макет изменит размер.
Я пробовал класс Джозефа Джонсона, и это сработало, но не вполне соответствовало моим потребностям. Вместо эмуляции android: windowSoftInputMode = "adjustResize", мне нужно было эмулировать android: windowSoftInputMode = "adjustPan".
Я использую это для полноэкранного просмотра. Чтобы панорамировать представление содержимого в правильное положение, мне нужно использовать интерфейс javascript, который содержит информацию о позиции элемента страницы, который имеет фокус, и, таким образом, получает ввод с клавиатуры. Я опустил эти детали, но предоставил свой пересмотр класса Джозефа Джонсона. Это обеспечит очень прочную основу для реализации пользовательского панорамирования по сравнению с его размером.
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. Настоятельно рекомендуется всегда указывать одно или другое). Вы можете найти это здесь:
http://developer.android.com/resources/articles/on-screen-inputs.html
Он отлично работает для меня.
Действительно, внешний вид мягкой клавиатуры, по-видимому, никак не влияет на Activity
, независимо от того, какой windowSoftInputMode
я выбираю в режиме FullScreen
.
Хотя я не мог найти много документации по этому свойству, я думаю, что режим FullScreen
был разработан для игрового приложения, которое не требует особого использования мягкой клавиатуры. Если ваша деятельность - это действие, которое требует взаимодействия с пользователем с помощью мягкой клавиатуры, пожалуйста, передумайте, используя тему, отличную от FullScreen. Вы можете отключить TitleBar с помощью темы NoTitleBar
. Почему вы хотите скрыть панель уведомлений?
Я использовал Джозефа Джонсона, созданного для AndroidBug5497Workaround, но получая черное пространство между программной клавиатурой и представлением. Я ссылался на эту ссылку Грег Эннис. После выполнения некоторых изменений выше это мой последний рабочий код.
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 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);
}
}
}
Я в настоящее время использую этот подход, и он работает как шарм. Хитрость в том, что мы получаем высоту клавиатуры из различных методов на 21 выше и ниже, а затем используем ее в качестве нижнего отступа нашего корневого представления в нашей деятельности. Я предположил, что ваш макет не нуждается в верхнем заполнении (идет ниже строки состояния), но если вы это сделаете, сообщите мне, чтобы обновить мой ответ.
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout mainLayout = findViewById(R.id.main_layout);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ViewCompat.setOnApplyWindowInsetsListener(mainLayout , new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
return insets;
}
});
} else {
View decorView = getWindow().getDecorView();
final View contentView = mainLayout;
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
decorView.getWindowVisibleDisplayFrame(r);
//get screen height and calculate the difference with the useable area from the r
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
//if it could be a keyboard add the padding to the view
if (diff != 0) {
// if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
//check if the padding is 0 (if yes set the padding for the keyboard)
if (contentView.getPaddingBottom() != diff) {
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
}
} else {
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0) {
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
}
}
});
}
}
...
}
Не забудьте указать свой корневой вид с идентификатором:
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
Надеюсь, это поможет кому-то.
основан на fooobar.com/questions/16389/... и желание сделать это...
обновленная идея
объединяя ответы от
Соответствующий код:
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
// keyboard probably just became hidden
if(usableHeightPrevious != 0) {
frameLayoutParams.height = usableHeightSansKeyboard;
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
Полный источник на https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java
Создайте статическое значение высоты контейнеров перед открытием клавиатуры. Установите высоту контейнера на основе usableHeightSansKeyboard - heightDifference
когда клавиатура открывается, и возвращайте ее к сохраненному значению, когда она закрывается.
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
int mStatusHeight = getStatusBarHeight();
frameLayoutParams.topMargin = mStatusHeight;
((MainActivity)activity).setMyMainHeight(usableHeightSansKeyboard - heightDifference);
if(BuildConfig.DEBUG){
Log.v("aBug5497", "keyboard probably just became visible");
}
} else {
// keyboard probably just became hidden
if(usableHeightPrevious != 0) {
frameLayoutParams.height = usableHeightSansKeyboard;
((MainActivity)activity).setMyMainHeight();
}
frameLayoutParams.topMargin = 0;
if(BuildConfig.DEBUG){
Log.v("aBug5497", "keyboard probably just became hidden");
}
}
Методы в MainActivity
public void setMyMainHeight(final int myMainHeight) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ConstraintLayout.LayoutParams rLparams = (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
rLparams.height = myMainHeight;
myContainer.setLayoutParams(rLparams);
}
});
}
int mainHeight = 0;
public void setMyMainHeight() {
runOnUiThread(new Runnable() {
@Override
public void run() {
ConstraintLayout.LayoutParams rLparams = (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
rLparams.height = mainHeight;
myContainer.setLayoutParams(rLparams);
}
});
}
Пример контейнера XML
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.constraint.ConstraintLayout
android:id="@+id/my_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintHeight_percent=".8">
Аналогичным образом можно добавить поля при необходимости...
Другое соображение - использование padding. Пример этого можно найти по адресу:
https://github.com/mikepenz/MaterialDrawer/issues/95#issuecomment-80519589
Вы хотите, чтобы нижняя панель придерживалась нижней части представления, но когда клавиатура отображается, они должны перемещаться вверх, чтобы располагаться над клавиатурой, правильно?
Вы можете попробовать этот фрагмент кода:
<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>
BottomBar будет придерживаться нижней части представления, а LinearLayout, содержащий ScrollView, займет то, что осталось от представления после того, как верхняя/нижняя панель и клавиатура отображаются. Дайте мне знать, работает ли это для вас.
Спасибо, Иосиф за ваш ответ. Однако в методе возможноResizeChildOfContent() часть
else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
не работал у меня, так как нижняя часть обзора скрывалась. Поэтому мне пришлось взять глобальную переменную restoreHeight, а в конструкторе я вставил последнюю строку
restoreHeight = frameLayoutParams.height;
а затем я заменил предыдущую часть
else {
// keyboard probably just became hidden
frameLayoutParams.height = restoreHeight;
}
Но я понятия не имею, почему ваш код не работал у меня. Было бы очень полезно, если кто-то может пролить свет на это.
Я использовал только полноэкранный режим, чтобы скрыть строку состояния. Тем не менее, я хочу, чтобы приложение изменялось, когда отображается клавиатура. Все другие решения (вероятно, из-за возраста сообщения) были сложными или невозможными для моего использования (хотите избежать изменения кода Java для пакета PhoneGap Build).
Вместо того, чтобы использовать полноэкранный режим, я изменил настройку для Android на не-полноэкранный режим:
<preference name="fullscreen" value="false" />
И добавил cordova-plugin-statusbar
через командную строку:
cordova plugin add cordova-plugin-statusbar
Когда приложение загрузилось, я просто вызываю метод на плагине, чтобы скрыть себя, например:
if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar)
window.StatusBar.hide();
Это работает как шарм. Только реальный недостаток заключается в том, что строка состояния отображается достаточно быстро, пока приложение загружается. Для моих нужд это не было проблемой.
Я опробовал все возможные ответы от stackOverflow, наконец, решил через неделю длительный поиск. Я использовал компоновку координат, и я изменил это с помощью linearLayout, и моя проблема исправлена. Я не знаю, возможно, в макете координат есть ошибки или что-то еще моя ошибка.
Я пробовал много решений, включая Джозефа Джонсона и Йохана Стуйца. Но в результате я получил пробел между содержимым и клавиатурой на некоторых устройствах (например, Lenovo s820) во всех случаях. Поэтому я внес некоторые изменения в свои коды и, наконец, получил рабочее решение.
Моя идея основана на добавлении поля в верхнюю часть содержимого, когда отображается клавиатура.
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
int difference = usableHeightNow - usableHeightPrevious;
if (difference < 0 && difference < -150) {
keyboardShowed = true;
rootViewLayout.topMargin -= difference + 30;
rootViewLayout.bottomMargin += 30;
}
else if (difference < 0 && difference > -150){
rootViewLayout.topMargin -= difference + 30;
}
else if (difference > 0 && difference > 150) {
keyboardShowed = false;
rootViewLayout.topMargin = 0;
rootViewLayout.bottomMargin = 0;
}
rootView.requestLayout();
Log.e("Bug Workaround", "Difference: " + difference);
usableHeightPrevious = usableHeightNow;
}
Как вы можете видеть, я добавляю 30 пикселей к разнице, потому что между верхней частью экрана и областью содержимого с запасом есть небольшое пробел. И я не знаю, откуда он появляется, поэтому я решил просто уменьшить поля, и теперь он работает именно так, как мне нужно.
1) Создать KeyboardHeightHelper:
public class KeyboardHeightHelper {
private final View decorView;
private int lastKeyboardHeight = -1;
public KeyboardHeightHelper(Activity activity, View activityRootView, OnKeyboardHeightChangeListener listener) {
this.decorView = activity.getWindow().getDecorView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
int keyboardHeight = getKeyboardHeight();
if (lastKeyboardHeight != keyboardHeight) {
lastKeyboardHeight = keyboardHeight;
listener.onKeyboardHeightChange(keyboardHeight);
}
});
}
private int getKeyboardHeight() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
return decorView.getHeight() - rect.bottom;
}
public interface OnKeyboardHeightChangeListener {
void onKeyboardHeightChange(int keyboardHeight);
}
}
2) Пусть ваша деятельность будет на весь экран:
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
3) Прослушайте изменения высоты клавиатуры и добавьте нижний отступ для вашего вида:
View rootView = activity.findViewById(R.id.root); // your root view or any other you want to resize
KeyboardHeightHelper effectiveHeightHelper = new KeyboardHeightHelper(
activity,
rootView,
keyboardHeight -> rootView.setPadding(0, 0, 0, keyboardHeight));
Таким образом, каждый раз, когда на экране появляется клавиатура - нижний отступ для вашего вида будет меняться, и содержимое будет переупорядочено.
Сегодня не работает AdjustResize на полном экране проблема актуальна для Android SDK.
Из ответов я нашел:
решение - но решение имеет этот показатель на изображении проблемы:
Затем я нашел решение и удалил одно ненужное действие:
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
Итак, посмотрите мой фиксированный код решения на Kotlin:
class AndroidBug5497Workaround constructor(val activity: Activity) {
private val content = activity.findViewById<View>(android.R.id.content) as FrameLayout
private val mChildOfContent = content.getChildAt(0)
private var usableHeightPrevious: Int = 0
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 listener = {
possiblyResizeChildOfContent()
}
fun addListener() {
mChildOfContent.apply {
viewTreeObserver.addOnGlobalLayoutListener(listener)
}
}
fun removeListener() {
mChildOfContent.apply {
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
}
private fun possiblyResizeChildOfContent() {
val contentAreaOfWindowBounds = Rect()
mChildOfContent.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
val usableHeightNow = contentAreaOfWindowBounds.height()
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow
rootView.layout(contentAreaOfWindowBounds.left,
contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
mChildOfContent.requestLayout()
usableHeightPrevious = usableHeightNow
}
}
}
Мой код для исправления ошибок:
class LeaveDetailActivity : BaseActivity(){
private val keyBoardBugWorkaround by lazy {
AndroidBug5497Workaround(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
keyBoardBugWorkaround.addListener()
super.onResume()
}
override fun onPause() {
keyBoardBugWorkaround.removeListener()
super.onPause()
}
}
В моем случае эта проблема возникла, когда я добавил Crosswalk в приложение для Кордовы. Мое приложение не используется в полноэкранном и андроидном: windowSoftInputMode = "adjustPan".
У меня уже был плагин с ионной клавиатурой в приложении, поэтому обнаружение того, что клавиатура была вверх или вниз, была легкой благодаря этому:
// 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');
}
Я испробовал все исправления выше, но простая строка, которая закончилась тем, что делала это для меня, была эта бит css:
&.keyboardUp {
overflow-y: scroll;
}
Надеюсь, что это сэкономит вам несколько дней, потраченных на это.:)
В полноэкранном режиме используйте
`` `ява
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
`` `