簡(jiǎn)易封裝的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;

/**
 * 簡(jiǎn)易封裝的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) {
            //設(shè)置點(diǎn)擊外部可以取消腾节,必須和下面這個(gè)方法配合才有效,(setOutsideTouchable設(shè)置生效的前提是setTouchable(true)和setFocusable(false),此處存疑)
            mPopupWindow.setOutsideTouchable(true);
            //設(shè)置一個(gè)空背景,設(shè)置了這個(gè)背景之后橄抹,設(shè)置點(diǎn)擊外部取消才有效
            mPopupWindow.setBackgroundDrawable(new ColorDrawable()); //如果不設(shè)置PopupWindow的背景,有些版本就會(huì)出現(xiàn)一個(gè)問題:無論是點(diǎn)擊外部區(qū)域還是Back鍵都無法dismiss彈框
//            mPopupWindow.setTouchable(true);
            mPopupWindow.setFocusable(true); // false時(shí)PopupWindow不處理返回鍵(此處設(shè)置為true,則效果是正常的镶殷,和上方的說法存疑)
        }
        //Popupwindow可以點(diǎn)擊,PopupWindow彈出后,所有的觸屏和物理按鍵都有PopupWindows處理。
        // 其他任何事件的響應(yīng)都必須發(fā)生在PopupWindow消失之后, (home  等系統(tǒng)層面的事件除外)响巢。
        // 比如這樣一個(gè)PopupWindow出現(xiàn)的時(shí)候,按back鍵首先是讓PopupWindow消失棒妨,
        // 第二次按才是退出activity踪古,
        //解決Pop遮擋住虛擬鍵盤的問題
        mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
        //讓pop自適應(yīng)輸入狀態(tài)
        mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        if (builder.animStyle != 0) {
            mPopupWindow.setAnimationStyle(builder.animStyle); //設(shè)置pop顯示的動(dòng)畫效果
        }
        mPopupWindow.setOnDismissListener(this); //設(shè)置pop關(guān)閉的監(jiān)聽事件

        // 原生的Outside 事件會(huì)穿透到下方(原生問題),故用gray_layout多做一層補(bǔ)充作用(主要用于點(diǎn)擊消失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();
        }
    }


    /**
     * 相對(duì)于窗體的顯示位置
     *
     * @param view    可以為Activity中的任意一個(gè)View(最終的效果一樣)批钠,
     *                會(huì)通過這個(gè)View找到其父Window啡省,也就是Activity的Window。
     * @param gravity 在窗體中的位置躬贡,默認(rèn)為Gravity.NO_GRAVITY
     * @param x       表示距離Window邊緣的距離腰懂,方向由Gravity決定幌蚊。
     *                例如:設(shè)置了Gravity.TOP翻伺,則y表示與Window上邊緣的距離畴蒲;
     *                而如果設(shè)置了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); //設(shè)置窗體的背景透明度為半透明
        }
        return this;
    }


    /**
     * 顯示在anchor控件的正下方燕刻,或者相對(duì)這個(gè)控件的位置
     *
     * @param anchor 錨點(diǎn)
     * @param xOff   相對(duì)這個(gè)控件x方向的偏移
     * @param yOff   相對(duì)這個(gè)控件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以上系統(tǒng)
//                //獲取目標(biāo)控件在屏幕中的坐標(biāo)位置
//                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); //設(shè)置窗體的背景透明度為半透明
//        }
//        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); //設(shè)置窗體的背景透明度為半透明
            }
//            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); //設(shè)置窗體的背景透明度為半透明
            }
//            else {
//                this.dismiss();
//            }
        }
        return this;
    }

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


    /**
     * 根據(jù)id設(shè)置pop內(nèi)部的控件的點(diǎn)擊事件的監(jiān)聽
     *
     * @param viewId
     * @param listener
     */
    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        View view = getItemView(viewId);
        view.setOnClickListener(listener);
    }

    /**
     * 設(shè)置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; //動(dòng)畫效果
        private float backgroundAlpha = 0.5f; //背景的透明度,默認(rèn)半透明
        private boolean outsideTouchable = false; //設(shè)置點(diǎn)擊外部可以取消

        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); //設(shè)置窗體的背景透明度為不透明
    }
}

使用方法:

private CustomPopupWindow mSearchDropPop; 

/**
     * 初始化Pop剖笙,pop的布局是一個(gè)列表
     */
    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();
            //搜索聯(lián)想結(jié)果的列表
            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); // 點(diǎn)擊聯(lián)想詞
                }
            });
        }
    }

/**關(guān)鍵字聯(lián)想詞*/
        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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市请唱,隨后出現(xiàn)的幾起案子弥咪,更是在濱河造成了極大的恐慌,老刑警劉巖十绑,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聚至,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡本橙,警方通過查閱死者的電腦和手機(jī)扳躬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贷币,你說我怎么就攤上這事击胜。” “怎么了役纹?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵偶摔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我促脉,道長(zhǎng)辰斋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任瘸味,我火速辦了婚禮宫仗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旁仿。我一直安慰自己锰什,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布丁逝。 她就那樣靜靜地躺著汁胆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霜幼。 梳的紋絲不亂的頭發(fā)上嫩码,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音罪既,去河邊找鬼铸题。 笑死,一個(gè)胖子當(dāng)著我的面吹牛琢感,可吹牛的內(nèi)容都是我干的丢间。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼驹针,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼烘挫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柬甥,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤饮六,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后苛蒲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卤橄,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年臂外,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窟扑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喇颁。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嚎货,靈堂內(nèi)的尸體忽然破棺而出橘霎,到底是詐尸還是另有隱情,我是刑警寧澤厂抖,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布茎毁,位于F島的核電站,受9級(jí)特大地震影響忱辅,放射性物質(zhì)發(fā)生泄漏七蜘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一墙懂、第九天 我趴在偏房一處隱蔽的房頂上張望橡卤。 院中可真熱鬧,春花似錦损搬、人聲如沸碧库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嵌灰。三九已至,卻和暖如春颅悉,著一層夾襖步出監(jiān)牢的瞬間沽瞭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工剩瓶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驹溃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓延曙,卻偏偏與公主長(zhǎng)得像豌鹤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枝缔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345