簡易封裝的PopupWindow

import android.app.Activity;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;

import com.msyc.onion.R;

import java.lang.ref.WeakReference;

/**
 * 簡易封裝的PopupWindow
 */

public class CustomPopupWindow implements PopupWindow.OnDismissListener {
    private PopupWindow mPopupWindow;
    private View contentView;
    private static WeakReference<Activity> refActivity;
    private Builder builder;

    public CustomPopupWindow(Builder builder) {
        this.builder = builder;
        contentView = LayoutInflater.from(refActivity.get()).inflate(builder.contentViewId, null);
        mPopupWindow = new PopupWindow(contentView, builder.width, builder.height);
        if (builder.outsideTouchable) {
            //設置點擊外部可以取消,必須和下面這個方法配合才有效,(setOutsideTouchable設置生效的前提是setTouchable(true)和setFocusable(false),此處存疑)
            mPopupWindow.setOutsideTouchable(true);
            //設置一個空背景,設置了這個背景之后,設置點擊外部取消才有效
            mPopupWindow.setBackgroundDrawable(new ColorDrawable()); //如果不設置PopupWindow的背景,有些版本就會出現一個問題:無論是點擊外部區域還是Back鍵都無法dismiss彈框
//            mPopupWindow.setTouchable(true);
            mPopupWindow.setFocusable(true); // false時PopupWindow不處理返回鍵(此處設置為true,則效果是正常的,和上方的說法存疑)
        }
        //Popupwindow可以點擊,PopupWindow彈出后,所有的觸屏和物理按鍵都有PopupWindows處理。
        // 其他任何事件的響應都必須發生在PopupWindow消失之后, (home  等系統層面的事件除外)。
        // 比如這樣一個PopupWindow出現的時候,按back鍵首先是讓PopupWindow消失,
        // 第二次按才是退出activity,
        //解決Pop遮擋住虛擬鍵盤的問題
        mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
        //讓pop自適應輸入狀態
        mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        if (builder.animStyle != 0) {
            mPopupWindow.setAnimationStyle(builder.animStyle); //設置pop顯示的動畫效果
        }
        mPopupWindow.setOnDismissListener(this); //設置pop關閉的監聽事件

        // 原生的Outside 事件會穿透到下方(原生問題),故用gray_layout多做一層補充作用(主要用于點擊消失popwindow,避免事件穿透)
        if (contentView.findViewById(R.id.gray_layout) != null) {
            View grayLayout = (View) contentView.findViewById(R.id.gray_layout);
            grayLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                }
            });
        }
    }

    /**
     * popup 消失
     */
    public void dismiss() {
        if (mPopupWindow != null && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        }
    }


    /**
     * 相對于窗體的顯示位置
     *
     * @param view    可以為Activity中的任意一個View(最終的效果一樣),
     *                會通過這個View找到其父Window,也就是Activity的Window。
     * @param gravity 在窗體中的位置,默認為Gravity.NO_GRAVITY
     * @param x       表示距離Window邊緣的距離,方向由Gravity決定。
     *                例如:設置了Gravity.TOP,則y表示與Window上邊緣的距離;
     *                而如果設置了Gravity.BOTTOM,則y表示與下邊緣的距離。
     * @param y
     * @return
     */
    public CustomPopupWindow showAtLocation(View view, int gravity, int x, int y) {
        if (mPopupWindow != null) {
            mPopupWindow.showAtLocation(view, gravity, x, y);
            if (builder != null) setBackgroundAlpha(builder.backgroundAlpha); //設置窗體的背景透明度為半透明
        }
        return this;
    }


    /**
     * 顯示在anchor控件的正下方,或者相對這個控件的位置
     *
     * @param anchor 錨點
     * @param xOff   相對這個控件x方向的偏移
     * @param yOff   相對這個控件y方向的偏移
     * @return
     */
