天天看點

android 彈出軟鍵盤覆寫了popupwindow的終極解決辦法

在經過幾年的經驗累積之後,我終于決定整理一下曾經遇到的各種問題,給各位走在Android開發路上的朋友一點幫助,更多相關問題,請通路我的部落格:http://blog.csdn.net/xiaoliluote 如果您對該問題有更多的解決方式,請留言,驗證之後我會編輯部落格

寫之前,我想先吐槽一下,各大網站真的是垃圾水友多,一個人這麼寫,其它人就無腦抄,抄過去的好歹也自己試試效果啊,浪費大家的時間.

比如這樣子的:

popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
           

您老在複制這段代碼釋出到自己的部落格之前,能不能去試試? popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED); 這行代碼雖然不會導緻編譯失敗,但是它下面畫着紅色波浪線的,您眼瞎看不到嗎? 正确的寫法是setInputMethodMode,而不是setSoftInputMode.

筆者遇到的場景是:在Activity中點選購買,會從底部彈出PopupWindow,然後在該PopupWindow中有個EditText允許使用者自行輸入購買數量,此時彈出的軟鍵盤,會覆寫掉popupWindow的内容,體驗效果就很糟糕了.

在注冊檔案中設定android:windowSoftInputMode="adjustResize" 是沒有用的,它隻有在Activity的EditText裡面才有用,這裡是在PopupWindow裡面.

好,吐槽完畢,下面說方案

1.上面的方案,放在popupWindow的show方法之前,在部分手機是有效的,也就是這樣子用:

View view = LayoutInflater.from(this).inflate(R.layout.view_pop, null);  
        popview = new PopupWindow(view,  
                android.view.ViewGroup.LayoutParams.MATCH_PARENT,  
                LayoutParams.WRAP_CONTENT, true);  
        popview.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));  
        popview.setFocusable(true);  
        // 設定點選其他地方就消失  
        popview.setOutsideTouchable(true);  
        popview.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);  
        popview.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);  
        popview.showAtLocation(ll_all, Gravity.BOTTOM  
                | Gravity.CENTER_VERTICAL, 0, 0); 
           

2.筆者在親測中發現,手裡的一款樂視手機沒得用,軟體盤還是覆寫了PopupWindow的内容,如果您在測試中也遇到了該問題,那麼用下面這個方案吧,應該是可以解決所有手機的問題.

這裡借鑒了該網友的部分代碼,附上連結,尊重别人的勞動成果:https://www.jianshu.com/p/9bba256f261f

但該網友的辦法,在使用時,發現第一次彈出軟鍵盤無效,原因是第一次彈出軟鍵盤的時候,沒有測量視圖的高度,是以沒有進入到軟鍵盤彈出的監聽方法,這裡貼出修改過後的完整源代碼:

import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;

/**
 * Created by KillaXiao on 2019/8/14.
 * 監聽軟鍵盤的彈出與收起, 在部分手機測試到,popupwindow裡面有edittext的時候,彈出軟鍵盤,會覆寫掉從底部彈出的popupwindow内容
 */
public class SoftKeyBoardListener {
    private View rootView;  //activity的根視圖
    int rootViewVisibleHeight;  //紀錄根視圖的顯示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;
    public SoftKeyBoardListener(Activity activity) {
        //擷取activity的根視圖
        rootView = activity.getWindow().getDecorView();
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        int visibleHeight = r.height();
        rootViewVisibleHeight = visibleHeight;

        //監聽視圖樹中全局布局發生改變或者視圖樹中的某個視圖的可視狀态發生改變
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //擷取目前根視圖在螢幕上顯示的大小
                Rect r = new Rect();
                rootView.getWindowVisibleDisplayFrame(r);
                int visibleHeight = r.height();
                System.out.println(""+visibleHeight);
                if (rootViewVisibleHeight == 0) {
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }
                //根視圖顯示高度沒有變化,可以看作軟鍵盤顯示/隐藏狀态沒有改變
                if (rootViewVisibleHeight == visibleHeight) {
                    return;
                }
                //根視圖顯示高度變小超過200,可以看作軟鍵盤顯示了
                if (rootViewVisibleHeight - visibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }
                //根視圖顯示高度變大超過200,可以看作軟鍵盤隐藏了
                if (visibleHeight - rootViewVisibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }
            }
        });
    }
    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }
    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);
        void keyBoardHide(int height);
    }
    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }
}
           

然後在PopupWindow中設定監聽:

LinearLayout content_container;
//該方法先執行,測量一下布局的高度,筆者是自己寫了一個class繼承PopupWindow,固這裡都是私有方法
private void initView(){
content_container = view.findViewById(R.id.content_container);
int width = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        int temp_height = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        content_container.measure(width, temp_height);
}

//布局高度測量完畢之後,設定監聽
private void softInputListener(Activity mContext){
        SoftKeyBoardListener.setListener(mContext, new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
            @Override
            public void keyBoardShow(int height) {
                ViewGroup.LayoutParams layoutParams = content_container.getLayoutParams();
            //用父布局的原高度 + 軟鍵盤彈出的高度 設定為父布局的新高度,軟鍵盤就實際是覆寫了空白的部分,就不會遮擋住原popupWindow的内容了
                layoutParams.height = content_container.getMeasuredHeight()+height;
                content_container.setLayoutParams(layoutParams);
                content_container.invalidate();
            }

            @Override
            public void keyBoardHide(int height) {
            //關閉軟鍵盤時,再把布局高度設定回來
                ViewGroup.LayoutParams layoutParams = content_container.getLayoutParams();
                layoutParams.height = content_container.getMeasuredHeight()-height;
                content_container.setLayoutParams(layoutParams);
                content_container.invalidate();
            }
        });
    }
           

繼續閱讀