Android Cách điều chỉnh bố cục ở Chế độ toàn màn hình khi hiển thị bảng phím mềm


178

Tôi đã nghiên cứu rất nhiều để điều chỉnh bố cục khi phím chức năng đang hoạt động và tôi đã thực hiện thành công nhưng vấn đề xảy ra khi tôi sử dụng android:theme="@android:style/Theme.NoTitleBar.Fullscreen"điều này trong thẻ hoạt động của mình trong tệp kê khai.

Đối với điều này, tôi đã sử dụng android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"với các tùy chọn khác nhau nhưng không có may mắn.

Sau đó, tôi đã thực hiện theo FullScreenchương trình và thử bố trí khác nhau để làm việc FullScreennhưng tất cả đều vô ích.

Tôi đã giới thiệu các liên kết này và đã xem nhiều bài viết ở đây liên quan đến vấn đề này:

http://android-developers.blogspot.com/2009/04/updating-appluggest-for-on-screen.html

http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/

Đây là mã 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>

nhập mô tả hình ảnh ở đây

Tôi muốn 2 nút dưới cùng sẽ đi lên khi bảng phím mềm xuất hiện.

nhập mô tả hình ảnh ở đây


1
Tôi nghĩ bạn phải thêm các Nút bên trong ScrollView và bên dưới EditText.
Balaji Khadake

Tôi đã thử nhiều tùy chọn không hoạt động ...
Vineet Shukla

1
đặt các nút của bạn trong một framelayout và đặt trọng lượng của framelayout là 1 và cuối cùng chỉ sử dụng android:windowSoftInputMode="adjustPan"cho tôi biết nếu công việc này ..
Sherif elKhatib

@VineetShukla bạn đã tìm thấy bất kỳ công việc nào với toàn màn hình ??
Muhammad Babar

2
Lưu ý rằng bạn không nên sử dụng adjustResizeadjustPanđồng thời, từ javadoc của android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE: "Không thể kết hợp với {@link SOFT_INPUT_ADJUST_PAN}"
Denis Kniazhev

Câu trả lời:


257

Dựa trên cách giải quyết của yghm, tôi đã mã hóa một lớp tiện lợi cho phép tôi giải quyết vấn đề bằng một lớp lót (sau khi thêm lớp mới vào mã nguồn của khóa học). Một lớp lót là:

     AndroidBug5497Workaround.assistActivity(this);

Và lớp thực hiện là:


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

Hy vọng điều này sẽ giúp được ai đó.


8
Cảm ơn! Tôi không biết tại sao, nhưng tôi đã phải thay thế return (r.bottom - r.top); bằng return r.bottomđể có được nó hoạt động trên HTC của tôi Một Mini, nếu không thì xem hoạt động sẽ được đẩy quá cao bởi kích thước của thanh trạng thái. Tôi chưa thử nó trên một thiết bị khác. Hy vọng rằng có thể giúp đỡ.
Joan

4
Xin chào Joseph johnson, tôi đã sử dụng mã của bạn và nó hoạt động hoàn hảo. Nhưng ngày nay phải đối mặt với một vấn đề trên một số thiết bị nhỏ mà nó cho thấy khoảng cách (màn hình trống) giữa bàn phím và bố cục. Bạn có ý kiến ​​gì về vấn đề này không? Tôi cũng đã thử trả lại r.bottom.
Pankaj

2
Joseph Johnson: Tôi đã triển khai phương pháp của bạn, nó hoạt động tốt khi chúng tôi nhấp vào văn bản chỉnh sửa hàng đầu nhưng khi chúng tôi nhấp vào edittext dưới cùng, tất cả thiết kế sẽ tăng lên
ranjith

3
Thật không may, nó không hoạt động trên Nexus 7 (2013). Nó vẫn chảo ngay cả với bộ điều chỉnh.
Le-roy Staines

