1. 程式人生 > >我們仍未知道的popWindow 7.0 8.0位置顯示錯誤

我們仍未知道的popWindow 7.0 8.0位置顯示錯誤

popWindow一個神奇的控制元件,為了記錄自己曾解決過的問題,也避免其他小哥遇到一樣的問題,故留下部落格進行記錄。

最近在寫一個下拉框的時候,測試小哥找到我說7.0,7.1,8.0的顯示效果不一致……

我當時的心情是……&¥%#&&(&

好吧,當遇這樣的問題,第一反應是不要慌……不要慌……甩鍋……不對,是分析並解決問題。由於各種原因我這裡就不上產品的效果,取而代之用一個抽取了特徵的demo來代替說明問題。(其實在驗證問題時,抽取出相關因素用demo進行還原除錯,不失為一個很好的辦法,畢竟有些工程光編譯就要7、8分鐘,你會感受到被編譯支配的恐懼。)

1、問題展示

正常效果是這樣的:

8.0手機上的效果是這樣的:

2、問題的嘗試與分析

好了,上程式碼吧。

    public void popWindow(View view) {
        // 將佈局檔案轉換成View物件,popupview 內容檢視
        View mPopView = getLayoutInflater().inflate(R.layout.pop_window_item, null);
        // 將轉換的View放置到 新建一個popuwindow物件中
        PopupWindow mPopupWindow = new PopupWindow(mPopView,
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        
        mPopupWindow.showAsDropDown(view);
    }

從程式碼上看貌似沒什麼問題,那麼我們就要考慮是否是不同api之間的問題了。

這裡經過嘗試當高度使用WRAP_CONTENT而不是MATCH_PARENT則不會出現問題,那麼我們可以猜想出showAsDropDown的anchor定位view並沒有錯,使用WRAP_CONTENT計算的起始下標為指定view的左下座標點。

public void showAsDropDown(View anchor) {
        throw new RuntimeException("Stub!"); 
}

而MATCH_PARENT的座標起始點恐怕已經被設定成狀態列下的左上頂部座標點了吧。

3、解決方案

自定義一個繼承PopWindow的類,並複寫showAsDropDown()方法,你可以複寫showAsDropDown(View anchor),public void showAsDropDown(View anchor, int xoff, int yoff) 等方法,具體看各自呼叫的需求。

public class CompatiblePopWindow extends PopupWindow {
    public CompatiblePopWindow(View contentView, int width, int height) {
        super(contentView, width, height);
    }

    @Override
    public void showAsDropDown(View anchor) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Rect compatibleFix = new Rect();
            anchor.getGlobalVisibleRect(compatibleFix);
            int height = anchor.getResources().getDisplayMetrics().heightPixels - compatibleFix.bottom;
            this.setHeight(height);
        }
        super.showAsDropDown(anchor);
    }

}
    /**Button彈出popupWindow的點選事件
     */
    public void popWindow(View view) {
        // 將佈局檔案轉換成View物件,popupview 內容檢視
        View mPopView = getLayoutInflater().inflate(R.layout.pop_window_item, null);
        // 將轉換的View放置到 新建一個popuwindow物件中
        CompatiblePopWindow popupWindow = new CompatiblePopWindow(mPopView,
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);

        popupWindow.showAsDropDown(view);
    }

附贈一個簡單PopWindow類的封裝呼叫,該封裝類和使用demo可以下載附件獲取。

    /**Button彈出popupWindow的點選事件
     */
    public void popWindow(View view) {
        // 將佈局檔案轉換成View物件,popupview 內容檢視
        View mPopView = getLayoutInflater().inflate(R.layout.pop_window_item, null);

        //附帶庫的使用方法
        TomesPopWindow mPopWindow = new TomesPopWindow.PopupWindowBuilder(this)
                .setView(mPopView)
                .size(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT)
                .create()
                .showAsDropDown(view,0,0);
    }

Demo下載