打造属于自己的Dialog---仿安卓系统自带原生Dialog设计

前言:这个过程中遇到了两个问题,都比较基础,第一个问题是:系统无法识别图片资源,不过还好,被我删了之后就很好的运行了,第二个也是比较鬼畜的问题,错把==符号变成了!=结果导致闪退缺不报错!现在我们为什么要来这一个属于自己的dialog,原因很简单,安卓自带的太丑了!!!而且局限性强,那么为了解决这个问题,分开view与逻辑,更方便的进行拓展下面我们需要用一个非常常见的设计模式builder!


buidler设计模式:一个比方——组装电脑,一系列产品的电脑,可以有不同的配置,不同的cpu,不同的arm,一个电脑最后的模样是取决于各个配件的组合,同样的道理,我们在使用dialog的过程中也会有这样那样的需求,因此,1.为了更灵活的去运用dialog,实现更多样化。2.为了易拓展,view与实现逻辑分开!等…



具体需要的类有三个,DialogViewhelper(辅助类存在),AlertDialog,AerltController




1,AerltDialog类:继承了Dialog(值得注意的是这里继承的只是Dialog而非AlertDialog),这里具体的一些思路是,构造函数出来,然后new一个AlertController出来然后,设置一些传递参数用的方法如:setText和getview这些,当然主要的还是builder里面的内容是直接仿安卓源码的,将数据放入P中,然后进行传递!当然这里最好加上一个通过id去寻找的setContextView,同时值得注意的是,无论是文本还是事件不止只有一个,所以用SparseArray储存起来!为什么要使用这个呢,很简单在安卓源码里头,有一句英语表明了如果是键值对为int加值的这种,这个比hasmp更优越!

package com.example.baselibrary.baseActvity.dialog;

import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import com.example.baselibrary.R;


/**
 * Created by 廖成康 on 2017/4/26.
 */

public class AlertDialog extends Dialog
{
    private AlertController mAlert;


    public AlertDialog(Context context, int themeResId)
    {
        super(context, themeResId);

        mAlert= new AlertController(this,getWindow());
    }

    /**
     * 设置文本
     * @param ResId
     * @param text
     */

    public void setText(int ResId,CharSequence text)
    {
       mAlert.setText(ResId,text);
    }

    /**
     * 设置getView方法
     * @param ResId
     * @param <T>
     * @return
     */

    public <T extends View> T getView(int ResId)
    {
        return mAlert.getView(ResId);
    }


    /**
     * 设置点击事件
     *
     * @param ResId
     * @param listener
     */
    public void   setOnClickLisnter(int ResId,View.OnClickListener listener)
    {
        mAlert.setOnClickLisnter(ResId,listener);
    }


    public static class Builder
    {
        public final AlertController.AlertParams P;

        /**
         * Creates a builder for an alert dialog that uses the default alert
         * dialog theme.
         * <p/>
         * The default alert dialog theme is defined by
         * {@link android.R.attr#alertDialogTheme} within the parent
         * {@code context}'s theme.
         *
         * @param context the parent context
         */
        public Builder(Context context)
        {
            this(context, R.style.dialog);
        }


        /**
         * Creates a builder for an alert dialog that uses an explicit theme
         * resource.
         * <p/>
         * The specified theme resource ({@code themeResId}) is applied on top
         * of the parent {@code context}'s theme. It may be specified as a
         * style resource containing a fully-populated theme, such as
         * {@link android.R.style#Theme_Material_Dialog}, to replace all
         * attributes in the parent {@code context}'s theme including primary
         * and accent colors.
         * <p/>
         * To preserve attributes such as primary and accent colors, the
         * {@code themeResId} may instead be specified as an overlay theme such
         * as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will
         * override only the window attributes necessary to style the alert
         * window as a dialog.
         * <p/>
         * Alternatively, the {@code themeResId} may be specified as {@code 0}
         * to use the parent {@code context}'s resolved value for
         * {@link android.R.attr#alertDialogTheme}.
         *
         * @param context    the parent context
         * @param themeResId the resource ID of the theme against which to inflate
         *                   this dialog, or {@code 0} to use the parent
         *                   {@code context}'s default alert dialog theme
         */
        public Builder(Context context, int themeResId)
        {
            P =new AlertController.AlertParams(context,themeResId);
        }

