設置背景色
在Android App的業(yè)務場景中次慢,經(jīng)常需要在屏幕彈出PopupWindow后,將背景設置為半透明的灰色效果翔曲。比較常見的解決方案就是設置Window的透明度迫像。
具體代碼如下:
//設置屏幕的透明度
public void setBackgroundAlpha(Activity activity,float alpha)
{
WindowManager.LayoutParams lp = activity .getWindow().getAttributes();
lp.alpha = alpha; //0.0-1.0
activity .getWindow().getWindow().setAttributes(lp);
}
PopupWindow在使用時瞳遍,需要監(jiān)聽其Touch事件闻妓,允許觸摸彈窗外地方時取消顯示。同時需要監(jiān)聽dismiss事件掠械,便于在彈窗消失后恢復背景的透明度由缆。
moreZPop = new PopupWindow(mContext);
moreZPop.setContentView(popZSRootView);
moreZPop.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
moreZPop.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
moreZPop.setBackgroundDrawable(new BitmapDrawable());
moreZPop.setOutsideTouchable(true);
moreZPop.setFocusable(true);
moreZPop.setAnimationStyle(R.style.optional_index_pop_style);
popWin.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
setBackgroundAlpha(TestActivity.this, 1f);
}
});
但是該方案不適合于app頁面中間某位置彈窗的場景,下圖示例:
展開彈窗展示具體信息
7.0手機showAsDropDown兼容性問題
針對上述場景猾蒂,常見的實現(xiàn)就是PopupWindow的視圖中包括兩部分均唉,一部分是上部的content,另一部分是下部的透明背景肚菠。其中透明背景部分使用match_parent充滿全屏舔箭。
但是該方案配合showAsDropDown方法,在android 7.0及以上手機時案糙,彈窗會出現(xiàn)在狀態(tài)欄下面限嫌,而不是指定的控件下。
解決方案如下时捌,通過設置PopupWindow的高度來解決怒医。但是針對華為虛擬鍵盤存在兼容性問題,目前未找到解決方案奢讨。
public class NougatFixPopwindow extends PopupWindow {
public NougatFixPopwindow(Context context) {
super(context);
}
public NougatFixPopwindow(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NougatFixPopwindow(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public NougatFixPopwindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public NougatFixPopwindow() {
}
public NougatFixPopwindow(View contentView) {
super(contentView);
}
public NougatFixPopwindow(int width, int height) {
super(width, height);
}
public NougatFixPopwindow(View contentView, int width, int height) {
super(contentView, width, height);
}
public NougatFixPopwindow(View contentView, int width, int height, boolean focusable) {
super(contentView, width, height, focusable);
}
@Override
public void showAsDropDown(View anchor) {
if (Build.VERSION.SDK_INT >= 24) {
//TODO 下列代碼在華為手機虛擬鍵盤隱藏的情況下有兼容性問題稚叹。目前未找到完美解決方案
Rect visibleFrame = new Rect();
anchor.getGlobalVisibleRect(visibleFrame);
int height = anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom;
setHeight(height);
super.showAsDropDown(anchor);
//下列方案在小米android 7.1.1上遇到問題。popupwindow未在showAtLocation指定的位置出現(xiàn)拿诸,而是在屏幕頂部
// int[] location = new int[2];
// anchor.getLocationOnScreen(location);
// super.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, location[1] + anchor.getHeight());
} else {
super.showAsDropDown(anchor);
}
}
}
向下展開向上收起動畫
在上面的解決方案中扒袖,如果需要為彈窗加入向下展開向上收起的動畫,不能使用簡單的traslate亩码,scale等系統(tǒng)動畫季率。
我使用ValueAnimator來動態(tài)設置PopupWindow中content部分的高度來實現(xiàn)動畫。具體見下面代碼:
public class ExpandAndCollapseAnimPopupWindow extends NougatFixPopwindow {
private int mContentHeight;
private View mContentView;
private AnimatorSet mOpenAnimator;
private AnimatorSet mCloseAnimator;
private int mDuration = 200;
private boolean mIsDismiss = false;
public ExpandAndCollapseAnimPopupWindow(Context context) {
super(context);
init();
}
public ExpandAndCollapseAnimPopupWindow(View contentView, int width, int height) {
super(contentView, width, height);
init();
}
private void init(){
}
public void setAnimationView(View contentView, int duration){
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
this.setAnimationView(contentView, contentView.getMeasuredHeight(), duration);
}
public void setAnimationView(View contentView, int contentHeight, int duration){
this.mContentView = contentView;
this.mContentHeight = contentHeight;
this.mDuration = duration;
if (mOpenAnimator == null){
mOpenAnimator = createOpenAnimation();
}
if (mCloseAnimator == null){
mCloseAnimator = createCloseAnimation();
}
//TODO 設置setOutsideTouchable為false描沟,因目前未找到好的方法監(jiān)聽dismiss開始事件
this.setOutsideTouchable(false);
}
@Override
public void showAsDropDown(View anchor){
super.showAsDropDown(anchor);
if (mOpenAnimator != null){
mOpenAnimator.start();
}
}
@Override
public void dismiss(){
if (mIsDismiss){
super.dismiss();
mIsDismiss = false;
} else {
if (mCloseAnimator != null){
mCloseAnimator.start();
}
}
}
private static ValueAnimator createDropAnimator(final View v, int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
int value = (int) arg0.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height = value;
v.setLayoutParams(layoutParams);
}
});
return animator;
}
private AnimatorSet createOpenAnimation() {
AnimatorSet set = new AnimatorSet();
set.setDuration(mDuration);
ValueAnimator downAnimator = createDropAnimator(mContentView, 0, mContentHeight);
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this.getContentView(), View.ALPHA, 0.0f, 1.0f);
set.playTogether(downAnimator, alphaAnimator);
set.setDuration(mDuration);
return set;
}
private AnimatorSet createCloseAnimation() {
AnimatorSet set = new AnimatorSet();
set.setDuration(mDuration);
ValueAnimator upAnimator = createDropAnimator(mContentView, mContentHeight, 0);
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this.getContentView(), View.ALPHA, 1.0f, 0.0f);
set.playTogether(upAnimator, alphaAnimator);
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mIsDismiss = true;
ExpandAndCollapseAnimPopupWindow.this.dismiss();
}
});
set.setDuration(mDuration);
return set;
}
}