Android Cara menyesuaikan tata letak dalam Mode Layar Penuh ketika papan tombol terlihat

178

Saya telah banyak meneliti untuk menyesuaikan tata letak ketika papan tombol aktif dan saya telah berhasil mengimplementasikannya tetapi masalahnya muncul ketika saya menggunakan android:theme="@android:style/Theme.NoTitleBar.Fullscreen"ini dalam tag aktivitas saya dalam file manifes.

Untuk ini saya telah menggunakan android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"opsi yang berbeda tetapi tidak berhasil.

Setelah itu saya mengimplementasikan secara FullScreenterprogram dan mencoba berbagai tata letak untuk bekerja FullScreentetapi semuanya sia-sia.

Saya merujuk tautan ini dan telah melihat banyak posting di sini terkait dengan masalah ini:

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/

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

masukkan deskripsi gambar di sini

Saya ingin tombol 2 bawah harus naik ketika softkeyboard muncul dalam gambar.

masukkan deskripsi gambar di sini

Vineet Shukla
sumber
1
Saya pikir Anda harus menambahkan Tombol di dalam ScrollView dan di bawah EditText.
Balaji Khadake
Saya sudah mencoba banyak opsi yang tidak berhasil ...
Vineet Shukla
1
letakkan kancing Anda di framelayout dan atur bobot framelayout ke 1 dan akhirnya gunakan hanya android:windowSoftInputMode="adjustPan"beri tahu saya jika ini berhasil ..
Sherif elKhatib
@VineetShukla apakah Anda menemukan latihan dengan layar penuh ??
Muhammad Babar
2
Perhatikan bahwa Anda tidak boleh menggunakan adjustResizedan adjustPanpada saat yang sama, dari javadoc dari android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE: "Ini tidak dapat digabungkan dengan {@link SOFT_INPUT_ADJUST_PAN}"
Denis Kniazhev

Jawaban:

257

Berdasarkan solusi yghm, saya membuat kelas kenyamanan yang memungkinkan saya untuk menyelesaikan masalah dengan satu-liner (setelah menambahkan kelas baru ke kode sumber saya tentu saja). Satu-liner adalah:

     AndroidBug5497Workaround.assistActivity(this);

Dan kelas implementasi adalah:


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

Semoga ini bisa membantu seseorang.

Joseph Johnson
sumber
8
Terima kasih! Saya tidak tahu mengapa, tetapi saya harus mengganti return (r.bottom - r.top); dengan return r.bottomuntuk membuatnya bekerja pada HTC One Mini saya, jika tidak, tampilan aktivitas akan didorong terlalu tinggi oleh ukuran bilah status. Saya belum mengujinya di perangkat lain. Semoga itu bisa membantu.
Joan
4
Hai Joseph johnson, saya menggunakan kode Anda dan itu bekerja dengan sempurna. Namun kini beberapa hari menghadapi masalah pada beberapa perangkat kecil yang menunjukkan celah (layar kosong) antara keyboard dan tata letak. Apakah Anda tahu tentang masalah ini? Saya juga mencoba mengembalikan r.bottom.
Pankaj
2
Joseph Johnson: Saya telah menerapkan metode Anda, ini berfungsi dengan baik ketika kami mengklik teks edit atas tetapi ketika kami mengklik di bagian bawah edittext semua desain naik
ranjith
3
Sayangnya itu tidak berfungsi pada Nexus 7 (2013). Itu masih panci bahkan dengan set AdjustNothing.
Le-roy Staines
4
Jawaban yang luar biasa, terima kasih banyak. Ini bekerja pada Nexus 6 tetapi alih-alih menggunakan frameLayoutParams.height = usableHeightSansKeyboard;saya harus menggunakan frameLayoutParams.height = usableHeightNow; Jika saya tidak melakukan ini beberapa elemen jatuh di luar layar.
RobertoAllende
36

Karena jawabannya telah dipilih dan masalah diketahui sebagai bug, saya pikir saya akan menambahkan "Kemungkinan Bekerja Sekitar".

Anda dapat mengaktifkan mode layar penuh saat keyboard lunak ditampilkan. Ini memungkinkan "AdjustPan" bekerja dengan benar.