//    public CustomPopupWindow showAsDropDown(View anchor, int xOff, int yOff) {
//        if (mPopupWindow != null) {
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//                //7.0以上系統
//                //獲取目標控件在屏幕中的坐標位置
//                int[] location = new int[2];
//                anchor.getLocationOnScreen(location);
//                mPopupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, location[1] + anchor.getHeight() + yOff);
//            } else {
//                mPopupWindow.showAsDropDown(anchor, xOff, yOff);
//            }
//            if (builder != null) setBackgroundAlpha(builder.backgroundAlpha); //設置窗體的背景透明度為半透明
//        }
//        return this;
//    }
    public CustomPopupWindow showAsDropDown(View anchor, int xOff, int yOff) {
        if (mPopupWindow != null) {
            if (!mPopupWindow.isShowing()) {
                // 以下拉方式顯示popupwindow
                mPopupWindow.showAsDropDown(anchor, xOff, yOff);
                if (builder != null) setBackgroundAlpha(builder.backgroundAlpha); //設置窗體的背景透明度為半透明
            }
//            else {
//                this.dismiss();
//            }
        }
        return this;
    }

    public CustomPopupWindow showAsDropDown(View anchor) {
        if (mPopupWindow != null) {
            if (!mPopupWindow.isShowing()) {
                // 以下拉方式顯示popupwindow
                mPopupWindow.showAsDropDown(anchor);
                if (builder != null) setBackgroundAlpha(builder.backgroundAlpha); //設置窗體的背景透明度為半透明
            }
//            else {
//                this.dismiss();
//            }
        }
        return this;
    }

    /**
     * 根據id獲取view
     *
     * @param viewId
     * @return
     */
    public View getItemView(int viewId) {
        if (mPopupWindow != null) {
            return contentView.findViewById(viewId);
        }
        return null;
    }


    /**
     * 根據id設置pop內部的控件的點擊事件的監聽
     *
     * @param viewId
     * @param listener
     */
    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        View view = getItemView(viewId);
        view.setOnClickListener(listener);
    }

    /**
     * 設置Activity或者Fragment的背景透明度
     *
     * @param bgAlpha 背景的透明度
     */
    public void setBackgroundAlpha(float bgAlpha) {
        if (refActivity.get() == null || refActivity.get().getWindow() == null) return;
        WindowManager.LayoutParams layoutParams = refActivity.get().getWindow().getAttributes();
        layoutParams.alpha = bgAlpha; //0.0-1.0
        refActivity.get().getWindow().setAttributes(layoutParams);
    }

    /**
     * builder 類
     */
    public static class Builder {
        private int contentViewId; //pop的布局文件
        private int width; //pop的寬度
        private int height;  //pop的高度
        private int animStyle; //動畫效果
        private float backgroundAlpha = 0.5f; //背景的透明度,默認半透明
        private boolean outsideTouchable = false; //設置點擊外部可以取消

        public Builder(Activity activity) {
            refActivity = new WeakReference<>(activity);
        }

        public Builder setContentView(int contentViewId) {
            this.contentViewId = contentViewId;
            return this;
        }

        public Builder setwidth(int width) {
            this.width = width;
            return this;
        }

        public Builder setheight(int height) {
            this.height = height;
            return this;
        }


        public Builder setAnimationStyle(int animStyle) {
            this.animStyle = animStyle;
            return this;
        }

        public Builder setBackgroundAlpha(float backgroundAlpha) {
            this.backgroundAlpha = backgroundAlpha;
            return this;
        }

        public Builder setOutsideTouchable(boolean touchable) {
            outsideTouchable = touchable;
            return this;
        }

        public CustomPopupWindow build() {
            return new CustomPopupWindow(this);
        }
    }

    @Override
    public void onDismiss() {
        if (builder == null || builder.backgroundAlpha != 1f)
            setBackgroundAlpha(1f); //設置窗體的背景透明度為不透明
    }
}

使用方法:

private CustomPopupWindow mSearchDropPop; 

/**
     * 初始化Pop,pop的布局是一個列表
     */
    private void initPop() {
        if (mSearchDropPop == null || mSearchDropAdapter == null) {
            mSearchDropPop = new CustomPopupWindow.Builder(this)
                    .setContentView(R.layout.search_drop_pop_window)
                    .setwidth(LinearLayout.LayoutParams.MATCH_PARENT)
                    .setheight(LinearLayout.LayoutParams.WRAP_CONTENT)
                    .setBackgroundAlpha(1.0f)
                    .build();
            //搜索聯想結果的列表
            ListView searchLv = (ListView) mSearchDropPop.getItemView(R.id.lv_search_list);
            mSearchDropAdapter = new SearchDropAdapter(this, null);
            searchLv.setAdapter(mSearchDropAdapter);
            searchLv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    mBinding.editTextSearch.setText(mSearchDropAdapter.getList().get(position).text);
                    mKeyword = mSearchDropAdapter.getList().get(position).text;
                    preSearch().search(mSearchDropAdapter.request_id); // 點擊聯想詞
                }
            });
        }
    }

/**關鍵字聯想詞*/
        mViewModel.mSearchDropData.observe(this, result -> {
            if (result == null || result.getBeanList().size() <= 0) {
                mSearchDropPop.dismiss();
            } else {
                String s = mBinding.editTextSearch.getText().toString();
                if (s.length() > 0 && s.equals(mmSearchDropWord)) {
                    mSearchDropAdapter.setDatas(result);
                    mSearchDropAdapter.notifyDataSetChanged();
                    mSearchDropPop.showAsDropDown(mBinding.editTextSearch); 
                }
            }
        });

@Override
    protected void onDestroy() {
        if (mSearchDropPop != null) {
            mSearchDropPop.dismiss();
        }
        super.onDestroy();
    }

xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#66000000"
    android:orientation="vertical">

    <ListView
        android:id="@+id/lv_search_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:divider="@null"
        android:paddingTop="@dimen/dp_6" />
    <!--該View用來撐滿屏幕用 顯示灰色透明背景-->
    <View
        android:id="@+id/gray_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F1F2F4" />

</LinearLayout>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370