4
Câu trả lời tuyệt vời, cảm ơn bạn rất nhiều. Nó hoạt động trên Nexus 6 nhưng thay vì sử dụng frameLayoutParams.height = usableHeightSansKeyboard;tôi phải sử dụng frameLayoutParams.height = usableHeightNow; Nếu tôi không, một số yếu tố nằm ngoài màn hình.
RobertoAllende

36

Vì câu trả lời đã được chọn và vấn đề được biết là một lỗi, tôi nghĩ rằng tôi sẽ thêm một "Công việc có thể xảy ra".

Bạn có thể chuyển chế độ fullScreen khi bàn phím mềm được hiển thị. Điều này cho phép "điều chỉnh" hoạt động chính xác.

Nói cách khác, tôi vẫn sử dụng @android: style / Theme.Black.NoTitleBar.Fullscreen như một phần của chủ đề ứng dụng và stateVisible | điều chỉnh Kích thước như một phần của chế độ nhập mềm của cửa sổ hoạt động nhưng để chúng hoạt động cùng nhau, tôi phải chuyển chế độ toàn màn hình trước khi bàn phím xuất hiện.

Sử dụng mã sau đây:

Tắt chế độ toàn màn hình

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

Bật chế độ toàn màn hình

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

Lưu ý - nguồn cảm hứng đến từ: Ẩn tiêu đề ở chế độ Toàn màn hình


1
Tôi đánh giá cao rằng bạn đã dành thời gian cho vấn đề, +1 cho điều đó. Tôi chắc chắn sẽ kiểm tra phương pháp này và cho bạn biết sớm nếu nó hiệu quả với tôi, cảm ơn.
Vineet Shukla

1
Đang làm việc như nghi ngờ! Giải pháp thực sự tốt! +1 từ phía tôi.
Mike


1
bàn phím bật, làm cho nền bàn phím màu đen. Hiệu ứng chụp nhanh trông không được tốt :(
nibz 6/12/17

wow nhờ ... nó làm việc cho tôi thực sự tốt bằng cách kết hợp Giải pháp được đề cập bởi AndroidBug5497Workaround ... Tôi đã tải lên nguồn kết hợp với GitHub ... github.com/CrandellWS/AndroidBug5497Workaround/blob/master/...
CrandellWS

23

Tôi đã thử giải pháp từ Joseph Johnson , nhưng giống như những người khác, tôi gặp phải vấn đề khoảng cách giữa nội dung và bàn phím. Sự cố xảy ra do chế độ nhập mềm luôn xoay khi sử dụng chế độ toàn màn hình. Panning này can thiệp vào giải pháp của Joseph khi bạn kích hoạt trường đầu vào bị ẩn bởi đầu vào mềm.

Khi đầu vào mềm xuất hiện, nội dung đầu tiên được lát dựa trên chiều cao ban đầu của nó, sau đó thay đổi kích thước theo bố cục được yêu cầu bởi giải pháp của Joseph. Việc thay đổi kích thước và bố trí tiếp theo không hoàn tác panning, dẫn đến khoảng cách. Thứ tự đầy đủ của các sự kiện là:

  1. Người nghe bố trí toàn cầu
  2. Panning
  3. Bố cục nội dung (= thay đổi kích thước thực tế của nội dung)

Không thể vô hiệu hóa panning, nhưng có thể buộc pan offset bằng 0 bằng cách thay đổi chiều cao của nội dung. Điều này có thể được thực hiện trong người nghe, bởi vì nó được chạy trước khi panning diễn ra. Đặt chiều cao nội dung thành chiều cao có sẵn sẽ mang lại trải nghiệm mượt mà cho người dùng, tức là không nhấp nháy.

Tôi cũng đã thực hiện những thay đổi này. Nếu bất kỳ vấn đề nào trong số này giới thiệu, hãy cho tôi biết:

  • Chuyển đổi xác định chiều cao có sẵn để sử dụng getWindowVisibleDisplayFrame. Các Rectbộ nhớ đệm để ngăn chặn một chút rác không cần thiết.
  • Cho phép người nghe được loại bỏ quá. Điều này hữu ích khi bạn sử dụng lại một hoạt động cho các đoạn khác nhau có các yêu cầu toàn màn hình khác nhau.
  • Không phân biệt giữa bàn phím được hiển thị hoặc ẩn, nhưng luôn đặt chiều cao nội dung thành chiều cao khung hiển thị có thể nhìn thấy.

Nó đã được thử nghiệm trên Nexus 5 và trình giả lập chạy các cấp API 16-24 với kích thước màn hình từ nhỏ đến lớn.

Mã này đã được chuyển sang Kotlin, nhưng chuyển các thay đổi của tôi trở lại Java rất đơn giản. Hãy cho tôi biết nếu bạn cần sự giúp đỡ:

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
Đây dường như là câu trả lời tốt nhất. Tôi đã chuyển sang java ở đây gist.github.com/grennis/2e3cd5f7a9238c59861015ce0a7c5584 . Lưu ý rằng tôi đã nhận được ngoại lệ rằng người quan sát không còn sống và cũng phải kiểm tra điều đó.
Greg Enni

Ôi chúa ơi! đã đi qua tất cả hệ thống phân cấp lượt xem hệ thống đang tìm kiếm không gian Ghost đó. Tôi đã gần máy tính mương cho một chiếc xe tải thực phẩm nhưng đã thấy câu trả lời của bạn trong phút cuối. Nó hoạt động :)
rupps 16/03/18

