Android Jak dostosować układ w trybie pełnoekranowym, gdy widoczna jest klawiatura programowa


178

Dużo badałem, aby dostosować układ, gdy klawiatura programowa jest aktywna i udało mi się ją zaimplementować, ale problem pojawia się, gdy używam android:theme="@android:style/Theme.NoTitleBar.Fullscreen"tego w moim tagu aktywności w pliku manifestu.

Do tego użyłem android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"różnych opcji, ale bez powodzenia.

Potem zaimplementowałem FullScreenprogramowo i próbowałem różnych układów, FullScreenale wszystko na próżno.

Skierowałem te linki i obejrzałem tutaj wiele postów związanych z tym problemem:

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/

Oto kod 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>

wprowadź opis obrazu tutaj

Chcę, aby dolne 2 przyciski przesunęły się do góry, gdy pojawi się klawiatura programowa.

wprowadź opis obrazu tutaj


1
Myślę, że musisz dodać przyciski wewnątrz ScrollView i poniżej EditText.
Balaji Khadake

Wypróbowałem już wiele opcji, które nie działają ...
Vineet Shukla

1
umieść przyciski w układzie framelayout i ustaw wagę framelayout na 1 i na koniec użyj tylko android:windowSoftInputMode="adjustPan"powiedz mi, czy to działa ..
Sherif elKhatib

@VineetShukla czy znalazłeś jakieś ćwiczenie z pełnym ekranem?
Muhammad Babar

2
Zauważ, że nie powinieneś używać adjustResizei adjustPanjednocześnie z javadoc android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE: „To nie może być łączone z {@link SOFT_INPUT_ADJUST_PAN}”
Denis Kniazhev

Odpowiedzi:


257

Opierając się na obejściu yghm, stworzyłem wygodną klasę, która pozwala mi rozwiązać problem za pomocą jednowierszowego (oczywiście po dodaniu nowej klasy do kodu źródłowego). Jednowierszowy to:

     AndroidBug5497Workaround.assistActivity(this);

Klasa implementacji to:


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);
    }
}

Mam nadzieję, że to komuś pomoże.


8
Dzięki! Nie mam pojęcia dlaczego, ale musiałem zastąpić return (r.bottom - r.top); go, return r.bottomaby działał na moim HTC One Mini, w przeciwnym razie widok aktywności zostałby przesunięty zbyt wysoko przez rozmiar paska stanu. Nie testowałem tego jeszcze na innym urządzeniu. Mam nadzieję, że to pomoże.
Joan

4
Cześć Joseph Johnson, użyłem twojego kodu i zadziałał idealnie. Ale teraz dni napotykają problem na niektórych małych urządzeniach, który pokazuje lukę (pusty ekran) między klawiaturą a układem. Masz jakiś pomysł na ten problem? Próbowałem też wrócić r. Dnem.
Pankaj

2
Joseph Johnson: Zaimplementowałem twoją metodę, działa dobrze, gdy klikniemy tekst edycji u góry, ale kiedy klikniemy edittext na dole, cały projekt idzie w górę
ranjith

3
Niestety nie działa na Nexusie 7 (2013). Nadal patrzy, nawet po ustawieniu AdjustNothing.
Le-roy Staines

4
Świetna odpowiedź, bardzo dziękuję. Działa na Nexusie 6, ale zamiast używać, frameLayoutParams.height = usableHeightSansKeyboard;muszę użyć, frameLayoutParams.height = usableHeightNow; jeśli nie, niektóre elementy wypadają poza ekran.
RobertoAllende

37

Ponieważ odpowiedź została już wybrana i wiadomo, że problem jest błędem, pomyślałem, że dodam „Możliwe rozwiązanie”.

Możesz przełączać tryb pełnego ekranu, gdy wyświetlana jest klawiatura ekranowa. Dzięki temu funkcja „adjustPan” będzie działać poprawnie.

Innymi słowy, nadal używam @android: style / Theme.Black.NoTitleBar.Fullscreen jako część motywu aplikacji i stateVisible | adjustResize jako część miękkiego trybu wprowadzania w oknie aktywności, ale aby zmusić je do współpracy, muszę przełączyć tryb pełnoekranowy zanim pojawi się klawiatura.