Dengan kata lain, saya masih menggunakan @android: style / Theme.Black.NoTitleBar.Fullscreen sebagai bagian dari tema aplikasi dan stateVisible | AdjustResize sebagai bagian dari mode input lunak jendela aktivitas tetapi untuk membuatnya bekerja bersama, saya harus beralih ke mode layar penuh sebelum keyboard muncul.

Gunakan Kode berikut:

Matikan mode layar penuh

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

Aktifkan mode layar penuh

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

Catatan - inspirasi berasal dari: Menyembunyikan Judul dalam mode Layar Penuh

LEO
sumber
1
Saya menghargai bahwa Anda telah memberikan waktu untuk masalahnya, +1 untuk itu. Saya pasti akan menguji pendekatan ini dan memberi tahu Anda segera jika itu berhasil untuk saya, terima kasih.
Vineet Shukla
1
Bekerja seperti yang diduga! Solusi yang sangat bagus! +1 dari sisi saya.
Mike
1
keyboard terkunci, membuat latar belakang keyboard hitam. Efek gertakan tidak terlihat bagus :(
nibz
wow terima kasih ... ini bekerja dengan baik untuk saya dengan menggabungkan Workaround yang disebutkan oleh AndroidBug5497Workaround ... Saya mengunggah sumber gabungan ke GitHub ... github.com/CrandellWS/AndroidBug5497Workaround/blob/master/…
CrandellWS
23

Saya mencoba solusi dari Joseph Johnson , tetapi seperti orang lain saya mengalami masalah kesenjangan antara konten dan keyboard. Masalahnya terjadi karena mode input lunak selalu menggeser ketika menggunakan mode layar penuh. Panning ini mengganggu solusi Joseph ketika Anda mengaktifkan bidang input yang akan disembunyikan oleh input lunak.

Ketika input lunak muncul, konten pertama-tama digeser berdasarkan ketinggian aslinya, dan kemudian diubah ukurannya oleh tata letak yang diminta oleh solusi Joseph. Mengubah ukuran dan tata letak selanjutnya tidak membatalkan panning, yang menghasilkan celah. Urutan lengkap acara adalah:

  1. Pendengar tata letak global
  2. Panning
  3. Layout konten (= mengubah ukuran konten yang sebenarnya)

Tidak mungkin untuk menonaktifkan panning, tetapi dimungkinkan untuk memaksa offset pan menjadi 0 dengan mengubah ketinggian konten. Ini bisa dilakukan di pendengar, karena dijalankan sebelum panning berlangsung. Mengatur ketinggian konten ke ketinggian yang tersedia menghasilkan pengalaman pengguna yang lancar, yaitu tidak berkedip.

Saya juga melakukan perubahan ini. Jika ada yang menimbulkan masalah, beri tahu saya:

  • Menentukan penentuan ketinggian yang tersedia untuk digunakan getWindowVisibleDisplayFrame. The Rectcache untuk mencegah sedikit sampah yang tidak dibutuhkan.
  • Izinkan pendengar untuk dihapus juga. Ini berguna ketika Anda menggunakan kembali suatu kegiatan untuk fragmen yang berbeda memiliki persyaratan layar penuh yang berbeda.
  • Jangan membedakan antara keyboard yang ditampilkan atau disembunyikan, tetapi selalu atur tinggi konten ke tinggi bingkai tampilan yang terlihat.

Ini telah diuji pada Nexus 5, dan emulator menjalankan level API 16-24 dengan ukuran layar mulai dari kecil hingga besar.

Kode telah porting ke Kotlin, tetapi porting perubahan saya kembali ke Jawa sederhana. Beri tahu saya jika Anda membutuhkan bantuan:

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
        }
    }
}
Johan Stuyts
sumber
9
Ini sepertinya jawaban yang terbaik. Saya porting ke java di sini gist.github.com/grennis/2e3cd5f7a9238c59861015ce0a7c5584 . Perhatikan saya mendapatkan pengecualian bahwa pengamat tidak hidup, dan harus memeriksanya juga.
Greg Ennis
Ya Tuhan! telah melintasi semua hierarki tampilan sistem mencari ruang Ghost itu. Saya sudah dekat dengan parit komputer untuk truk makanan tetapi melihat jawaban Anda di menit terakhir.
Berhasil
1
@Greg Ennis Terima kasih untuk port Java. Menghemat banyak usaha dan waktu.
Ikun
@GregEnnis, terima kasih, solusi Anda berfungsi dengan onResume (), onPause (), onDestroy () (lihat komentar dalam kode GitHub).
CoolMind
Ini berfungsi untuk saya, kecuali bahwa panggilan removeListener tampaknya tidak berfungsi. Saya meletakkan breakpoints di dalam possiblyResizeChildOfContentpanggilan dan removeListenerpanggilan, dan bahkan setelah saya mencapai removeListenerbreakpoint, possiblyResizeChildOfContentmasih dipanggil. Adakah orang lain yang mengalami masalah ini?
Quinn
14