1
@Greg Enni Cảm ơn cổng Java. Tiết kiệm rất nhiều nỗ lực và thời gian.
Ikun

@GregEnnis, cảm ơn, giải pháp của bạn hoạt động với onResume (), onPause (), onDestroy () (xem bình luận trong mã GitHub).
CoolMind

Điều này đang làm việc với tôi, ngoại trừ cuộc gọi removeListener dường như không hoạt động. Tôi đặt các điểm dừng bên trong cả possiblyResizeChildOfContentcuộc gọi và removeListenercuộc gọi, và thậm chí sau khi tôi nhấn removeListenerđiểm dừng, possiblyResizeChildOfContentvẫn đang được gọi. Bất cứ ai khác có vấn đề này?
Quinn

14

Tôi chỉ tìm thấy một giải pháp đơn giản và đáng tin cậy nếu bạn đang sử dụng phương pháp UI hệ thống ( https://developer.android.com/training/system-ui/immersive.html ).

Nó hoạt động trong trường hợp khi bạn đang sử dụng View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, ví dụ nếu bạn đang sử dụng CoordinatorLayout.

Nó không hoạt động cho WindowManager.LayoutParams.FLAG_FULLSCREEN(Cái bạn cũng có thể đặt trong chủ đề android:windowFullscreen), nhưng bạn có thể đạt được hiệu ứng tương tự với SYSTEM_UI_FLAG_LAYOUT_STABLE(cái "có cùng hiệu ứng hình ảnh" theo tài liệu ) và giải pháp này sẽ hoạt động trở lại.

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)

Tôi đã thử nghiệm nó trên thiết bị của tôi chạy Marshmallow.

Điều quan trọng là bàn phím mềm cũng là một trong những cửa sổ hệ thống (như thanh trạng thái và thanh điều hướng), do đó, WindowInsetshệ thống được gửi đi chứa thông tin chính xác và đáng tin cậy về nó.

Đối với trường hợp sử dụng, chẳng hạn như ở DrawerLayoutnơi chúng tôi đang cố gắng vẽ phía sau thanh trạng thái, Chúng tôi có thể tạo bố cục chỉ bỏ qua phần trên cùng và áp dụng phần dưới cùng chiếm phần mềm cho bàn phím mềm.

Đây là tùy chỉnh của tôi 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);
        }
    }
}

Và để sử dụng nó:

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

