拒絕無用功陷虎,封裝一個通用的 PopupWindow

作者: 夏至到踏,歡迎轉(zhuǎn)載,但請保留這段申明尚猿,謝謝
https://juejin.im/post/5961e03e51882568b13c3308

為了避免重復(fù)造輪子窝稿,我們一般都會封裝一個通用的控件,比如這次凿掂,項目中需要用到比較多的 popupwindow 伴榔,如果需要一個個寫,那么依舊會累死人庄萎,而且還是無用功踪少,無意義,所以糠涛,封裝一個通用的援奢,除了讓同事看了直刷666之外,自己還省了很多事情脱羡。
先上效果圖:

1萝究、如何使用

那么,一般我們配置一個 PopupWindow 正常步驟需要多少代碼呢锉罐?如下:

PopupWindow popupWindow = new PopupWindow(this);
        View contentview = LayoutInflater.from(this).inflate(R.layout.popup_calendar,null);
        popupWindow =
                new PopupWindow(contentview,
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        true);
        //設(shè)置取消
        popupWindow.setOutsideTouchable(true);
        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
       
        
        //設(shè)置位置
        View rootview = LayoutInflater.from(this).inflate(R.layout.activity_main,null);
        popupWindow.showAtLocation(rootview,Gravity.CENTER,0,0);

一般我們需要實現(xiàn)上面的基本代碼帆竹,PopupWindow 才能跑起來,然后我們還需要添加動畫脓规,監(jiān)聽back鍵等等栽连,然后,另外一個需要用到的時候侨舆,又得重復(fù)寫秒紧,真的讓人很絕望,這個時候挨下,封裝的思想就從腦袋冒出來了熔恢,那么,封裝之后臭笆,怎么樣的呢叙淌?如下:

CustomPopupWindow popupWindow = new CustomPopupWindow.Builder()
                        .setContext(this) //設(shè)置 context
                        .setContentView(R.layout.popup_calendar) //設(shè)置布局文件
                        .setwidth(LinearLayout.LayoutParams.WRAP_CONTENT) //設(shè)置寬度,由于我已經(jīng)在布局寫好愁铺,這里就用 wrap_content就好了
                        .setheight(LinearLayout.LayoutParams.WRAP_CONTENT) //設(shè)置高度
                        .setFouse(true)  //設(shè)置popupwindow 是否可以獲取焦點
                        .setOutSideCancel(true) //設(shè)置點擊外部取消
                        .setAnimationStyle(R.style.popup_anim_style) //設(shè)置popupwindow動畫
                        .builder() //
                        .showAtLocation(R.layout.activity_calendar, Gravity.CENTER,0,0); //設(shè)置popupwindow居中顯示

注意上面的 showAtLocation 是在 builder 之后的鹰霍,表示顯示正中間;如果想讓它顯示在某個 view 的相應(yīng)位置茵乱,也可以使用 showAsLocation() 來實現(xiàn)茂洒。
至于為什么在 builder() 的后面呢?因為不太確定在用的時候瓶竭,是顯示在父布局的位置督勺,還是顯示在某個控件的相應(yīng)位置渠羞,所以,我把代碼封裝成下面這樣:

   /**
     * 根據(jù)父布局玷氏,顯示位置
     * @param rootviewid
     * @param gravity
     * @param x
     * @param y
     * @return
     */
    public CustomPopupWindow showAtLocation(int rootviewid,int gravity,int x,int y){
        if (mPopupWindow != null){
            View rootview = LayoutInflater.from(mContext).inflate(rootviewid,null);
            mPopupWindow.showAtLocation(rootview,gravity,x,y);
        }
        return this;
    }

當(dāng)然堵未,你要把它抽出來也可以的;

還有一種常見的情況盏触,我們常用 popupwindow 作用 dialog,那么里面有 button 處理相應(yīng)的邏輯块饺。那如何想獲取 PopupWindow 里面的控件怎么辦赞辩?為了方便調(diào)用,這里我也采用用 id 的形式授艰,所以辨嗽,調(diào)用只要這樣即可:

mMonthPicker = (PickerView) popupWindow.getItemView(R.id.picker_month);

然后就可以用 mMonthPicker 這個 view 搞事情了。

這樣就把 contentview 中的控件取出來使用了淮腾,只要知道 id 就可以了糟需,是不是方便了很多,都挺簡單的谷朝,大家自己封裝一邊就ok全明白了洲押。

封裝思路

相比封裝 listview 和 recyclerview ,這個算是比較簡單的圆凰,就是觀察最原始的代碼杈帐,提取最核心不變的;無非就是 PopupWindow 的最要布局

  • cnotentview 专钉,為了避免每次都來個 layoutinflate 挑童,我們封裝成一個 id
  • 大小,我們都知道 PopupWindow 沒有自己的布局跃须,上面在給了 contentview 之后站叼,大小也要給
  • 顯示位置,顯示就兩個函數(shù) 菇民,showAtLocation 和 showAsLocation 尽楔,為了方便,我們也寫成 id 的方式玉雾,當(dāng)然也可以傳入 view

基本就可以了翔试,至于其他附加項,比如動畫复旬,點擊外部取消垦缅,監(jiān)聽back鍵,或者簡單 contentview 控件的事件驹碍,都是變動的壁涎,所以凡恍,用 Builder 的模式構(gòu)建比較舒服一些。具體就這些了怔球。如果你對 Builder 這中模式不熟悉嚼酝,可以看我以前文章:

