自定義PopupWindow:兼容7.0,向下展開向上收起動畫

設置背景色

在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;
    }
}

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末飒泻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吏廉,更是在濱河造成了極大的恐慌泞遗,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件席覆,死亡現(xiàn)場離奇詭異史辙,居然都是意外死亡,警方通過查閱死者的電腦和手機佩伤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門聊倔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畦戒,你說我怎么就攤上這事方库。” “怎么了障斋?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵纵潦,是天一觀的道長。 經(jīng)常有香客問我垃环,道長邀层,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任遂庄,我火速辦了婚禮寥院,結果婚禮上,老公的妹妹穿的比我還像新娘涛目。我一直安慰自己秸谢,他們只是感情好凛澎,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著估蹄,像睡著了一般塑煎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上臭蚁,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天最铁,我揣著相機與錄音,去河邊找鬼垮兑。 笑死冷尉,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的系枪。 我是一名探鬼主播雀哨,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嗤无!你這毒婦竟也來了震束?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤当犯,失蹤者是張志新(化名)和其女友劉穎垢村,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚎卫,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡嘉栓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拓诸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侵佃。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奠支,靈堂內(nèi)的尸體忽然破棺而出馋辈,到底是詐尸還是另有隱情,我是刑警寧澤倍谜,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布迈螟,位于F島的核電站,受9級特大地震影響尔崔,放射性物質(zhì)發(fā)生泄漏答毫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一季春、第九天 我趴在偏房一處隱蔽的房頂上張望洗搂。 院中可真熱鬧,春花似錦、人聲如沸耘拇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惫叛。三九已至秦驯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挣棕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工亲桥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洛心,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓题篷,卻偏偏與公主長得像词身,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子番枚,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

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