Użyj następującego kodu:

Wyłącz tryb pełnego ekranu

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

Włącz tryb pełnego ekranu

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

Uwaga - inspiracja wzięła się z: Ukrywania tytułu w trybie pełnoekranowym


1
Doceniam, że poświęciłeś temu problemowi +1. Z pewnością przetestuję to podejście i wkrótce dam znać, czy zadziałało, dzięki.
Vineet Shukla

1
Działa zgodnie z podejrzeniem! Naprawdę dobre rozwiązanie! +1 z mojej strony.
Mike,


1
klawiatura zatrzaśnie się, powodując czarne tło klawiatury. Efekt przyciągania nie wygląda dobrze :(
nibz

wow, dzięki ... to działa dla mnie naprawdę dobrze, łącząc Obejście wspomniane przez AndroidBug5497Workaround ... Przesłałem połączone źródło do GitHub ... github.com/CrandellWS/AndroidBug5497Workaround/blob/master/
CrandellWS

23

Wypróbowałem rozwiązanie od Josepha Johnsona , ale tak jak inni natknąłem się na problem luki między treścią a klawiaturą. Ten problem występuje, ponieważ podczas korzystania z trybu pełnoekranowego tryb wprowadzania programowego jest zawsze panoramowany . To panoramowanie koliduje z rozwiązaniem Josepha, gdy aktywujesz pole wejściowe, które byłoby ukryte przez miękkie wejście.

Kiedy pojawia się miękki sygnał wejściowy, zawartość jest najpierw przesuwana w panoramie na podstawie jej oryginalnej wysokości, a następnie zmieniana zgodnie z układem wymaganym przez rozwiązanie Josepha. Zmiana rozmiaru i późniejszy układ nie cofają panoramowania, co powoduje powstanie luki. Pełna kolejność wydarzeń to:

  1. Odbiornik układu globalnego
  2. Panoramowanie
  3. Układ treści (= rzeczywista zmiana rozmiaru treści)

Nie można wyłączyć panoramowania, ale można wymusić przesunięcie panoramy na 0, zmieniając wysokość zawartości. Można to zrobić w odbiorniku, ponieważ jest uruchamiane przed panoramowaniem. Ustawienie wysokości treści na dostępną wysokość zapewnia płynne wrażenia użytkownika, tj. Brak migotania.

Ja też dokonałem tych zmian. Jeśli którykolwiek z tych elementów powoduje problemy, daj mi znać:

  • Przełączane określanie dostępnej wysokości do wykorzystania getWindowVisibleDisplayFrame. RectSą buforowane, aby zapobiec trochę niepotrzebnych śmieci.
  • Pozwól też na usunięcie słuchacza. Jest to przydatne, gdy ponownie używasz działania dla różnych fragmentów o różnych wymaganiach dotyczących pełnego ekranu.
  • Nie rozróżniaj klawiatury pokazanej lub ukrytej, ale zawsze ustawiaj wysokość zawartości na widoczną wysokość ramki wyświetlania.

Został przetestowany na Nexusie 5 i emulatorach z poziomami API 16-24 z ekranami o rozmiarach od małych do dużych.

Kod został przeniesiony do Kotlin, ale przeniesienie moich zmian z powrotem na Javę jest proste. Daj mi znać jeśli potrzebujesz pomocy:

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 = ViewTreeObserver.OnGlobalLayoutListener { 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
        }
    }
}

9
To wydaje się być najlepszą odpowiedzią. Przeniosłem się na java tutaj gist.github.com/grennis/2e3cd5f7a9238c59861015ce0a7c5584 . Zauważ, że otrzymywałem wyjątki, że obserwator nie żyje i również musiałem to sprawdzić.
Greg Ennis

O mój Boże! przeszukuje wszystkie hierarchie widoków systemowych, szukając przestrzeni Ducha. Byłem blisko wyrzucenia komputerów dla food trucka, ale zobaczyłem twoją odpowiedź w ostatniej chwili. Działa :)
rupps

1
@Greg Ennis Dzięki za port Java. Zaoszczędzono dużo wysiłku i czasu.
Ikun