Saya baru saja menemukan solusi yang sederhana dan andal jika Anda menggunakan pendekatan sistem UI ( https://developer.android.com/training/system-ui/immersive.html ).

Ini berfungsi dalam kasus ketika Anda menggunakan View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, misalnya jika Anda menggunakanCoordinatorLayout .

Ini tidak akan berfungsi untuk WindowManager.LayoutParams.FLAG_FULLSCREEN(Yang Anda juga dapat mengatur dengan tema android:windowFullscreen), tetapi Anda dapat mencapai efek yang sama dengan SYSTEM_UI_FLAG_LAYOUT_STABLE(yang "memiliki efek visual yang sama" menurut dokumen ) dan solusi ini harus bekerja lagi.

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)

Saya sudah mengujinya di perangkat saya yang menjalankan Marshmallow.

Kuncinya adalah keyboard lunak juga merupakan salah satu jendela sistem (seperti bilah status dan bilah navigasi), sehingga yang WindowInsetsdikirim oleh sistem berisi informasi yang akurat dan dapat diandalkan tentang hal itu.

Untuk use case seperti pada DrawerLayout kami mencoba menggambar di belakang bilah status, Kami dapat membuat tata letak yang mengabaikan hanya inset atas, dan menerapkan inset bawah yang menyumbang keyboard lunak.

Ini kebiasaan saya 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);
        }
    }
}

Dan untuk menggunakannya:

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

Secara teori ini harus berfungsi untuk perangkat apa pun tanpa modifikasi gila, jauh lebih baik daripada peretasan yang mencoba mengambil ukuran layar acak 1/3atau 1/4sebagai referensi.

(Ini membutuhkan API 16+, tapi saya menggunakan layar penuh hanya pada Lollipop + untuk menggambar di belakang bilah status jadi itu solusi terbaik dalam kasus ini.)

Hai Zhang
sumber
@Dilip Ini berfungsi pada API 16+, asalkan kondisi yang disebutkan di atas terpenuhi.
Hai Zhang
10

Harap dicatat bahwa android:windowSoftInputMode="adjustResize"tidak berfungsi ketika WindowManager.LayoutParams.FLAG_FULLSCREENdiatur untuk suatu kegiatan. Anda punya dua opsi.

  1. Nonaktifkan mode layar penuh untuk aktivitas Anda. Aktivitas tidak diukur ulang dalam mode layar penuh. Anda dapat melakukannya di xml (dengan mengubah tema aktivitas) atau dalam kode Java. Tambahkan baris berikut dalam metode onCreate () Anda.

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

ATAU

  1. Gunakan cara alternatif untuk mencapai mode layar penuh. Tambahkan kode berikut dalam metode onCreate () Anda.

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

Harap dicatat bahwa metode-2 hanya berfungsi di Android 4.1 dan di atasnya.

Abhinav Chauhan
sumber
Metode @AnshulTyagi-2 hanya berfungsi di Android 4.1 ke atas.
Abhinav Chauhan
4
Diuji pada 5.0 dan 4.4.2, Nexus 9 dan Samsung s4 masing-masing, metode ke-2 tidak berfungsi.
RobVoisey
1
Metode 2 sama sekali tidak bekerja dan saya membuang banyak waktu untuk itu.
Greg Ennis
Terima kasih, selamatkan hari saya.
Deni Rohimat
9

