public PopupWindow (Context context)
public PopupWindow(View contentView)
public PopupWindow(int width, int height)
public PopupWindow(View contentView, int width, int height)
public PopupWindow(View contentView, int width, int height, boolean focusable)
showAsDropDown(View anchor):相對(duì)某個(gè)控件的位置(正左下方),無(wú)偏移
showAsDropDown(View anchor, int xoff, int yoff):相對(duì)某個(gè)控件的位置,有偏移
showAtLocation(View parent, int gravity, int x, int y):相對(duì)于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以設(shè)置偏移或無(wú)偏移
具體如下所示
順昌網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。成都創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來(lái)到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司。//創(chuàng)建對(duì)象
PopupWindow popupWindow = new PopupWindow(this);
View inflate = LayoutInflater.from(this).inflate(R.layout.view_pop_custom, null);
//設(shè)置view布局
popupWindow.setContentView(inflate);
popupWindow.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
//設(shè)置動(dòng)畫的方法
popupWindow.setAnimationStyle(R.style.BottomDialog);
//設(shè)置PopUpWindow的焦點(diǎn),設(shè)置為true之后,PopupWindow內(nèi)容區(qū)域,才可以響應(yīng)點(diǎn)擊事件
popupWindow.setTouchable(true);
//設(shè)置背景透明
popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
//點(diǎn)擊空白處的時(shí)候讓PopupWindow消失
popupWindow.setOutsideTouchable(true);
// true時(shí),點(diǎn)擊返回鍵先消失 PopupWindow
// 但是設(shè)置為true時(shí)setOutsideTouchable,setTouchable方法就失效了(點(diǎn)擊外部不消失,內(nèi)容區(qū)域也不響應(yīng)事件)
// false時(shí)PopupWindow不處理返回鍵,默認(rèn)是false
popupWindow.setFocusable(false);
//設(shè)置dismiss事件
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
}
});
boolean showing = popupWindow.isShowing();
if (!showing){
//show,并且可以設(shè)置位置
popupWindow.showAsDropDown(mTv1);
}
先看問(wèn)題代碼,下面這個(gè)不會(huì)出現(xiàn)彈窗,思考:為什么?
PopupWindow popupWindow = new PopupWindow(this);
View inflate = LayoutInflater.from(this).inflate(R.layout.view_pop_custom, null);
popupWindow.setContentView(inflate);
popupWindow.setAnimationStyle(R.style.BottomDialog);
popupWindow.showAsDropDown(mTv1);
首先先來(lái)看看源碼
可以看出,先判斷是否show,如果沒(méi)有showing的話,則進(jìn)行contentView賦值,如果mWindowManager為null,則取獲取mWindowManager,這個(gè)很重要。最后便是根據(jù)SDK版本而不是在構(gòu)造函數(shù)中設(shè)置附加InDecor的默認(rèn)設(shè)置,因?yàn)闃?gòu)造函數(shù)中可能沒(méi)有上下文對(duì)象。我們只想在這里設(shè)置默認(rèn),如果應(yīng)用程序尚未設(shè)置附加InDecor。
public void setContentView(View contentView) {
//判斷是否show,如果已經(jīng)show,則返回
if (isShowing()) {
return;
}
//賦值
mContentView = contentView;
if (mContext == null && mContentView != null) {
mContext = mContentView.getContext();
}
if (mWindowManager == null && mContentView != null) {
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
//在這里根據(jù)SDK版本而不是在構(gòu)造函數(shù)中設(shè)置附加InDecor的默認(rèn)設(shè)置,因?yàn)闃?gòu)造函數(shù)中可能沒(méi)有上下文對(duì)象。我們只想在這里設(shè)置默認(rèn),如果應(yīng)用程序尚未設(shè)置附加InDecor。
if (mContext != null && !mAttachedInDecorSet) {
setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.LOLLIPOP_MR1);
}
}
public void setAttachedInDecor(boolean enabled) {
mAttachedInDecor = enabled;
mAttachedInDecorSet = true;
}
先來(lái)看一下showAsDropDown(View anchor)部分代碼
public void showAsDropDown(View anchor) {
showAsDropDown(anchor, 0, 0);
}
//主要看這個(gè)方法
//注意啦:關(guān)于更多內(nèi)容,可以參考我的博客大匯總:https://github.com/yangchong211/YCBlogs
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (isShowing() || mContentView == null) {
return;
}
TransitionManager.endTransitions(mDecorView);
//下面單獨(dú)講
//https://github.com/yangchong211/YCBlogs
attachToAnchor(anchor, xoff, yoff, gravity);
mIsShowing = true;
mIsDropdown = true;
//通過(guò)createPopupLayoutParams方法創(chuàng)建和初始化LayoutParams
final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
preparePopup(p);
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
p.width, p.height, gravity);
updateAboveAnchor(aboveAnchor);
p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
invokePopup(p);
}
接著來(lái)看看attachToAnchor(anchor, xoff, yoff, gravity)源碼
關(guān)于四種引用的深入介紹可以參考我的這邊文章:01.四種引用比較與源碼分析
private void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
detachFromAnchor();
final ViewTreeObserver vto = anchor.getViewTreeObserver();
if (vto != null) {
vto.addOnScrollChangedListener(mOnScrollChangedListener);
}
final View anchorRoot = anchor.getRootView();
anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
mAnchor = new WeakReference<>(anchor);
mAnchorRoot = new WeakReference<>(anchorRoot);
mIsAnchorRootAttached = anchorRoot.isAttachedToWindow();
mAnchorXoff = xoff;
mAnchorYoff = yoff;
mAnchoredGravity = gravity;
}
接著看看dismissImmediate(View decorView, ViewGroup contentHolder, View contentView)源碼
第三步,講mDecorView,mBackgroundView置為null
private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) {
// If this method gets called and the decor view doesn't have a parent,
// then it was either never added or was already removed. That should
// never happen, but it's worth checking to avoid potential crashes.
if (decorView.getParent() != null) {
mWindowManager.removeViewImmediate(decorView);
}
if (contentHolder != null) {
contentHolder.removeView(contentView);
}
// This needs to stay until after all transitions have ended since we
// need the reference to cancel transitions in preparePopup().
mDecorView = null;
mBackgroundView = null;
mIsTransitioningToDismiss = false;
}
通過(guò)createDecorView(View contentView)方法可以知道,是PopupDecorView直接new出來(lái)的布局對(duì)象decorView,外面包裹了一層PopupDecorView,這里的PopupDecorView也是我們自定義的FrameLayout的子類,然后看一下里面的代碼:
private class PopupDecorView extends FrameLayout {
private TransitionListenerAdapter mPendingExitListener;
public PopupDecorView(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if ((event.getAction() == MotionEvent.ACTION_DOWN)
&& ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
dismiss();
return true;
} else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
} else {
return super.onTouchEvent(event);
}
}
}
new CustomPopupWindow.PopupWindowBuilder(this)
//.setView(R.layout.pop_layout)
.setView(contentView)
.setFocusable(true)
//彈出popWindow時(shí),背景是否變暗
.enableBackgroundDark(true)
//控制亮度
.setBgDarkAlpha(0.7f)
.setOutsideTouchable(true)
.setAnimationStyle(R.style.popWindowStyle)
.setOnDissmissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
//對(duì)話框銷毀時(shí)
}
})
.create()
.showAsDropDown(tv6,0,10);
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。