@GregEnnis, dzięki, Twoje rozwiązanie działa z onResume (), onPause (), onDestroy () (zobacz komentarze w kodzie GitHub).
CoolMind

To działa dla mnie, z wyjątkiem tego, że wywołanie removeListener wydaje się nie działać. Umieszczam punkty przerwania zarówno w possiblyResizeChildOfContentwywołaniu, jak i removeListenerwywołaniu, a nawet po osiągnięciu removeListenerpunktu przerwania possiblyResizeChildOfContentnadal jest wywoływana. Czy ktoś jeszcze ma ten problem?
Quinn

14

Właśnie znalazłem proste i niezawodne rozwiązanie, jeśli korzystasz z podejścia systemowego UI ( https://developer.android.com/training/system-ui/immersive.html ).

Działa w przypadku, gdy używasz View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREENnp. Gdy używasz CoordinatorLayout.

To nie zadziała WindowManager.LayoutParams.FLAG_FULLSCREEN(ten, który możesz również ustawić w motywie android:windowFullscreen), ale możesz osiągnąć podobny efekt z SYSTEM_UI_FLAG_LAYOUT_STABLE(który „ma ten sam efekt wizualny” zgodnie z dokumentacją ) i to rozwiązanie powinno działać ponownie.

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)

Przetestowałem to na moim urządzeniu z systemem Marshmallow.

Kluczowe jest to, że klawiatury programowe są również jednym z okien systemowych (takie jak pasek stanu i pasek nawigacji), więc WindowInsetswysyłane przez system zawierają dokładne i wiarygodne informacje na jego temat.

W przypadku użycia, na przykład w DrawerLayoutprzypadku, gdy próbujemy rysować za paskiem stanu, możemy utworzyć układ, który ignoruje tylko górną wstawkę i stosuje dolną wstawkę, która odpowiada za klawiaturę programową.

Oto mój zwyczaj 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);
        }
    }
}

I aby z niego skorzystać:

<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>

Powinno to teoretycznie działać na każdym urządzeniu bez szalonych modyfikacji, znacznie lepiej niż jakikolwiek hack, który próbuje wziąć losowy 1/3lub 1/4rozmiar ekranu jako odniesienie.

(Wymaga API 16+, ale używam pełnego ekranu tylko w Lollipop + do rysowania za paskiem stanu, więc jest to najlepsze rozwiązanie w tym przypadku.)


@Dilip Działa na API 16+ pod warunkiem spełnienia w / w warunków.
Hai Zhang

10

Należy pamiętać, że android:windowSoftInputMode="adjustResize"nie działa, gdy WindowManager.LayoutParams.FLAG_FULLSCREENjest ustawiony na aktywność. Masz dwie możliwości.

  1. Wyłącz tryb pełnoekranowy dla swojej aktywności. Aktywność nie jest zmieniana w trybie pełnoekranowym. Możesz to zrobić w xml (zmieniając temat działania) lub w kodzie Java. Dodaj następujące wiersze do metody onCreate ().

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);   
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`

LUB

  1. Użyj alternatywnego sposobu, aby przejść do trybu pełnoekranowego. Dodaj następujący kod do metody 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);`

Należy pamiętać, że metoda-2 działa tylko w systemie Android 4.1 i nowszych.


@AnshulTyagi metoda-2 działa tylko w systemie Android 4.1 i nowszych.
Abhinav Chauhan

4
Testowana na 5.0 i 4.4.2, odpowiednio Nexus 9 i Samsung s4, druga metoda nie działa.
RobVoisey

1
Druga metoda po prostu nie działa i zmarnowałem na nią dużo czasu.
Greg Ennis

Dziękuję, ratuj mój dzień.
Deni Rohimat

9

Musiałem też zmierzyć się z tym problemem i miałem pracę, którą sprawdziłem na HTC One, Galaxy S1, S2, S3, Note i HTC sensation.

umieść odbiornik globalnego układu w widoku głównym układu

mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
            public void onGlobalLayout() {
                checkHeightDifference();
            }
    });