Saya harus menghadapi masalah ini juga dan memiliki pekerjaan yang saya periksa di HTC one, galaxy s1, s2, s3, note dan sensasi HTC.

letakkan pendengar tata letak global pada tampilan root tata letak Anda

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

dan di sana saya memeriksa perbedaan ketinggian dan jika perbedaan tinggi layar lebih besar maka sepertiga pada tinggi layar maka kita dapat menganggap keyboard terbuka. mengambilnya dari jawaban ini .

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

ini mungkin bukan bukti peluru dan mungkin pada beberapa perangkat itu tidak akan berfungsi tetapi itu bekerja untuk saya dan berharap itu akan membantu Anda juga.

yghm
sumber
1
Perlu beberapa penyesuaian, tetapi berhasil. Di Nexus 7 2013 saya harus mengurangi ketinggian keyboard (screenHeight / 3) beberapa piksel. Ide bagus, terima kasih!
Joao Sousa
7

Saya menerapkan solusi Joseph Johnson dan itu bekerja dengan baik, saya perhatikan setelah menggunakan solusi ini kadang-kadang laci pada aplikasi tidak akan menutup dengan benar. Saya menambahkan fungsionalitas untuk menghapus listener removeOnGlobalLayoutListener ketika pengguna menutup fragmen di mana edittexts berada.

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

menggunakan kelas di mana edittext saya berada

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

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

Tambahkan android:fitsSystemWindows="true"ke tata letak, dan tata letak ini akan mengubah ukuran.

zayn
sumber
Itulah yang memecahkannya untuk saya. Selain itu, pastikan Anda mengaturnya di tampilan yang benar. Jika Anda memiliki latar belakang yang seharusnya berada di bawah bilah status, jangan atur di sana, tetapi pada tata letak di dalamnya. Mungkin tampilan EditText dll harus di dalam tata letak kedua di dalam. Tonton juga ceramah ini, karena ini membuat semuanya lebih jelas: youtube.com/watch?v=_mGDMVRO3iE
Stan
Bekerja untuk saya juga. Berkat @Stan komentar saya juga bisa membuatnya bekerja dengan tema FULLSCREEN menempatkan atribut itu di ViewPager alih-alih tata letak aktivitas / fragmen.
marcouberti
5

Untuk membuatnya bekerja dengan Layar Penuh:

Gunakan plugin keyboard ionik. Ini memungkinkan Anda mendengarkan ketika keyboard muncul dan menghilang.

OnDeviceReady menambahkan pendengar acara ini:

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

Pada dasarnya, jika perbedaannya minus maka itu adalah jumlah piksel yang menutupi keyboard dari input Anda. Jadi, jika Anda menyesuaikan div orang tua Anda dengan ini yang harus menangkalnya.

Menambahkan batas waktu ke logika mengatakan 300ms juga harus mengoptimalkan kinerja (karena ini akan memungkinkan waktu keyboard muncul.

tyler_mitchell
sumber
3

Saya mencoba kelas Joseph Johnson, dan itu berhasil, tetapi tidak cukup memenuhi kebutuhan saya. Daripada meniru android: windowSoftInputMode = "adjustResize", saya perlu meniru android: windowSoftInputMode = "AdjustPan".

Saya menggunakan ini untuk tampilan web layar penuh. Untuk menggeser tampilan konten ke posisi yang benar, saya perlu menggunakan antarmuka javascript yang memberikan rincian tentang posisi elemen halaman yang memiliki fokus dan dengan demikian menerima input keyboard. Saya telah menghilangkan detail-detail itu, tetapi memberikan penulisan ulang saya tentang kelas Joseph Johnson. Ini akan memberikan dasar yang sangat kuat bagi Anda untuk mengimplementasikan pan kustom vs ukurannya.

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

}
Terima kasih
sumber
tampaknya apa yang saya butuhkan, bisakah Anda menambahkan sampel lengkap? terima kasih untuk pekerjaan kamu!
vilicvane
Saya tidak ingin memposting seluruh proyek. Apa yang saya berikan akan membawa Anda jauh ke arah solusi yang bekerja dengan sempurna. Apa yang perlu Anda definisikan sendiri: Buat kelas "JavaScriptObject" dan masukkan ke dalam tampilan web Anda sebagai antarmuka js (Lihat dokumentasi tampilan web untuk itu). Ada kemungkinan besar Anda sudah melakukannya jika menulis sesuatu yang menggunakan tampilan web secara komprehensif. Tambahkan JavaScript di tampilan web untuk mendengarkan acara fokus dan untuk memberi makan data ke kelas JavaScriptObject Anda tentang penentuan posisi elemen fokus.
BuvinJ
2

