天天看点

禁用AlertDialog的按钮

由于业务要求,需要在弹出AlertDialog的时候,将其中的一个按钮置为灰色,即禁用点击功能。下面是具体的实现方法,一个Demo

布局很简单,一个按钮,点击后弹出禁用按钮的AlertDialog,就不放代码了。

主要说一下有关禁用方面的话题

class MyOnClickListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            builder = new AlertDialog.Builder(context);
            builder.setTitle("对话框");
            builder.setMessage("显示对话框,并将禁用按钮");
            builder.setPositiveButton("确定", null);
            builder.setNegativeButton("取消", null);
            dialog = builder.create();

            // 必须要先显示对话框,再从里面获取Button,否则得到的Button为null
            // 可以把下面这行注释掉实验一下,将打印null的LOG
            dialog.show();
            
            Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
            if(null==button){
                Log.i("carter", "button is null");
            }else{
                button.setEnabled(false);
            }
        }
        
    }
           

这里面有个很重要的地方需要说明一下,如果想得到里面的Button,单单执行dialog = builder.create();和button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);是不够的,会返回一个null的button,必须要先调用dialog.show();方法 后再获取BUtton,具体的原因不是很清楚,可能得去看源代码了

看了Jelly Bean的源码,大概了解的实现的过程。下面简单分析下:

1、调用AlertDialog.show()方法,实际上是调用Dialog.show()方法

2、在show()方法中,会判断是否已经显示,如果是则返回;没有显示则执行dispatchOnCreate(null)方法

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

3、在dispatchOnCreate()方法中会去执行onCreate()方法,而这个onCreate()方法是由AlertDialog类具体实现的。在方法的注释中写着“内部方法,把mcreated设置成合适的值,而不需要用户调用super类中的onCreate方法”

// internal method to make sure mcreated is set properly without requiring
    // users to call through to super in onCreate
    void dispatchOnCreate(Bundle savedInstanceState) {
        if (!mCreated) {
            onCreate(savedInstanceState);
            mCreated = true;
        }
    }
           

4、在AlertDialog的onCreate()方法中,去调用mAlert.installContent()方法。mAlert是一个AlertController类,位于android.internal.app包中。installContent方法,我的理解就是通过AlertController去装载需要显示的内容。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }
           

5、在AlertController的installContent()方法中,会去执行setupView()方法,去创建、设置需要显示的组件

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(mAlertDialogLayout);
        setupView();
    }
           

6、在setupView()方法中,会先去加载设置显示的内容,比如提示的信息什么的,

LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
        setupContent(contentPanel);
           

在setupContent()方法中,获取了一个ScrollView,可以滚动显示加载的内容。这里跟Button无关,可以简单看下,知道就行了。

private void setupContent(LinearLayout contentPanel) {
        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
        mScrollView.setFocusable(false);
        
        // Special case for users that only want to display a String
        mMessageView = (TextView) mWindow.findViewById(R.id.message);
        if (mMessageView == null) {
            return;
        }
        
        if (mMessage != null) {
            mMessageView.setText(mMessage);
        } else {
            mMessageView.setVisibility(View.GONE);
            mScrollView.removeView(mMessageView);
            
            if (mListView != null) {
                contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
                contentPanel.addView(mListView,
                        new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
                contentPanel.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f));
            } else {
                contentPanel.setVisibility(View.GONE);
            }
        }
    }
           

7、设置完这些要显示的信息后,就会继续在setupView()方法中加载Button了,关键的地方终于来了。

boolean hasButtons = setupButtons();
           

8、在setupButtons()方法中,就会一个个的去生成这些Button,设置监听器、显示的内容等信息。

private boolean setupButtons() {
        int BIT_BUTTON_POSITIVE = 1;
        int BIT_BUTTON_NEGATIVE = 2;
        int BIT_BUTTON_NEUTRAL = 4;
        int whichButtons = 0;
        mButtonPositive = (Button) mWindow.findViewById(R.id.button1);
        mButtonPositive.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mButtonPositiveText)) {
            mButtonPositive.setVisibility(View.GONE);
        } else {
            mButtonPositive.setText(mButtonPositiveText);
            mButtonPositive.setVisibility(View.VISIBLE);
            whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
        }

        mButtonNegative = (Button) mWindow.findViewById(R.id.button2);
        mButtonNegative.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mButtonNegativeText)) {
            mButtonNegative.setVisibility(View.GONE);
        } else {
            mButtonNegative.setText(mButtonNegativeText);
            mButtonNegative.setVisibility(View.VISIBLE);

            whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
        }

        mButtonNeutral = (Button) mWindow.findViewById(R.id.button3);
        mButtonNeutral.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mButtonNeutralText)) {
            mButtonNeutral.setVisibility(View.GONE);
        } else {
            mButtonNeutral.setText(mButtonNeutralText);
            mButtonNeutral.setVisibility(View.VISIBLE);

            whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
        }

        if (shouldCenterSingleButton(mContext)) {
            /*
             * If we only have 1 button it should be centered on the layout and
             * expand to fill 50% of the available space.
             */
            if (whichButtons == BIT_BUTTON_POSITIVE) {
                centerButton(mButtonPositive);
            } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
                centerButton(mButtonNeutral);
            } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
                centerButton(mButtonNeutral);
            }
        }
        
        return whichButtons != 0;
    }
           

9、执行完上面这些,Content和Button就都被初始化完成了,所以也就验证了为什么在没有调用show()方法之前,返回的Button会是null的问题。