        /**
         * Sets a custom view to be the contents of the alert dialog.
         * <p/>
         * When using a pre-Holo theme, if the supplied view is an instance of
         * a {@link ListView} then the light background will be used.
         * <p/>
         * <strong>Note:</strong> To ensure consistent styling, the custom view
         * should be inflated or constructed using the alert dialog's themed
         * context obtained via {@link #getContext()}.
         *
         * @param view the view to use as the contents of the alert dialog
         * @return this Builder object to allow for chaining of calls to set
         * methods
         */
        public Builder setContextView(View view) {
            P.mView = view;
            P.mViewLayoutResId = 0;
            return this;
        }


        /**
         * 设置布局Id
         * @param ResId
         * @return
         */

        public Builder setContextView(int ResId){
            P.mView=null;
            P.mViewLayoutResId=ResId;
            return this;
        }


        /**
         * 设置文本
         * @param ResId
         * @param text
         * @return
         */

        public Builder setText( int ResId,CharSequence text)
        {
            P.mTextArray.put(ResId,text);
            return this;
        }

        /**
         * 设置点击事件
          * @param view
         * @param listener
         * @return
         */
        public Builder setOnClickLisnter(int view,View.OnClickListener listener)
        {
            P.mClickArray.put(view,listener);
            return this;

        }

        /**
          * 设置宽度
          * @return
         */
       public Builder fullWidth()
       {
           P.mWidth= ViewGroup.LayoutParams.MATCH_PARENT;
           return this;
       }


        public Builder fromButton(boolean isAnimation)
        {
            if (isAnimation)
            {
               P.mAnimations=R.style.dialog_from_bottom_anim;
            }

            P.mGrivity= Gravity.BOTTOM;

            return this;
        }

        /**
         * 设置Dialog的宽高
         * @param width
         * @param height
         * @return
         */
        public Builder setWidthAndHeight(int width, int height){
            P.mWidth = width;
            P.mHeight = height;
            return this;
        }

        /**
         * 添加默认动画
         * @return
         */
        public Builder addDefaultAnimation(){
            P.mAnimations = R.style.dialog_scale_anim;
            return this;
        }

        /**
         * 设置动画
         * @param styleAnimation
         * @return
         */
        public Builder setAnimations(int styleAnimation){
            P.mAnimations = styleAnimation;
            return this;
        }

        /**
         * Sets whether the dialog is cancelable or not.  Default is true.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setCancelable(boolean cancelable) {
            P.mCancelable = cancelable;
            return this;
        }

        /**
         * Sets the callback that will be called if the dialog is canceled.
         *
         * <p>Even in a cancelable dialog, the dialog may be dismissed for reasons other than
         * being canceled or one of the supplied choices being selected.
         * If you are interested in listening for all cases where the dialog is dismissed
         * and not just when it is canceled, see
         * {@link #setOnDismissListener(android.content.DialogInterface.OnDismissListener) setOnDismissListener}.</p>
         * @see #setCancelable(boolean)
         * @see #setOnDismissListener(android.content.DialogInterface.OnDismissListener)
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
            P.mOnCancelListener = onCancelListener;
            return this;
        }

        /**
         * Sets the callback that will be called when the dialog is dismissed for any reason.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setOnDismissListener(OnDismissListener onDismissListener) {
            P.mOnDismissListener = onDismissListener;
            return this;
        }

        /**
         * Sets the callback that will be called if a key is dispatched to the dialog.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setOnKeyListener(OnKeyListener onKeyListener) {
            P.mOnKeyListener = onKeyListener;
            return this;
        }


        /**
         * Creates an {@link AlertDialog} with the arguments supplied to this
         * builder.
         * <p/>
         * Calling this method does not display the dialog. If no additional
         * processing is needed, {@link #show()} may be called instead to both
         * create and display the dialog.
         */
        public AlertDialog create() {
            // Context has already been wrapped with the appropriate theme.
            final AlertDialog dialog = new AlertDialog(P.mContext, P.mThemeResId);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }


        /**
         * Creates an {@link AlertDialog} with the arguments supplied to this
         * builder and immediately displays the dialog.
         * <p/>
         * Calling this method is functionally identical to:
         * <pre>
         *     AlertDialog dialog = builder.create();
         *     dialog.show();
         * </pre>
         */
        public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }


    }

}


2.AlertContorller:
这个类里面我们是给了一系列参数了的,那么这个类是干什么的呢很简单,传过来的参数传到vieqhelper里面进行实现,当然,在这个过程中,我们需要做一些优化,比如说,我们需要做,一些参数在值上默认,容错等等,这些就不具体将了注视里面相当清楚了,
而我这里主要实现了什么东西呢?1.设置文本,2.设置监听事件,3.配置全屏  从底部弹出,动画等!!
package com.example.baselibrary.baseActvity.dialog;

import android.content.Context;
import android.content.DialogInterface;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;

/**
 * Created by 廖成康 on 2017/4/26.
 */

class AlertController
{
    private DialogViewHelper mdialogViewHelper;

    private AlertDialog malertDialog;

    private Window mwindow;




    public AlertController(AlertDialog alertDialog, Window window)
    {
            this.malertDialog=alertDialog;
            this.mwindow=window;
    }


    public void setMdialogViewHelper(DialogViewHelper dialogViewHelper)
    {
       this.mdialogViewHelper=dialogViewHelper;
    }


    /***
     *
     * 设置文本
     *
     * 具体实现在DialogViewHelper
     *
     * @param resId
     * @param text
     */


    public  void setText(int resId, CharSequence text)
    {
     mdialogViewHelper.setText(resId,text);
    }

    /**
     * 设置获取得到View
     *
     * @param resId
     * @param <T>
     * @return
     */

    public <T extends View> T getView(int resId)
    {
        return mdialogViewHelper.getView(resId);
    }


    /**
     * 设置点击事件
     *
     * @param resId
     * @param listener
     */
    public void setOnClickLisnter(int resId, View.OnClickListener listener) {
    mdialogViewHelper.setOnClickLisnter(resId,listener);
    }

    /**
     * 获取得到dialog
     *
     * @return
     */

    public AlertDialog getMalertDialog()
    {
        return malertDialog;
    }

    /**
     * 获取得到window
     *
     *
     * @return
     */

    public Window getMwindow()
    {
        return mwindow;
    }


    /**
     * 一个媒介,从AlertDialog里面得到参数
     *
     */

    public static class AlertParams
    {
        public View mView;
        //布局的Id
        public int mViewLayoutResId;
        ///上下文
        public Context mContext;
        ///主题的Id
        public int mThemeResId;
        ///点击空白处是否取消
        public boolean mCancelable=true;
        ///三个参数
        public DialogInterface.OnCancelListener mOnCancelListener;
        public DialogInterface.OnDismissListener mOnDismissListener;
        public DialogInterface.OnKeyListener mOnKeyListener;
        // 存放字体的修改
        public SparseArray<CharSequence> mTextArray = new SparseArray<>();
        // 存放点击事件
        public SparseArray<View.OnClickListener> mClickArray = new SparseArray<>();

        ///设置宽度 自定义参数
        public int mWidth= ViewGroup.LayoutParams.WRAP_CONTENT;

        //设置位置 自定义参数
        public int mGrivity= Gravity.CENTER;

        //设置高度 自定义参数
        public int mHeight=ViewGroup.LayoutParams.WRAP_CONTENT;

        //设置动画
        public int mAnimations=0;

        public AlertParams(Context context,int mThemeResId)
        {
                this.mContext=context;
                this.mThemeResId=mThemeResId;
        }