Memang penampilan keyboard yang lembut sepertinya tidak mempengaruhi Activityapa pun yang windowSoftInputModesaya pilih dalam FullScreenmode.

Meskipun saya tidak dapat menemukan banyak dokumentasi di properti ini, saya pikir FullScreenmode ini dirancang untuk aplikasi game yang tidak memerlukan banyak penggunaan keyboard lunak. Jika Anda adalah Aktivitas yang memerlukan interaksi pengguna melalui keyboard lunak, harap pertimbangkan kembali menggunakan tema non-Layar Penuh. Anda bisa mematikan TitleBar menggunakan NoTitleBartema. Mengapa Anda ingin menyembunyikan bilah notifikasi?

Arnab Chakraborty
sumber
2

Tetap seperti android:windowSoftInputMode="adjustResize". Karena itu diberikan untuk menjaga hanya satu dari "adjustResize"dan "adjustPan"(Mode penyesuaian jendela ditentukan dengan AdjustResize atau AdjustPan. Sangat disarankan agar Anda selalu menentukan satu atau yang lain). Anda dapat menemukannya di sini: http://developer.android.com/resources/articles/on-screen-inputs.html

Ini bekerja dengan baik untuk saya.

Balaji Khadake
sumber
Saya tidak mendapatkan masalah ... Saya telah mencoba XML Anda juga. Yang ini juga berfungsi..m menggunakan Os versi 2.2
Balaji Khadake
Saya telah mencoba dengan mode layar penuh saja ... sedang mengujinya pada Nexus One dan Nexus S saya .... Berhasil.
Balaji Khadake
1
Saya sudah mencoba dengan Galaxy S, HTC wildfire, HTC Hero, Motorola Deify dan Sony XPeria. Tidak berfungsi di satu perangkat.
Vineet Shukla
mari kita lanjutkan diskusi ini dalam obrolan
Balaji Khadake
2

Saat ini saya menggunakan pendekatan ini dan itu berfungsi seperti pesona. Caranya adalah kita mendapatkan ketinggian keyboard dari metode yang berbeda pada 21 di atas dan di bawah dan kemudian menggunakannya sebagai padding bawah dari tampilan root kita dalam aktivitas kita. Saya berasumsi tata letak Anda tidak memerlukan bantalan atas (masuk di bawah bilah status) tetapi jika Anda melakukannya, beri tahu saya untuk memperbarui jawaban saya.

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

Jangan lupa untuk mengatasi tampilan root Anda dengan id:

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

Semoga ini bisa membantu seseorang.

Sdghasemi
sumber
1
Tidak bisa mengerti, mengapa jawaban ini masih belum di atas. Yang lain salah, flash, tapi yang ini brilian, terutama jika Anda punya 5+ api.
Anton Shkurenko
1

hanya gunakan android:windowSoftInputMode="adjustResize|stateHiddensaat Anda menggunakan AdjustPan maka itu menonaktifkan properti mengubah ukuran

Mohammed Azharuddin Shaikh
sumber
Saya telah menggunakannya juga .... tolong buat Anda melakukannya dalam mode layar penuh dan perangkat apa yang Anda uji?
Vineet Shukla
HTC NEXUS satu, ok saya harus menambahkan layar penuh
Mohammed Azharuddin Shaikh
dapatkah Anda menggunakan getWindow (). requestFeature (Window.FEATURE_NO_TITLE); onCreate () alih-alih menggunakan tema?
Mohammed Azharuddin Shaikh
10
kode di atas berfungsi dengan baik tanpa layar penuh tetapi menambahkan layar penuh baik dari xml atau dari kode ... Tidak berfungsi ... Baca pertanyaan dengan seksama.
Vineet Shukla
1

