关于android里的Dialog

由做android应用到做android手机也有些时间了。总是觉得自己成长的太慢。

后仔细想来,自己没有好好总结。学而不思则罔。今天就来好好总结下android里面的Dialog。

相信大家,都对用Dialog十分熟悉。有两种方法,

一种是在Activity里调用showDialog(int),然后在Dialog onCreateDialog里创建Dialog返回,交由Activity来管理。

一种是自己直接用AlertDialog.Builder自己Create,然后自己调用show(),然后显示。

我把话先说在前头,建议用第一种方法去做,这会让你省去很多麻烦,因为Activity已经帮我们管理Dialog,做了很多有用的事情。

还有几个,很重要的概念,相信大家都也应该清楚:

1. 我们所有的应用程序所用到的dialog都是继承自AlertDialog的,包括ProgressDialog,TimePickerDialog,DatePickerDialog等。

2. Dialog不同于Activity,它有自己的Window。


接下来,我们从两种创建Dialog方法来分析吧。以ProgressDialog为例。

首先,我们来看下,ProgressDialog显示出来的几个部分吧。

总的来说,分三部分。

1. Message,Title,等。

2. 进度条,显示百分比的字符等。

3.下面被隐藏的Button。

为什么这么说呢。请跟我看代码,从第一种方法说起。即ActivitShowDialog(int)

public final void showDialog(int id) {
        showDialog(id, null);
    }
public final boolean showDialog(int id, Bundle args) {
        if (mManagedDialogs == null) {
            mManagedDialogs = new SparseArray<ManagedDialog>();
        }
        ManagedDialog md = mManagedDialogs.get(id);
        if (md == null) {
            md = new ManagedDialog();
            md.mDialog = createDialog(id, null, args);
            if (md.mDialog == null) {
                return false;
            }
            mManagedDialogs.put(id, md);
        }

        md.mArgs = args;
        onPrepareDialog(id, md.mDialog, args);
        md.mDialog.show();
        return true;
    }
 private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
        final Dialog dialog = onCreateDialog(dialogId, args);
        if (dialog == null) {
            return null;
        }
        dialog.dispatchOnCreate(state);
        return dialog;
    }
这里面可以很明显的看出来,Activity首先去列表里面去查找,看这个id的Dialog是否创建过,不存在就先调用createDialog(),创建dialog。否则就直接调用了onPrepareDialog,最后调用show()(这里面有文章,放在后面讲)。

我们也可以看到,在createDialog里面,先调用了onCreateDialog(),拿到dialog对象,然后去触发dialog的,onCreate函数。

这里一直没发现,我们设置的一些参数setMessage,setTitle,setButton去哪儿了。我们去ProgressDialog.onCreate看看吧。

   protected void onCreate(Bundle savedInstanceState) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        if (mProgressStyle == STYLE_HORIZONTAL) {

            /* Use a separate handler to update the text views as they
             * must be updated on the same thread that created them.
             */
            mViewUpdateHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);

                    /* Update the number and percent */
                    int progress = mProgress.getProgress();
                    int max = mProgress.getMax();
                    double percent = (double) progress / (double) max;
                    String format = mProgressNumberFormat;
                    mProgressNumber.setText(String.format(format, progress, max));
                    SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
                    tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
                            0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    mProgressPercent.setText(tmp);
                }
            };
            View view = inflater.inflate(R.layout.alert_dialog_progress, null);
            mProgress = (ProgressBar) view.findViewById(R.id.progress);
            mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
            mProgressNumberFormat = "%d/%d";
            mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
            mProgressPercentFormat = NumberFormat.getPercentInstance();
            mProgressPercentFormat.setMaximumFractionDigits(0);
            setView(view);
        } else {
            View view = inflater.inflate(R.layout.progress_dialog, null);
            mProgress = (ProgressBar) view.findViewById(R.id.progress);
            mMessageView = (TextView) view.findViewById(R.id.message);
            setView(view);
        }
............................
        setIndeterminate(mIndeterminate);
        onProgressChanged();
        super.onCreate(savedInstanceState);

        public Builder setView(View view) {
            P.mView = view;
            P.mViewSpacingSpecified = false;
            return this;
        }

可以看到ProgresDialog只是,做了个主要setView(),实际上就是给mView赋值,然后调用父类AlertDialog的onCreate。也来看看吧。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }
进入AlertController
    public void installContent() { 
        /* We use a custom title so never request a window title */
        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
     
        if (mView == null || !canTextInput(mView)) {
            mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }
        mWindow.setContentView(com.android.internal.R.layout.alert_dialog);
        setupView();
    }
private void setupView() {
        LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
        setupContent(contentPanel);
        boolean hasButtons = setupButtons();

        LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
        TypedArray a = mContext.obtainStyledAttributes(
                null, com.android.internal.R.styleable.AlertDialog, com.android.internal.R.attr.alertDialogStyle, 0);
        boolean hasTitle = setupTitle(topPanel);

        View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
        if (!hasButtons) {
            buttonPanel.setVisibility(View.GONE);
        }

        FrameLayout customPanel = null;
        if (mView != null) {
            customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
            FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
            custom.addView(mView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
            if (mViewSpacingSpecified) {
                custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
                        mViewSpacingBottom);
            }
            if (mListView != null) {
                ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
            }
        } else {
            mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE);
        }

        /* Only display the divider if we have a title and a 
         * custom view or a message.
         */
        if (hasTitle && ((mMessage != null) || (mView != null))) {
            View divider = mWindow.findViewById(R.id.titleDivider);
            divider.setVisibility(View.VISIBLE);
    。。。。。。
看到了吗?我们前面的mView只是整个Dialog的一部分而已。 

好了,我们来总结下,这第一种创建方法的顺序吧。showDialog()------->createDialog()---------------->onCreateDialog()---------->onCreate()--------------->setupView()-------------->onPrepareDialog()-------------->show().

接下来,我们再来看看,第二创建方法吧。

  AlertDialog.Builder builder = new Builder(Main.this);
  builder.setMessage("确认退出吗?");
  builder.setTitle("提示");
  builder.setPositiveButton("确认", new OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
    Main.this.finish();
   }
  });
  builder.setNegativeButton("取消", new OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
   }
  });
  builder.create().show();

 public AlertDialog create() {
            final AlertDialog dialog = new AlertDialog(P.mContext);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            dialog.setOnCancelListener(P.mOnCancelListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }


看到没有。create完,直接调show().

那我不知道你们没有同样的疑问。像我们第一种方法里,像Title,Message,mView都是在AlertDialog的onCreate()里面放进去的。那我们又没有调用onCreate()函数,他们最后是怎样显示出来的呢?

呵呵。我们最后来看看

builder.create()产生的是AlertDialog对象,但它自己没有定义show().最后调到了Dialog.show()
 public void show() {
        if (mShowing) {
            if (mDecor != null) {
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        if (!mCreated) {
            dispatchOnCreate(null);
        }

        onStart();
        mDecor = mWindow.getDecorView();
        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }

        try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;

            sendShowMessage();
        } finally {
        }
    }

看到这里。为什么Tilte,message,为什么会出现,知道了吧。
第二种方法的流程是这样的。
show()------------>onCreat()----------->setupView().






总算简要的分析完了。
提个问题。如果,你想修改Dialog,title的字体,是不是只能在onPrepareDialog()里面来做啊?第二种方法是不是做不到啊?




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值