作者: 夏至到踏,歡迎轉(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);
}
}
}