模仿常用框架Builder初始化數(shù)據(jù),如何優(yōu)雅地裝逼

3竟坛、CustomPopupWindow 完成代碼

以下是我現(xiàn)在用的代碼闽巩,大家可以參考一下,根據(jù)自己的需求添加或者刪除担汤。

** 動畫部分:**

 <style name="popup_anim_style">
        <item name="android:windowEnterAnimation">@anim/menushow</item>
        <item name="android:windowExitAnimation">@anim/menudiss</item>
    </style>

menushow :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fillAfter="true">
    <scale
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1.0" />

</set>

menudiss :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fillAfter="true">
    <scale
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0"
        android:toYScale="0" />
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0" />

</set>

布局就不貼出來涎跨,由于用到自定義控件,貼出來反而不好崭歧,大家根據(jù)自己的需求隅很,編寫即可。

CustomPopupWindow 完整代碼:

public  class CustomPopupWindow {
    private PopupWindow mPopupWindow;
    private View contentview;
    private  Context mContext;
    public CustomPopupWindow(Builder builder) {
        mContext = builder.context;
        contentview = LayoutInflater.from(mContext).inflate(builder.contentviewid,null);
        mPopupWindow =
                new PopupWindow(contentview,builder.width,builder.height,builder.fouse);

        //需要跟 setBackGroundDrawable 結(jié)合
        mPopupWindow.setOutsideTouchable(builder.outsidecancel);
        mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        mPopupWindow.setAnimationStyle(builder.animstyle);



    }



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

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

    /**
     * 根據(jù)父布局率碾,顯示位置
     * @param rootviewid
     * @param gravity
     * @param x
     * @param y
     * @return
     */
    public CustomPopupWindow showAtLocation(int rootviewid,int gravity,int x,int y){
        if (mPopupWindow != null){
            View rootview = LayoutInflater.from(mContext).inflate(rootviewid,null);
            mPopupWindow.showAtLocation(rootview,gravity,x,y);
        }
        return this;
    }

    /**
     * 根據(jù)id獲取view 叔营,并顯示在該view的位置
     * @param targetviewId
     * @param gravity
     * @param offx
     * @param offy
     * @return
     */
    public CustomPopupWindow showAsLaction(int targetviewId,int gravity,int offx,int offy){
        if (mPopupWindow != null){
            View targetview = LayoutInflater.from(mContext).inflate(targetviewId,null);
            mPopupWindow.showAsDropDown(targetview,gravity,offx,offy);
        }
        return this;
    }

    /**
     * 顯示在 targetview 的不同位置
     * @param targetview
     * @param gravity
     * @param offx
     * @param offy
     * @return
     */
    public CustomPopupWindow showAsLaction(View targetview,int gravity,int offx,int offy){
        if (mPopupWindow != null){
            mPopupWindow.showAsDropDown(targetview,gravity,offx,offy);
        }
        return this;
    }


    /**
     * 根據(jù)id設(shè)置焦點監(jiān)聽
     * @param viewid
     * @param listener
     */
    public void setOnFocusListener(int viewid,View.OnFocusChangeListener listener){
        View view = getItemView(viewid);
        view.setOnFocusChangeListener(listener);
    }


    /**
     * builder 類
     */
    public static class Builder{
        private int contentviewid;
        private int width;
        private int height;
        private boolean fouse;
        private boolean outsidecancel;
        private int animstyle;
        private Context context;

       public Builder setContext(Context context){
           this.context = context;
           return this;
       }


        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 setFouse(boolean fouse){
            this.fouse = fouse;
            return this;
        }

        public Builder setOutSideCancel(boolean outsidecancel){
            this.outsidecancel = outsidecancel;
            return this;
        }
        public Builder setAnimationStyle(int animstyle){
            this.animstyle = animstyle;
            return this;
        }



        public CustomPopupWindow builder(){
           return new CustomPopupWindow(this);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市所宰,隨后出現(xiàn)的幾起案子绒尊,更是在濱河造成了極大的恐慌,老刑警劉巖歧匈,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垒酬,死亡現(xiàn)場離奇詭異,居然都是意外死亡件炉,警方通過查閱死者的電腦和手機勘究,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斟冕,“玉大人口糕,你說我怎么就攤上這事】纳撸” “怎么了景描?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秀撇。 經(jīng)常有香客問我超棺,道長,這世上最難降的妖魔是什么呵燕? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任棠绘,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氧苍。我一直安慰自己夜矗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布让虐。 她就那樣靜靜地躺著紊撕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赡突。 梳的紋絲不亂的頭發(fā)上对扶,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音惭缰,去河邊找鬼辩稽。 笑死,一個胖子當(dāng)著我的面吹牛从媚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播患整,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼拜效,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了各谚?” 一聲冷哼從身側(cè)響起紧憾,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昌渤,沒想到半個月后赴穗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡膀息,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年般眉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潜支。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡甸赃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冗酿,到底是詐尸還是另有隱情埠对,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布裁替,位于F島的核電站项玛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏弱判。R本人自食惡果不足惜襟沮,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臣嚣,春花似錦净刮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怎虫,卻和暖如春暑认,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背大审。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工蘸际, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徒扶。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓粮彤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姜骡。 傳聞我的和親對象是個殘疾皇子导坟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容