i tam sprawdziłem różnicę wysokości i jeśli różnica wysokości ekranu jest większa niż jedna trzecia na wysokości ekranu, to możemy założyć, że klawiatura jest otwarta. wziął to z tej odpowiedzi .

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;
    }
}

to prawdopodobnie nie jest kuloodporne i może na niektórych urządzeniach to nie zadziała, ale zadziałało dla mnie i mam nadzieję, że ci też pomoże.


1
Potrzebowałem pewnych poprawek, ale zadziałało. W Nexusie 7 2013 musiałem zmniejszyć wysokość klawiatury (screenHeight / 3) o kilka pikseli. Niezły pomysł, dzięki!
Joao Sousa

7

Wdrożyłem rozwiązanie Josepha Johnsona i działa dobrze, zauważyłem, że po zastosowaniu tego rozwiązania czasami szuflada aplikacji nie zamyka się poprawnie. Dodałem funkcję usuwania nasłuchiwania removeOnGlobalLayoutListener, gdy użytkownik zamknie fragment, w którym znajdują się 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);
    } 
}

używa klasy, w której znajdują się moje edittexts

@Override
public void onStart()
{
    super.onStart();
    AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}

@Override
public void onStop()
{
    super.onStop();
    AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}

7

Dodaj android:fitsSystemWindows="true"do układu, a ten układ zmieni rozmiar.


To właśnie rozwiązało to dla mnie. Ponadto pomyśl, upewnij się, że ustawiłeś go na odpowiedni widok. Jeśli masz tło, które powinno znajdować się poniżej paska stanu, nie ustawiaj go tam, ale na układzie wewnątrz. Prawdopodobnie widoki EditText itp. Powinny znajdować się wewnątrz tego drugiego układu. Obejrzyj także tę prelekcję, ponieważ wszystko jest bardziej zrozumiałe: youtube.com/watch?v=_mGDMVRO3iE
Stan

U mnie też zadziałało. Dzięki komentarzowi @Stan mogłem również sprawić, że będzie działał z motywem FULLSCREEN umieszczając ten atrybut na ViewPager zamiast układu aktywności / fragmentu.
marcouberti

5

Aby to działało z FullScreen:

Użyj wtyczki klawiatury jonowej. Pozwala to nasłuchiwać, kiedy klawiatura pojawia się i znika.

OnDeviceReady dodaj następujące detektory zdarzeń:

// Allow Screen to Move Up when Keyboard is Present
window.addEventListener('native.keyboardshow', onKeyboardShow);
// Reset Screen after Keyboard hides
window.addEventListener('native.keyboardhide', onKeyboardHide);

Logika:

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');
}

Zasadniczo, jeśli różnica wynosi minus, to jest to liczba pikseli, które pokrywa klawiatura na wejściu. Więc jeśli dostosujesz swój nadrzędny div o to, to powinno temu przeciwdziałać.

Dodanie limitów czasu do logiki mówi, że 300 ms powinno również zoptymalizować wydajność (ponieważ pozwoli to na pojawienie się czasu na klawiaturze.


3

Wypróbowałem lekcje Josepha Johnsona i zadziałało, ale nie do końca spełniło moje potrzeby. Zamiast emulować android: windowSoftInputMode = "adjustResize", potrzebowałem emulować android: windowSoftInputMode = "adjustPan".

Używam tego do pełnoekranowego widoku internetowego. Aby przesunąć widok treści do właściwej pozycji, muszę użyć interfejsu javascript, który dostarcza szczegółowych informacji na temat pozycji elementu strony, na którym jest fokus, a zatem otrzymuje dane wejściowe z klawiatury. Pominąłem te szczegóły, ale podałem moje przepisanie klasy Josepha Johnsona. Zapewni to bardzo solidną podstawę do zaimplementowania niestandardowej panoramy w porównaniu do jego zmiany rozmiaru.

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());
    }

}

wydaje mi się, że jest to, czego potrzebuję, czy mógłbyś dodać pełną próbkę? dziękuję za twoją pracę!
vilicvane

