優雅自定義Dialog

前言

在寫這篇之前我說說我的感受,在之前有用到Dialog的地方,我真的很鬱悶,各種不適配,功能實現起來很是麻煩,那麼當我接觸到WindowManager後,我就心想,我要自己弄一套Dialog,來實現我想要的功能。其實我們的大部分提示窗口只要依附在Activity上就可以了,我們得到一塊窗體後,我們就可以在窗體上進行繪製我們想要的效果。

封裝WindowManager

1.初始化我們的WindowManager.LayoutParams

  /**
     * 全屏模式
     *
     * @param context
     * @param bg
     */
    public MyPopWindow(Activity context, int bg, int animatorModel) {
        activity = context;
        mBackGroundColor = bg;
        mWindowManager = context.getWindowManager();
        lp = new WindowManager.LayoutParams();
        lp.format = PixelFormat.RGBA_8888;
        //透明狀態欄
        lp.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.MATCH_PARENT;
    }12345678910111213141516171234567891011121314151617

2.添加View,這裏注意不能重複添加

public void addView(View view) {
        this.contentView = view;
        if (mWindowManager == null) return;
        //當View已經被加到Window上去了,那麼就不能再加
        if (isAttachedToWindow(contentView) || contentView.getParent() != null) return;
        mWindowManager.addView(contentView, lp);
        if (contentView instanceof WindowLayout){
            ((WindowLayout)contentView).setPopWindow(this);
        }
    }1234567891012345678910

反射獲得isAttachedToWindow的值

 /**
     * 通過反射獲取View是否AttachWindow
     *
     * @param view
     */
    public boolean isAttachedToWindow(View view) {

        try {
            Class classzz = View.class;
            Field field = classzz.getDeclaredField("mAttachInfo");
            field.setAccessible(true);
            Object mAttach = field.get(view);
            return mAttach != null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }1234567891011121314151617181912345678910111213141516171819

3.remove

public void removeView() {
        try {
            if (mWindowManager == null) return;
            if (!isAttachedToWindow(contentView)) return;
            mWindowManager.removeView(contentView);
        } catch (Exception e) {
            if (Config.IS_DEBUG_MODE) {
                e.getMessage();
            }
        }

    }123456789101112123456789101112

4.回收防止window的泄露,Activity在銷燬之前要調用recycle方法

  /**
     * 回收
     */
    public void recycle() {
        activity = null;
        mWindowManager = null;
    }12345671234567

封裝DialogWindow

1.初始化構造方法

 public DialogWindow(Activity activity) {
        this.context = activity;
        myPopWindow = new MyPopWindow(activity);
    }

    public DialogWindow(Activity context, boolean isCancelable) {
        this.context = context;
        this.isCancelable = isCancelable;
        myPopWindow = new MyPopWindow(context);
    }1234567891012345678910

2.加載佈局

 public DialogWindow loading() {
        contentView = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.dialog_update, null);
        contentView.setOnClickListener(this);
        return this;
    }

    public DialogWindow loading(String tip) {
        contentView = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.dialog_update, null);
        TextView title = (TextView) contentView.findViewById(R.id.dialog_title);
        title.setText(tip);
        contentView.setOnClickListener(this);
        return this;
    }

    public void setTitle(String tip) {
        if (contentView == null) return;
        TextView title = (TextView) contentView.findViewById(R.id.dialog_title);
        title.setText(tip);
        isNeedReset = true;
    }

    public void resetTitle() {
        if (contentView == null) return;
        TextView title = (TextView) contentView.findViewById(R.id.dialog_title);
        title.setText(R.string.loading);
        isNeedReset = false;
    }

    public ViewGroup loading(@LayoutRes int resId) {
        contentView = (ViewGroup) LayoutInflater.from(context).inflate(resId, null);
        contentView.setOnClickListener(this);
        return contentView;
    }123456789101112131415161718192021222324252627282930313233123456789101112131415161718192021222324252627282930313233

3.show方法

    /**
     * 這你在show()的時候要判斷當前的狀態,
     */
    public void show() {
        Logger.e("tag", isShowing + "");
        if (!isShowing()) {
            try {
                myPopWindow.removeView();
                myPopWindow.addView(contentView);
                isShowing = true;
            } catch (Exception e) {
                if (Config.IS_DEBUG_MODE) {
                    Log.e("Window", e.toString());
                }
            }
        } else {
            handler.removeMessages(WHAT);
            dismissByUser();
            show();
        }
    }

    /**
     *
     */
    public void show(String tip) {
        Logger.e("tag", isShowing + "");
        if (!isShowing()) {
            try {
                if(!StringUtil.isEmpty(tip)){
                    setTitle(tip);
                }
                myPopWindow.addView(contentView);
                isShowing = true;
            } catch (Exception e) {
                if (Config.IS_DEBUG_MODE) {
                    Log.e("Window", e.toString());
                }
            }
        } else {
            handler.removeMessages(WHAT);
            dismissByUser();
            show(tip);
        }
    }123456789101112131415161718192021222324252627282930313233343536373839404142434445123456789101112131415161718192021222324252627282930313233343536373839404142434445

4.dismiss方法

  /**
     * 顯示,若果是網絡請求的話,就延遲500ms。
     */
    public void dismiss() {
        handler.sendEmptyMessageDelayed(WHAT, 500);
    }

    /**
     * 用戶點擊,就立刻取消
     */
    public void dismissByUser() {
        if (isShowing) {
            try {
                myPopWindow.removeView();
//                if (softReferenceListener.get()!=null){
//                    softReferenceListener.get().dialogDismiss();
//                }
                if (isNeedReset){
                    resetTitle();
                }
                isShowing = false;
            } catch (Exception e) {
                if (Config.IS_DEBUG_MODE) {
                    Log.e("Window", e.toString());
                }
            }
        }
    }12345678910111213141516171819202122232425262728291234567891011121314151617181920212223242526272829

5.用戶點擊處理

    /**
     * 用戶點擊window事件
     *
     * @param v
     */
    @Override
    public void onClick(View v) {
        if (isCancelable) {
            dismissByUser();
        }
    }12345678910111234567891011

6.回收防止window泄露

 public void recycle() {
        //先釋放Window裏面的Activity
        dismissByUser();
        if (myPopWindow != null) {
            myPopWindow.recycle();
            myPopWindow = null;
        }
    }1234567812345678

接收back事件

/**
 * 創建日期:2017/4/20 9:45
 *
 * @author yzz
 */
public class WindowLayout extends RelativeLayout {
    private MyPopWindow popWindow;
    public WindowLayout(Context context) {
        super(context);
    }

    public WindowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WindowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode()==KeyEvent.KEYCODE_BACK){
            if (popWindow!=null)popWindow.removeView();
        }
        return super.dispatchKeyEvent(event);
    }

    public void setPopWindow(MyPopWindow popWindow) {
        this.popWindow = popWindow;
    }
}12345678910111213141516171819202122232425262728293031321234567891011121314151617181920212223242526272829303132

總結

好,知道現在我們已經看完所有的源碼了,其實很簡單,就是我們拿到一塊window,那麼我們只要掌握其生命週期,然後我們就可以在這塊window上面繪製我們想要的一切。好了源碼由於一些原因就不上傳github了,有需要的可以聯繫我。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章