Về mặt lý thuyết, nó sẽ hoạt động cho bất kỳ thiết bị nào mà không cần sửa đổi điên rồ, tốt hơn nhiều so với bất kỳ hack nào cố lấy ngẫu nhiên 1/3hoặc 1/4kích thước màn hình làm tham chiếu.

(Nó yêu cầu API 16+, nhưng tôi chỉ sử dụng toàn màn hình trên Lollipop + để vẽ phía sau thanh trạng thái để nó là giải pháp tốt nhất trong trường hợp này.)


@Dilip Nó hoạt động trên API 16+, miễn là các điều kiện nói trên được đáp ứng.
Hai Zhang

10

Xin lưu ý rằng android:windowSoftInputMode="adjustResize"nó không hoạt động khi WindowManager.LayoutParams.FLAG_FULLSCREENđược đặt cho một hoạt động. Bạn có hai lựa chọn.

  1. Vô hiệu hóa chế độ toàn màn hình cho hoạt động của bạn. Hoạt động không được kích thước lại trong chế độ toàn màn hình. Bạn có thể làm điều này bằng xml (bằng cách thay đổi chủ đề của hoạt động) hoặc bằng mã Java. Thêm các dòng sau trong phương thức onCreate () của bạn.

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

HOẶC LÀ

  1. Sử dụng một cách khác để đạt được chế độ toàn màn hình. Thêm mã sau vào phương thức onCreate () của bạn.

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

Xin lưu ý rằng phương thức-2 chỉ hoạt động trong Android 4.1 trở lên.


@AnshulTyagi phương thức-2 chỉ hoạt động trong Android 4.1 trở lên.
Abhinav Chauhan

4
Đã thử nghiệm trên 5.0 và 4.4.2, Nexus 9 và Samsung s4, phương pháp thứ 2 không hoạt động.
RobVoisey

1
Phương pháp thứ 2 đơn giản là không hiệu quả và tôi đã lãng phí rất nhiều thời gian cho nó.
Greg Enni

Cảm ơn bạn, tiết kiệm ngày của tôi.
Deni Rohimat

9

Tôi cũng đã phải đối mặt với vấn đề này và đã có một công việc mà tôi đã kiểm tra trên HTC one, galaxy s1, s2, s3, note và HTC Sensation.

đặt một trình lắng nghe bố cục toàn cầu trên giao diện gốc của bố cục của bạn

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

và trong đó tôi đã kiểm tra chênh lệch chiều cao và nếu chênh lệch chiều cao của màn hình lớn hơn một phần ba chiều cao màn hình thì chúng ta có thể giả sử bàn phím đang mở. lấy nó từ câu trả lời này .

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

đây có thể không phải là bằng chứng đạn và có thể trên một số thiết bị, nó sẽ không hoạt động nhưng nó hoạt động với tôi và hy vọng nó cũng sẽ giúp bạn.


1
Cần một số điều chỉnh, nhưng nó đã làm việc. Trong Nexus 7 2013, tôi đã phải giảm chiều cao bàn phím (screenHeight / 3) xuống một số pixel. Ý kiến ​​hay, cảm ơn!
Joao Sousa

7

Tôi đã triển khai giải pháp Joseph Johnson và nó hoạt động tốt, tôi nhận thấy sau khi sử dụng giải pháp này đôi khi ngăn kéo trên ứng dụng sẽ không đóng đúng cách. Tôi đã thêm một chức năng để loại bỏ trình nghe removeOnGlobalLayoutListener khi người dùng đóng đoạn có vị trí 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);
    } 
}

sử dụng lớp mà edittexts của tôi nằm ở đâu

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

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

7

Thêm android:fitsSystemWindows="true"vào bố cục, và bố cục này sẽ thay đổi kích thước.


Đó là những gì đã giải quyết nó cho tôi. Ngoài suy nghĩ, hãy chắc chắn rằng bạn đặt nó ở chế độ xem đúng. Nếu bạn có một nền tảng bên dưới thanh trạng thái, đừng đặt nó ở đó, nhưng trên một bố cục bên trong. Có lẽ các khung nhìn EditText, v.v. nên nằm trong bố cục thứ hai bên trong. Đồng thời xem cuộc nói chuyện này, vì nó làm cho mọi thứ rõ ràng hơn: youtube.com/watch?v=_mGDMVRO3iE
Stan