Saya menggunakan Joseph Johnson menciptakan kelas AndroidBug5497Workaround tetapi mendapatkan ruang hitam antara softkeyboard dan tampilan. Saya merujuk tautan ini Greg Ennis . Setelah melakukan beberapa perubahan di atas ini adalah kode kerja terakhir saya.

 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);
  }
 }
}
Venkat
sumber
1

berdasarkan https://stackoverflow.com/a/19494006/1815624 dan keinginan untuk mewujudkannya ...

ide yang diperbarui


menggabungkan jawaban dari

Kode yang relevan:

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

            }

Sumber Lengkap di https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java

ide lama

Buat nilai statis tinggi wadah sebelum membuka keyboard. Atur tinggi wadah berdasarkan usableHeightSansKeyboard - heightDifferencekapan keyboard dibuka dan atur kembali ke nilai yang disimpan saat ditutup.

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

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

    });

}

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

margin yang sama dapat ditambahkan jika diperlukan ...

Pertimbangan lain adalah menggunakan bantalan contoh ini dapat ditemukan di:

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

CrandellWS
sumber
1

1) Buat 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) Biarkan aktivitas Anda menjadi layar penuh:

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

3) Dengarkan perubahan ketinggian keyboard dan tambahkan padding bawah untuk tampilan Anda:

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

Jadi , setiap kali keyboard akan muncul di layar - padding bawah untuk tampilan Anda akan berubah, dan konten akan disusun ulang.

repitch
sumber
0

Anda ingin bilah bawah menempel di bagian bawah tampilan, tetapi ketika keyboard ditampilkan, mereka harus bergerak ke atas untuk ditempatkan di atas keyboard, kan?

Anda dapat mencoba cuplikan kode ini:

<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 akan menempel di bagian bawah tampilan dan LinearLayout yang berisi ScrollView akan mengambil apa yang tersisa dari tampilan setelah bilah atas / bawah dan keyboard ditampilkan. Beri tahu saya jika itu bekerja untuk Anda juga.

banzai86
sumber
1
Sangat aneh karena berfungsi di aplikasi saya beberapa kali. Omong-omong, RelativeLayout tidak memiliki orientasi sehingga Anda dapat menghapus atribut ini dalam kode Anda. Saya baru saja mengenali bahwa saya dapat mengurangi potongan kode ke baris: android: layout_below = "@ + id / scoringContainerView" yang harus Anda tambahkan ke ScrollView Anda
banzai86
Layar penuh? Apakah maksud Anda tanpa tata letak di bagian atas?
banzai86
tidak ..... Maksud saya tidak ada bilah status yang menunjukkan masa pakai baterai, konektivitas untuk perangkat, dll ....
Vineet Shukla
tidak, bilah status terlihat di aplikasi saya. dapatkah Anda mencoba mengubah urutan tata letak Anda, artinya Anda meletakkan kode tata letak Anda dengan tombol di atas kode lainnya dan kemudian coba lagi? mungkin Anda harus mendefinisikannya terlebih dahulu untuk menggunakan layout_below
banzai86
1
tolong baca pertanyaan dengan seksama ...... Saya telah menyebutkan saya mengalami masalah dengan mode Layar Penuh ......
Vineet Shukla
0

Terima kasih, Joseph atas jawaban Anda. Namun, dalam metode maybeResizeChildOfContent (), porsinya

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

tidak berfungsi untuk saya, karena bagian bawah dari pandangan menjadi tersembunyi. Jadi saya harus mengambil variabel global restoreHeight, dan di konstruktor, saya memasukkan baris terakhir

restoreHeight = frameLayoutParams.height;

dan kemudian saya mengganti bagian yang disebutkan sebelumnya dengan

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

Tetapi saya tidak tahu mengapa kode Anda tidak bekerja untuk saya. Akan sangat membantu, jika seseorang dapat menjelaskan hal ini.

Debanjan
sumber
0