Nie chciałem publikować całego projektu. To, co dostarczyłem, przyniesie Ci jednak bardzo długą drogę do doskonale działającego rozwiązania. Co musisz zdefiniować siebie: utwórz klasę „JavaScriptObject” i wstaw ją do swojego webview jako interfejs js (sprawdź dokumentację webview). Jest duża szansa, że ​​już to zrobiłeś, pisząc coś, co wykorzystuje przeglądarkę internetową w sposób kompleksowy. Dodaj JavaScript w widoku WWW, aby nasłuchiwać zdarzeń fokusu i przesyłać do klasy JavaScriptObject dane dotyczące pozycjonowania elementu fokusa.
BuvinJ

2

Rzeczywiście wygląd miękkiej klawiatury nie wydaje się wpływać Activityw żaden sposób na to, co windowSoftInputModewybiorę w FullScreentrybie.

Chociaż nie mogłem znaleźć zbyt wielu dokumentacji na temat tej właściwości, myślę, że FullScreentryb został zaprojektowany dla aplikacji do gier, które nie wymagają dużego użycia miękkiej klawiatury. Jeśli jest to działanie, które wymaga interakcji użytkownika z klawiaturą programową, rozważ użycie motywu innego niż FullScreen. Możesz wyłączyć pasek tytułu za pomocą NoTitleBarmotywu. Dlaczego chcesz ukryć pasek powiadomień?


2

Po prostu zachowaj jako android:windowSoftInputMode="adjustResize". Ponieważ jest podawany, aby zachować tylko jedno z "adjustResize"i "adjustPan"(Tryb regulacji okna jest określany za pomocą adjustResize lub adjustPan. Zaleca się, aby zawsze określać jedno lub drugie). Możesz go znaleźć tutaj: http://developer.android.com/resources/articles/on-screen-inputs.html

U mnie działa idealnie.


Nie mam żadnego problemu ... Próbowałem również twojego XML. Ten też działa… na wersji 2.2
Balaji Khadake,

Próbowałem tylko z trybem pełnoekranowym ... testuję go na moim Nexusie One i Nexusie S .... Działa.
Balaji Khadake

1
Próbowałem z Galaxy S, HTC Wildfire, HTC Hero, Motorola Deify i Sony XPeria. Nie działa na żadnym urządzeniu.
Vineet Shukla


2

Obecnie używam tego podejścia i działa jak urok. Sztuczka polega na tym, że uzyskujemy wysokość klawiatury z różnych metod na 21 powyżej i poniżej, a następnie używamy jej jako dolnego wypełnienia naszego widoku głównego w naszej aktywności. Założyłem, że Twój układ nie wymaga górnej wyściółki (znajduje się poniżej paska stanu), ale jeśli tak, poinformuj mnie, żebym zaktualizował moją odpowiedź.

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);
                        }
                    }
                }
            });
        }
    }
...
}

Nie zapomnij zaadresować swojego widoku głównego za pomocą identyfikatora:

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">

Mam nadzieję, że to komuś pomoże.


1
Nie mogę zrozumieć, dlaczego ta odpowiedź wciąż nie jest na szczycie. Że inni glitch, flash, ale ten jest genialny, szczególnie jeśli masz 5+ api.
Anton Shkurenko

1

używaj tylko android:windowSoftInputMode="adjustResize|stateHiddenpodczas używania AdjustPan, a następnie wyłącz właściwość zmiany rozmiaru


Ja też go użyłem ... proszę spraw, abyś robił to w trybie pełnoekranowym i na jakim urządzeniu testujesz?
Vineet Shukla,

HTC NEXUS one, ok i hvnt dodaj pełny ekran
Mohammed Azharuddin Shaikh

czy możesz użyć getWindow (). requestFeature (Window.FEATURE_NO_TITLE); onCreate () zamiast używać theme?
Mohammed Azharuddin Shaikh,

10
powyższy kod działa dobrze bez pełnego ekranu, ale dodaje pełny ekran albo z xml, albo z kodu ... To nie działa ... Przeczytaj uważnie pytanie.
Vineet Shukla,

1

Użyłem Josepha Johnsona, który stworzył klasę AndroidBug5497Workaround, ale otrzymałem czarną przestrzeń między klawiaturą programową a widokiem. Skierowałem ten link Greg Ennis . Po wprowadzeniu kilku zmian do powyższego jest to mój ostatni działający kod.

 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);
  }
 }
}