        public void apply(AlertController mAlert)
        {
           ///完善需要设置一些参数

          //1.DialogViewhelper设置view布局
            DialogViewHelper viewHelper=null;
            if (mViewLayoutResId!=0)
            {
                viewHelper=new DialogViewHelper(mContext,mViewLayoutResId);
            }

            //2.设置view
            if (mView!=null)
            {
                viewHelper=new DialogViewHelper();
                viewHelper.setContextView(mView);
            }

            //容错处理
            if (viewHelper==null)
            {
                throw new IllegalArgumentException("还没有设置布局");
            }

            ///继承的是Dialog
            mAlert.getMalertDialog().setContentView(viewHelper.getmContextView());

             ///给辅助类设置viewhelper,对上面传参数有必要
            mAlert.setMdialogViewHelper(viewHelper);

            //2.设置文本
            int mtextsize=mTextArray.size();
            for (int length=0;length<mtextsize;length++)
            {
             mAlert.setText(mTextArray.keyAt(length),mTextArray.valueAt(length));
            }

            ///设置监听事件
            int  mclicksize=mClickArray.size();
            for (int i=0;i<mclicksize;i++)
            {
                mAlert.setOnClickLisnter(mClickArray.keyAt(i),mClickArray.valueAt(i));
            }

             ///配置自定义效果 全屏 从底部弹出 动画

            Window window=mAlert.getMwindow();
            window.setGravity(mGrivity);

            ///设置懂动画

            if (mAnimations!=0)
            {
                window.setWindowAnimations(mAnimations);
            }

            WindowManager.LayoutParams params=window.getAttributes();
            params.width=mWidth;
            params.height=mHeight;
            window.setAttributes(params);

        }
    }
}
3.最后,这个类里面就是我们实现的最后的目的了,这里面有一个叫软应用的,用来防止一些情况的发生所使用的,值得注意一下,
当然这个类并不是说只有它才实现而已,前面的第二个类也已经实现了一些功能,这里的话主要实现的是设置文本和设置点击事件!这两



package com.example.baselibrary.baseActvity.dialog;

/**
 * Created by 廖成康 on 2017/4/26.
 */

import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import java.lang.ref.WeakReference;

/**
 * Dialog 作为View的辅助类
 *
 */


class DialogViewHelper
{
    private View mContextView=null;

    //// 防止霸气侧漏

    private SparseArray<WeakReference<View>> mView;


    public DialogViewHelper(Context context,int viewId)
    {
     this();
     mContextView= LayoutInflater.from(context).inflate(viewId,null);
    }

    public DialogViewHelper()
    {
    mView=new SparseArray<>();
    }

    /**
     * 设置布局
     * @param context
     */

    public void setContextView(View context)
    {
       this.mContextView=context;
    }


    /**
     * 获取布局
     *
     */

    public View getmContextView()
    {
       return mContextView;
    }


       public <T extends View> T getView(int viewId)
       {
           WeakReference<View> viewWeakReference=mView.get(viewId);
           //侧漏问题
           View view=null;
           if (viewWeakReference!=null)
           {
               view=viewWeakReference.get();

           }
           if (view==null)
           {
               view=mContextView.findViewById(viewId);
               if (view==null)
               {
                   mView.put(viewId,new WeakReference<View>(view));
               }
           }
           return (T) view;
       }


    /**
     * 设置文本
     * @param resId
     * @param text
     */

    public void setText(int resId,CharSequence text)
    {
     TextView textView=getView(resId);
     if (textView!=null)
     {
         textView.setText(text);
     }
    }


    /**
     * 设置点击事件
     *
     * @param ResId
     * @param listener
     */

    public void setOnClickLisnter(int ResId,View.OnClickListener listener)
    {
        View view=getView(ResId);
        if (view!=null)
        {
             view.setOnClickListener(listener);
        }
    }
}
到这里,资源这些的话,如果想要在联系我吧1269729771扣扣号!!!!今天要早睡了








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值