Saya hanya menggunakan mode layar penuh untuk menyembunyikan bilah status. Namun, saya ingin aplikasi untuk mengubah ukuran ketika keyboard ditampilkan. Semua solusi lain (kemungkinan karena usia posting) rumit atau tidak mungkin untuk saya gunakan (ingin menghindari perubahan kode Java untuk karung PhoneGap Build).

Alih-alih menggunakan layar Penuh, saya mengubah konfigurasi saya untuk Android menjadi non-layar penuh:

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

Dan menambahkan cordova-plugin-statusbar, melalui baris perintah:

cordova plugin add cordova-plugin-statusbar

Ketika aplikasi telah dimuat, saya memanggil metode sederhana pada plugin untuk menyembunyikan dirinya, seperti:

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

Ini bekerja seperti pesona. Satunya downside nyata adalah bahwa bilah status terlihat sangat singkat saat aplikasi memuat. Untuk kebutuhan saya, itu bukan masalah.

raider33
sumber
0

Saya telah mencoba semua jawaban yang mungkin dari stackOverflow, akhirnya saya menyelesaikannya setelah seminggu pencarian panjang. Saya telah menggunakan tata letak koordinat dan saya mengubahnya dengan linearLayout dan masalah saya sudah diperbaiki. Saya tidak tahu mungkin tata letak koordinat memiliki bug atau kesalahan saya.

poudel yubaraj
sumber
0

Saya mencoba banyak solusi termasuk Joseph Johnson dan Johan Stuyts's. Tetapi sebagai hasilnya saya mendapat ruang putih antara konten dan keyboard pada beberapa perangkat (seperti Lenovo s820) dalam semua kasus. Jadi saya membuat beberapa perubahan pada kode mereka dan akhirnya mendapatkan solusi yang berfungsi.

Ide saya didasarkan pada penambahan margin ke atas konten saat keyboard ditampilkan.

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

Seperti yang Anda lihat, saya menambahkan 30 px ke perbedaan karena ada ruang putih kecil antara bagian atas layar dan zona konten dengan margin. Dan saya tidak tahu dari mana itu muncul jadi saya memutuskan untuk membuat margin lebih kecil dan sekarang berfungsi persis seperti yang saya butuhkan.

IDmikael
sumber
0

Hari ini tidak berfungsi adjustResize pada masalah layar penuh sebenarnya untuk sdk android.

Dari jawaban yang saya temukan:
solusinya - tetapi solusinya ada pada masalah gambar:

Daripada saya menemukan solusi dan menghapus satu tindakan yang tidak perlu:

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

Jadi, lihat kode solusi tetap saya di 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
        }
    }
}

Kode implementasi perbaikan bug saya:

 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()
    }
}
Serg Burlaka
sumber
0

Jangan gunakan:

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

karena bekerja buruk. Alih-alih itu, gunakan:

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)
    }
Alberto
sumber
-1

Dalam kasus saya, masalah ini mulai terjadi setelah saya menambahkan Crosswalk ke aplikasi Cordova saya. Aplikasi saya tidak digunakan dalam layar penuh dan android: windowSoftInputMode = "AdjustPan".

Saya sudah memiliki plugin keyboard ionik dalam aplikasi, jadi mendeteksi apakah keyboard naik atau turun mudah berkat itu:

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

Saya mencoba semua perbaikan di atas tetapi baris sederhana yang akhirnya melakukannya untuk saya adalah css ini:

&.keyboardUp {
        overflow-y: scroll;
}

Semoga ini menyelamatkan Anda beberapa hari saya habiskan untuk ini. :)

JR
sumber
Saya menggunakan crosswalk dengan cordova juga dengan android: windowSoftInputMode = "AdjustPan". Namun, itu tidak berfungsi. Saya melihat bahwa kelas semakin ditambahkan ke elemen html, tetapi css tidak memiliki efek pada layar. Apakah ada pengaturan lain yang Anda miliki yang memungkinkan layar bergerak?
darewreck
Saya harus mengatur add transform: translateY (0px) agar bisa berfungsi. Namun, bergulirnya tidak berfungsi sama sekali. Ada ide?
darewreck