Làm việc cho tôi là tốt. Nhờ bình luận @Stan, tôi cũng có thể làm cho nó hoạt động với chủ đề FULLSCREEN đặt thuộc tính đó trên ViewPager thay vì bố cục hoạt động / phân đoạn.
marcouberti

5

Để làm cho nó hoạt động với FullScreen:

Sử dụng plugin bàn phím ion. Điều này cho phép bạn nghe khi bàn phím xuất hiện và biến mất.

OnDeviceReady thêm những người nghe sự kiện này:

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

Hợp lý:

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

Về cơ bản nếu sự khác biệt của chúng là âm thì đó là lượng pixel mà bàn phím đang che mất đầu vào của bạn. Vì vậy, nếu bạn điều chỉnh div cha mẹ của bạn bằng cách này sẽ chống lại nó.

Thêm thời gian chờ vào logic cho biết 300ms cũng sẽ tối ưu hóa hiệu suất (vì điều này sẽ cho phép thời gian bàn phím xuất hiện.


3

Tôi đã thử lớp của Joseph Johnson, và nó đã hoạt động, nhưng không đáp ứng đủ nhu cầu của tôi. Thay vì giả lập android: windowSoftInputMode = "điều chỉnh kích thước", tôi cần phải mô phỏng android: windowSoftInputMode = "điều chỉnhPan".

Tôi đang sử dụng điều này cho một webview toàn màn hình. Để xoay chế độ xem nội dung đến đúng vị trí, tôi cần sử dụng giao diện javascript cung cấp chi tiết về vị trí của thành phần trang có tiêu điểm và do đó sẽ nhận được đầu vào bàn phím. Tôi đã bỏ qua những chi tiết đó, nhưng cung cấp bản viết lại của tôi về lớp của Joseph Johnson. Nó sẽ cung cấp một cơ sở rất vững chắc để bạn thực hiện một chảo tùy chỉnh so với thay đổi kích thước của anh ấy.

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

}

dường như là những gì tôi cần, bạn có thể vui lòng thêm một mẫu hoàn chỉnh không? Cám ơn việc làm của bạn!
vilicvane

Tôi đã không muốn đăng toàn bộ dự án. Những gì tôi đã cung cấp sẽ mang lại cho bạn một chặng đường rất dài mặc dù hướng tới một giải pháp hoàn hảo. Những gì bạn cần xác định chính mình: Tạo một lớp "JavaScriptObject" và đưa nó vào chế độ xem web của bạn dưới dạng giao diện js (Kiểm tra tài liệu về chế độ xem web để biết điều đó). Có một cơ hội tốt mà bạn đã thực hiện nếu viết một cái gì đó sử dụng webview một cách toàn diện. Thêm JavaScript trong chế độ xem web để lắng nghe các sự kiện trọng tâm và cung cấp dữ liệu vào lớp JavaScriptObject của bạn về định vị thành phần trọng tâm.
BuvinJ

2

Thật vậy, sự xuất hiện của bàn phím mềm dường như không ảnh hưởng đến Activitybất kỳ cách nào cho dù windowSoftInputModetôi chọn FullScreenchế độ nào.

Mặc dù tôi không thể tìm thấy nhiều tài liệu về tài sản này, tôi nghĩ rằng FullScreenchế độ này được thiết kế cho ứng dụng chơi game không yêu cầu sử dụng nhiều bàn phím mềm. Nếu hoạt động của bạn là Hoạt động yêu cầu tương tác người dùng thông qua bàn phím mềm, vui lòng xem xét lại bằng cách sử dụng chủ đề không phải FullScreen. Bạn có thể tắt TitleBar bằng một NoTitleBarchủ đề. Tại sao bạn muốn ẩn thanh thông báo?