1

na podstawie https://stackoverflow.com/a/19494006/1815624 i chęci, aby tak się stało ...

zaktualizowany pomysł


łączenie odpowiedzi od

Odpowiedni kod:

        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);

            }

Pełne źródło na https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java

stary pomysł

Utwórz statyczną wartość wysokości kontenera przed otwarciem klawiatury Ustaw wysokość kontenera na podstawie usableHeightSansKeyboard - heightDifference czasu otwarcia klawiatury i przywróć zapisaną wartość po jej zamknięciu

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");
                }
            }

Metody w 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);
        }

    });

}

Przykład kontenera 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">

podobnie marginesy można dodać w razie potrzeby ...

Inną kwestią jest użycie dopełnienia, którego przykład można znaleźć pod adresem:

https://github.com/mikepenz/MaterialDrawer/issues/95#issuecomment-80519589


1

1) Utwórz 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) Pozwól swojej aktywności na pełny ekran:

activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

3) Posłuchaj zmian wysokości klawiatury i dodaj dolną wyściółkę dla swojego widoku:

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));

Tak więc za każdym razem, gdy na ekranie pojawi się klawiatura - dolne wypełnienie widoku ulegnie zmianie, a treść zostanie ponownie ułożona.


0

Chcesz, aby dolny pasek przylegał do dołu widoku, ale kiedy klawiatura jest wyświetlana, powinna przesunąć się w górę, aby umieścić ją nad klawiaturą, prawda?

Możesz wypróbować ten fragment kodu:

<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 pozostanie na dole widoku, a LinearLayout zawierający ScrollView zajmie to, co pozostało z widoku po wyświetleniu górnego / dolnego paska i klawiatury. Daj mi znać, jeśli to działa również dla Ciebie.


1
Bardzo dziwne, ponieważ kilkakrotnie działało w moich aplikacjach. Nawiasem mówiąc, RelativeLayout nie ma orientacji, więc możesz usunąć te atrybuty w kodzie. Właśnie rozpoznałem, że mogłem skrócić fragment kodu do wiersza: android: layout_below = "@ + id / scoringContainerView", który musisz dodać do swojego
ScrollView

Pełny ekran? Masz na myśli bez układu u góry?
banzai86

nie ..... mam na myśli brak paska stanu, który pokazuje żywotność baterii, łączność z urządzeniem itp ...
Vineet Shukla

nie, pasek stanu jest widoczny w mojej aplikacji. czy możesz spróbować zmienić kolejność swoich układów, co oznacza, że ​​umieszczasz kod układu za pomocą przycisków nad innym kodem, a następnie spróbuj ponownie? może musisz je najpierw zdefiniować, aby użyć układu_poniżej
banzai86

1
przeczytaj uważnie pytanie ...... Wspomniałem, że mam problem z trybem
pełnoekranowym

0

Dziękuję Józefie za odpowiedź. Jednak w metodzie prawdopodobnieResizeChildOfContent () część

else {
            // keyboard probably just became hidden
            frameLayoutParams.height = usableHeightSansKeyboard;
        }

nie działało dla mnie, ponieważ dolna część widoku została ukryta. Musiałem więc wziąć globalną zmienną restoreHeight iw konstruktorze wstawiłem ostatnią linię

restoreHeight = frameLayoutParams.height;

a potem wymieniłem poprzednią wymienioną część na

else {
            // keyboard probably just became hidden
            frameLayoutParams.height = restoreHeight;
        }

Ale nie mam pojęcia, dlaczego twój kod nie zadziałał dla mnie. Byłoby bardzo pomocne, gdyby ktoś mógł rzucić na to światło.


0

Używałem trybu pełnoekranowego tylko do ukrycia paska stanu. Jednak chcę, aby aplikacja zmieniała rozmiar po wyświetleniu klawiatury. Wszystkie inne rozwiązania (prawdopodobnie ze względu na wiek postu) były skomplikowane lub niemożliwe do mojego użycia (chcę uniknąć zmiany kodu Java dla pakietu PhoneGap Build).

Zamiast używać pełnego ekranu, zmodyfikowałem konfigurację dla Androida, aby nie była pełnoekranowa:

            <preference name="fullscreen" value="false" />