2

Chỉ cần giữ như android:windowSoftInputMode="adjustResize". Bởi vì nó được đưa ra để chỉ giữ một trong số đó "adjustResize""adjustPan"(Chế độ điều chỉnh cửa sổ được chỉ định với điều chỉnhResize hoặc điều chỉnhPan. Rất khuyến khích bạn luôn chỉ định cái này hay cái khác). Bạn có thể tìm thấy nó ở đây: http://developer.android.com/resource/articles/on-screen-inputs.html

Nó hoạt động hoàn hảo cho tôi.


Tôi không gặp vấn đề gì cả ... Tôi cũng đã thử XML của bạn. Cái này cũng hoạt động..m sử dụng Os phiên bản 2.2
Balaji Khadake

Tôi đã thử với chế độ toàn màn hình chỉ ... tôi đang thử nghiệm nó trên Nexus One và Nexus S của tôi .... Nó hoạt động.
Balaji Khadake

1
Tôi đã thử với Galaxy S, HTC wildfire, HTC Hero, Motorola Deify và Sony XPeria. Không hoạt động trên bất kỳ thiết bị duy nhất.
Vineet Shukla


2

Tôi hiện đang sử dụng phương pháp này và nó hoạt động như một sự quyến rũ. Mẹo nhỏ là chúng ta lấy chiều cao bàn phím từ các phương thức khác nhau ở 21 trên và dưới và sau đó sử dụng nó làm phần đệm dưới cùng của chế độ xem gốc trong hoạt động của chúng ta. Tôi giả sử bố cục của bạn không cần phần đệm trên cùng (bên dưới thanh trạng thái) nhưng trong trường hợp bạn làm như vậy, hãy thông báo cho tôi để cập nhật câu trả lời của tôi.

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

Đừng quên giải quyết chế độ xem gốc của bạn bằng 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">

Hy vọng nó sẽ giúp được ai đó.


1
Không thể hiểu, tại sao câu trả lời này vẫn không nằm trong top. Đó là những người khác trục trặc, flash, nhưng điều này là tuyệt vời, đặc biệt là nếu bạn có 5+ api.
Anton Shkurenko

1

Chỉ sử dụng android:windowSoftInputMode="adjustResize|stateHiddenkhi bạn sử dụng Điều chỉnh, sau đó nó vô hiệu hóa thuộc tính thay đổi kích thước


Tôi cũng đã sử dụng nó .... vui lòng làm cho bạn đang thực hiện nó ở chế độ toàn màn hình và bạn đang thử nghiệm trên thiết bị nào?
Vineet Shukla

HTC NEXUS one, ok i hvnt thêm toàn màn hình
Mohammed Azharuddin Shaikh

bạn có thể sử dụng getWindow (). requestFeature (Window.FEATURE_NO_TITLE); onCreate () thay vì sử dụng theme?
Mohammed Azharuddin Shaikh

10
đoạn mã trên hoạt động tốt mà không cần toàn màn hình nhưng thêm toàn màn hình từ xml hoặc từ mã ... Nó không hoạt động ... Vui lòng đọc kỹ câu hỏi.
Vineet Shukla

1

Tôi đã sử dụng Joseph Johnson đã tạo lớp AndroidBug5497Workaround nhưng nhận được khoảng trắng giữa bảng phím mềm và chế độ xem. Tôi đã giới thiệu liên kết này Greg Ennis . Sau khi thực hiện một số thay đổi ở trên, đây là mã làm việc cuối cùng của tôi.

 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

dựa trên https://stackoverflow.com/a/19494006/1815624 và mong muốn biến nó thành hiện thực ...

cập nhật ý tưởng


kết hợp câu trả lời từ

Mã liên quan:

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

            }

Nguồn đầy đủ tại https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java

ý tưởng cũ

Tạo giá trị tĩnh của chiều cao vùng chứa trước khi mở bàn phím Đặt chiều cao vùng chứa dựa trên usableHeightSansKeyboard - heightDifferencethời điểm bàn phím mở và đặt lại về giá trị đã lưu khi đóng

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

Các phương thức trong 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);
        }

    });

}

Ví dụ về XML Container

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

lợi nhuận tương tự có thể được thêm vào nếu cần ...

Một xem xét khác là sử dụng phần đệm một ví dụ về điều này có thể được tìm thấy tại:

https://github.com/mikepenz/M vật liệuDrawer/issues/95#issuecomment-80519589


1

1) Tạo Bàn phímHeightHelper:

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) Hãy để hoạt động của bạn ở chế độ toàn màn hình:

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

3) Lắng nghe thay đổi chiều cao bàn phím và thêm phần đệm phía dưới cho chế độ xem của bạn:

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

Vì thế , mỗi lần bàn phím sẽ xuất hiện trên màn hình - phần đệm phía dưới cho chế độ xem của bạn sẽ thay đổi và nội dung sẽ được sắp xếp lại.


0

Bạn muốn thanh dưới cùng dính vào dưới cùng của chế độ xem, nhưng khi bàn phím được hiển thị, chúng sẽ di chuyển lên để được đặt phía trên bàn phím, phải không?

Bạn có thể thử đoạn mã này:

<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 sẽ bám vào phần dưới của chế độ xem và linearLayout chứa ScrollView sẽ lấy những gì còn lại của chế độ xem sau khi thanh trên cùng / dưới cùng và bàn phím được hiển thị. Hãy cho tôi biết nếu nó làm việc cho bạn là tốt.


1
Rất lạ vì nó hoạt động trong ứng dụng của tôi nhiều lần. Nhân tiện, RelativeLayout không có định hướng để bạn có thể xóa các thuộc tính này trong mã của mình. Tôi chỉ nhận ra rằng tôi có thể cắt đoạn mã xuống dòng: android: layout_below = "@ + id / pointsContainerView" mà bạn phải thêm vào ScrollView của mình
banzai86

Toàn màn hình? Bạn có nghĩa là không có bố trí ở đầu?
banzai86

không ..... Ý tôi là không có thanh trạng thái nào hiển thị thời lượng pin, khả năng kết nối cho thiết bị, v.v ....
Vineet Shukla

không, thanh trạng thái hiển thị trong ứng dụng của tôi. bạn có thể thử thay đổi thứ tự bố trí của mình không, nghĩa là bạn đặt mã cho bố cục của mình bằng các nút phía trên mã khác rồi thử lại? có lẽ bạn phải xác định chúng trước để sử dụng layout_below
banzai86

1
vui lòng đọc kỹ câu hỏi ...... Tôi đã đề cập rằng tôi đang gặp sự cố với chế độ FullScreen ......
Vineet Shukla

0

Cảm ơn Joseph cho câu trả lời của bạn. Tuy nhiên, trong phương thức có thểResizeChildOfContent (), phần

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

đã không làm việc cho tôi, vì phần dưới của tầm nhìn bị ẩn đi. Vì vậy, tôi đã phải thực hiện khôi phục biến toàn cụcHeight và trong hàm tạo, tôi đã chèn dòng cuối cùng

restoreHeight = frameLayoutParams.height;

và sau đó tôi thay thế phần được đề cập trước đây bằng

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

Nhưng tôi không biết tại sao mã của bạn không hoạt động với tôi. Nó sẽ rất hữu ích, nếu ai đó có thể làm sáng tỏ điều này.


0

Tôi chỉ sử dụng chế độ toàn màn hình để ẩn thanh trạng thái. Tuy nhiên, tôi muốn ứng dụng thay đổi kích thước khi bàn phím được hiển thị. Tất cả các giải pháp khác (có thể do tuổi của bài đăng) đều phức tạp hoặc không thể sử dụng được cho tôi (muốn tránh thay đổi mã Java để sa thải PhoneGap Build).