I dodał cordova-plugin-statusbar, za pomocą wiersza poleceń:

cordova plugin add cordova-plugin-statusbar

Po załadowaniu aplikacji po prostu wywołuję metodę we wtyczce, aby się ukryć, na przykład:

    if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar)
        window.StatusBar.hide();

To działa jak urok. Jedynym prawdziwym minusem jest to, że pasek stanu jest wyraźnie widoczny podczas ładowania aplikacji. Dla moich potrzeb to nie był problem.


0

Wypróbowałem wszystkie możliwe odpowiedzi ze stackOverflow, w końcu rozwiązałem po tygodniu Długie wyszukiwanie. Użyłem układu współrzędnych i zmieniłem to za pomocą linearLayout i mój problem został rozwiązany. Nie wiem, czy w układzie współrzędnych są błędy lub coś mojego.


0

Próbowałem wielu rozwiązań, w tym Josepha Johnsona i Johana Stuytsa. Ale w rezultacie otrzymałem białą przestrzeń między treścią a klawiaturą na niektórych urządzeniach (takich jak Lenovo s820) we wszystkich przypadkach. Więc wprowadziłem kilka zmian w ich kodach i wreszcie otrzymałem działające rozwiązanie.

Mój pomysł oparty na dodaniu marginesu u góry zawartości, gdy klawiatura jest wyświetlana.

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;
}

Jak widać, dodaję 30 px do różnicy, ponieważ między górą ekranu a strefą treści z marginesem jest mała biała przestrzeń. I nie wiem, skąd się to pojawia, więc postanowiłem po prostu zmniejszyć marginesy i teraz działa dokładnie tak, jak potrzebowałem.


0

Obecnie nie działa problem z dostosowywaniem rozmiaru na pełnym ekranie, który dotyczy zestawu SDK z systemem Android.

Z odpowiedzi, które znalazłem:
rozwiązanie - ale rozwiązanie ma ten problem z obrazem:

Niż znalazłem rozwiązanie i usunąłem jedną niepotrzebną akcję:

this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

Zobacz więc mój kod rozwiązania naprawczego w 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
        }
    }
}

Mój kod implementacji naprawy błędów:

 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()
    }
}

0

Nie używaj:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

ponieważ działa źle. Zamiast tego użyj:

fun setFullScreen(fullScreen: Boolean) {
        val decorView = getWindow().getDecorView()
        val uiOptions : Int
        if(fullScreen){
            uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN // this hide statusBar
            toolbar.visibility = View.GONE // if you use toolbar
            tabs.visibility = View.GONE // if you use tabLayout
        } else {
            uiOptions = View.SYSTEM_UI_FLAG_VISIBLE // this show statusBar
            toolbar.visibility = View.VISIBLE
            tabs.visibility = View.VISIBLE
        }
        decorView.setSystemUiVisibility(uiOptions)
    }

-1

W moim przypadku ten problem zaczął się pojawiać po dodaniu Crosswalk do mojej aplikacji Cordova. Moja aplikacja nie jest używana na pełnym ekranie i w systemie Android: windowSoftInputMode = "adjustPan".

Miałem już wtyczkę klawiatury jonowej w aplikacji, więc wykrycie, czy klawiatura jest podniesiona czy nie, było dzięki niej łatwe:

// 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');
}

Wypróbowałem wszystkie powyższe poprawki, ale prostą linią, która ostatecznie zrobiła to za mnie, była ta część CSS:

&.keyboardUp {
        overflow-y: scroll;
}

Mam nadzieję, że zaoszczędzi ci to kilku dni, które nad tym spędziłem. :)


Używam przejścia dla pieszych z Cordova, a także z Androidem: windowSoftInputMode = "adjustPan". Jednak to nie działa. Widzę, że klasa jest dodawana do elementu html, ale css nie ma wpływu na ekran. Czy jest jakieś inne ustawienie, które umożliwia przesuwanie ekranu?
darewreck

Muszę ustawić add transform: translateY (0px), aby działał. Jednak przewijanie w ogóle nie działa. Jakieś pomysły?
darewreck
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.