Thay vì sử dụng Toàn màn hình, tôi đã sửa đổi cấu hình của mình thành Android thành không toàn màn hình:

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

Và thêm cordova-plugin-statusbar, thông qua dòng lệnh:

cordova plugin add cordova-plugin-statusbar

Khi ứng dụng đã được tải, tôi đơn giản gọi một phương thức trên plugin để ẩn chính nó, như:

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

Công việc này như một cái duyên vậy. Chỉ có nhược điểm thực sự là thanh trạng thái hiển thị rõ ràng trong khi tải ứng dụng. Đối với nhu cầu của tôi, đó không phải là một vấn đề.


0

Tôi đã thử tất cả các câu trả lời có thể có từ stackOverflow, cuối cùng tôi đã giải quyết sau một tuần Tìm kiếm dài. Tôi đã sử dụng bố trí tọa độ và tôi đã thay đổi điều này với linearLayout và vấn đề của tôi đã được khắc phục. Tôi không biết có thể bố trí tọa độ có lỗi hoặc bất cứ điều gì sai lầm của tôi.


0

Tôi đã thử nhiều giải pháp bao gồm của Joseph Johnson và Johan Stuyts. Nhưng kết quả là tôi đã có một khoảng trắng giữa nội dung và bàn phím trên một số thiết bị (như Lenovo s820) trong mọi trường hợp. Vì vậy, tôi đã thực hiện một số thay đổi cho mã của họ và cuối cùng đã có giải pháp làm việc.

Ý tưởng của tôi dựa trên việc thêm lề vào đầu nội dung khi bàn phím được hiển thị.

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

Như bạn có thể thấy, tôi thêm 30 px vào sự khác biệt bởi vì có một khoảng trắng nhỏ giữa đỉnh màn hình và vùng nội dung có lề. Và tôi không biết nó xuất hiện từ đâu nên tôi quyết định chỉ làm cho lợi nhuận nhỏ hơn và bây giờ nó hoạt động chính xác như tôi cần.


0

Hôm nay không hoạt động điều chỉnhResize trên toàn màn hình vấn đề là thực tế cho sdk android.

Từ câu trả lời tôi tìm thấy:
giải pháp - nhưng giải pháp có điều này thể hiện trên vấn đề hình ảnh:

Hơn tôi tìm thấy giải pháp và loại bỏ một hành động không cần thiết:

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

Vì vậy, hãy xem mã giải pháp cố định của tôi trên 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ã triển khai sửa lỗi của tôi:

 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

Đừng sử dụng:

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

vì làm việc xấu Thay vào đó, sử dụng:

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

Trong trường hợp của tôi, vấn đề này bắt đầu xảy ra khi tôi thêm Crosswalk vào ứng dụng Cordova của mình. Ứng dụng của tôi không được sử dụng trong toàn màn hình và android: windowSoftInputMode = "điều chỉnhPan".

Tôi đã có plugin bàn phím ion trong ứng dụng, vì vậy việc phát hiện xem bàn phím lên hay xuống rất dễ dàng nhờ vào nó:

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

Tôi đã thử tất cả các bản sửa lỗi ở trên nhưng dòng đơn giản cuối cùng đã làm cho tôi là một chút của css:

&.keyboardUp {
        overflow-y: scroll;
}

Hy vọng điều này sẽ giúp bạn tiết kiệm trong vài ngày tôi dành cho việc này. :)


Tôi cũng đang sử dụng crosswalk với cordova với android: windowSoftInputMode = "điều chỉnhPan". Tuy nhiên, nó không hoạt động. Tôi thấy rằng lớp đang được thêm vào phần tử html, nhưng css không có hiệu lực trên màn hình. Có một số cài đặt khác mà bạn có cho phép màn hình di chuyển không?
darewreck

Tôi phải đặt biến đổi add: translateY (0px) để nó hoạt động. Tuy nhiên, cuộn không hoạt động gì cả. Có ý kiến ​​gì không?
con yêu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.