Android进阶——自定义View之扩展系统Dialog

引言

今天给大家总结有关自定义对话框的相关内容,前面文章Android入门——AlertDialog和ProgressDialog总结都在在利用系统提供的函数来实现对话框,但局限性太大,当我们想自己定义Dialog视图的时候,就不能利用系统函数了,就需要我们这里的自定义对话框了来满足产品经理的各种idea。

一、Dialog部分源码结构

学习下源码的编程风格和规范


/**
 * Base class for Dialogs.
 * Activity提供了一系列的方法用于dialog的管理:onCreateDialog(int)、onPrepareDialog(int)、showDialog(int)、dismissDialog(int)、
 *当这些方法被调用之后我们就可以通过 getOwnerActivity()方法获取得到对应的Dialog依附的Activity
 *
 *设置在Dialog中隐藏软键盘
 * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
 *         WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
 */
public class Dialog implements DialogInterface, Window.Callback,
        KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {

    private Activity mOwnerActivity;
    final Context mContext;
    final WindowManager mWindowManager;
    Window mWindow;
    View mDecor;
    private ActionBar mActionBar;
    protected boolean mCancelable = true;
    private String mCancelAndDismissTaken;
    private Message mCancelMessage,mDismissMessage,mShowMessage;

    private OnKeyListener mOnKeyListener;
    private boolean mCreated = false,mShowing = false,mCanceled = false;
    private final Handler mHandler = new Handler();
    private static final int DISMISS = 0x43,CANCEL = 0x44,SHOW = 0x45;
    private Handler mListenersHandler;

    private SearchEvent mSearchEvent;
    private ActionMode mActionMode;

    private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;

    private final Runnable mDismissAction = new Runnable() {
        public void run() {
            dismissDialog();
        }
    };

    public Dialog(@NonNull Context context) {
        this(context, 0, true);
    }

    public Dialog(@NonNull Context context, @StyleRes int themeResId) {
        this(context, themeResId, true);
    }

    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == 0) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }

    /**
     * @deprecated
     * @hide
     */
    @Deprecated
    protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
        this(context);
        mCancelable = cancelable;
        mCancelMessage = cancelCallback;
    }

    protected Dialog(@NonNull Context context, boolean cancelable,
            OnCancelListener cancelListener) {
        this(context);
        mCancelable = cancelable;
        setOnCancelListener(cancelListener);
    }

    /**
     * Retrieve the Context this Dialog is running in.
     * @return Context The Context used by the Dialog.
     */
    @NonNull
    public final Context getContext() {
        return mContext;
    }
    /**
     * Sets the Activity that owns this dialog. An example use: This Dialog will
     * use the suggested volume control stream of the Activity.
     * @param activity The Activity that owns this dialog.
     */
    public final void setOwnerActivity(Activity activity) {
        mOwnerActivity = activity;
        getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
    }

    /**
     * Returns the Activity that owns this Dialog. For example, if
     * {@link Activity#showDialog(int)} is used to show this Dialog, that
     * Activity will be the owner (by default). Depending on how this dialog was
     * created, this may return null.
     *
     * @return The Activity that owns this Dialog.
     */
    public final Activity getOwnerActivity() {
        return mOwnerActivity;
    }

    public boolean isShowing() {
        return mShowing;
    }
    public void create() {
        if (!mCreated) {
            dispatchOnCreate(null);
        }
    }
    public void show() {
        if (DBG) {
            Log.d(TAG, "show");
        }

        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;

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

        onStart();
        mDecor = mWindow.getDecorView();

        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        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 {
        }
    }

    /**
     * Hide the dialog, but do not dismiss it.
     */
    public void hide() {
        if (mDecor != null) {
            mDecor.setVisibility(View.GONE);
        }
    }

    /**
     * 关闭并删除Dialog,线程安全,不能重写
     */
    @Override
    public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else {
            mHandler.post(mDismissAction);
        }
    }
    void dismissDialog() {
        if (DBG) {
            Log.d(TAG, "dismissDialog");
        }
        if (mDecor == null || !mShowing) {
            return;
        }
        if (mWindow.isDestroyed()) {
            Log.e(TAG, "Tried to dismissDialog() but the Dialog‘s window was already destroyed!");
            return;
        }
        try {
            mWindowManager.removeViewImmediate(mDecor);
        } finally {
            if (mActionMode != null) {
                mActionMode.finish();
            }
            mDecor = null;
            mWindow.closeAllPanels();
            onStop();
            mShowing = false;
            sendDismissMessage();
        }
    }

    private void sendDismissMessage() {
        if (mDismissMessage != null) {
            Message.obtain(mDismissMessage).sendToTarget();
        }
    }

    private void sendShowMessage() {
        if (mShowMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mShowMessage).sendToTarget();
        }
    }

    /**
     *与Activity的类似,初始化Dialog,包括调用 setContentView
     *如果Dialog在Activity之前关闭,那么会调用onSaveInstanceState保留状态
     * @param savedInstanceState If this dialog is being reinitalized after a
     */
    protected void onCreate(Bundle savedInstanceState) {
    }

    /**
     * Called when the dialog is starting.
     */
    protected void onStart() {
        if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
    }

    /**
     * Called to tell you that you‘re stopping.
     */
    protected void onStop() {
        if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
    }

    private static final String DIALOG_SHOWING_TAG = "android:dialogShowing";
    private static final String DIALOG_HIERARCHY_TAG = "android:dialogHierarchy";

    public Bundle onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
        if (mCreated) {
            bundle.putBundle(DIALOG_HIERARCHY_TAG, mWindow.saveHierarchyState());
        }
        return bundle;
    }
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
        if (dialogHierarchyState == null) {
            // dialog has never been shown, or onCreated, nothing to restore.
            return;
        }
        dispatchOnCreate(savedInstanceState);
        mWindow.restoreHierarchyState(dialogHierarchyState);
        if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) {
            show();
        }
    }
    public Window getWindow() {
        return mWindow;
    }
    public View getCurrentFocus() {
        return mWindow != null ? mWindow.getCurrentFocus() : null;
    }

    @Nullable
    public View findViewById(@IdRes int id) {
        return mWindow.findViewById(id);
    }

    public void setContentView(@LayoutRes int layoutResID) {
        mWindow.setContentView(layoutResID);
    }
    public void setContentView(View view) {
        mWindow.setContentView(view);
    }
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        mWindow.setContentView(view, params);
    }
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        mWindow.addContentView(view, params);
    }
    public void setTitle(CharSequence title) {
        mWindow.setTitle(title);
        mWindow.getAttributes().setTitle(title);
    }
    public void setTitle(@StringRes int titleId) {
        setTitle(mContext.getText(titleId));
    }
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            event.startTracking();
            return true;
        }

        return false;
    }
    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
        return false;
    }
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
                && !event.isCanceled()) {
            onBackPressed();
            return true;
        }
        return false;
    }
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
        return false;
    }
    public void onBackPressed() {
        if (mCancelable) {
            cancel();
        }
    }

    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
        return false;
    }
    public boolean onTouchEvent(MotionEvent event) {
        if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
            cancel();
            return true;
        }

        return false;
    }
    public boolean onTrackballEvent(MotionEvent event) {
        return false;
    }
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (mDecor != null) {
            mWindowManager.updateViewLayout(mDecor, params);
        }
    }

    public void onContentChanged() {
    }

    public void onWindowFocusChanged(boolean hasFocus) {
    }

    public void onAttachedToWindow() {
    }

    public void onDetachedFromWindow() {
    }

    /** @hide */
    @Override
    public void onWindowDismissed() {
        dismiss();
    }

    /**
     * 事件传递 :用于处理各种事件,我们可以重写key events在传递到window之前
     * @param event The key event.
     */
    public boolean dispatchKeyEvent(KeyEvent event) {
        if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
            return true;
        }
        if (mWindow.superDispatchKeyEvent(event)) {
            return true;
        }
        return event.dispatch(this, mDecor != null
                ? mDecor.getKeyDispatcherState() : null, this);
    }
    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
        if (mWindow.superDispatchKeyShortcutEvent(event)) {
            return true;
        }
        return onKeyShortcut(event.getKeyCode(), event);
    }
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mWindow.superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    public final boolean requestWindowFeature(int featureId) {
        return getWindow().requestFeature(featureId);
    }
    public final void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
        getWindow().setFeatureDrawableResource(featureId, resId);
    }
    public final void setFeatureDrawableUri(int featureId, Uri uri) {
        getWindow().setFeatureDrawableUri(featureId, uri);
    }
    public final void setFeatureDrawable(int featureId, Drawable drawable) {
        getWindow().setFeatureDrawable(featureId, drawable);
    }
    public final void setFeatureDrawableAlpha(int featureId, int alpha) {
        getWindow().setFeatureDrawableAlpha(featureId, alpha);
    }

    public LayoutInflater getLayoutInflater() {
        return getWindow().getLayoutInflater();
    }
    /**
     *各种监听器
     **/
    public void setOnCancelListener(final OnCancelListener listener) {
        if (mCancelAndDismissTaken != null) {
            throw new IllegalStateException(
                    "OnCancelListener is already taken by "
                    + mCancelAndDismissTaken + " and can not be replaced.");
        }
        if (listener != null) {
            mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);
        } else {
            mCancelMessage = null;
        }
    }
    public void setOnDismissListener(final OnDismissListener listener) {
        if (mCancelAndDismissTaken != null) {
            throw new IllegalStateException(
                    "OnDismissListener is already taken by "
                    + mCancelAndDismissTaken + " and can not be replaced.");
        }
        if (listener != null) {
            mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);
        } else {
            mDismissMessage = null;
        }
    }
    public void setOnShowListener(OnShowListener listener) {
        if (listener != null) {
            mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
        } else {
            mShowMessage = null;
        }
    }
    /**
     * Sets the callback that will be called if a key is dispatched to the dialog.
     */
    public void setOnKeyListener(final OnKeyListener onKeyListener) {
        mOnKeyListener = onKeyListener;
    }
    private static final class ListenersHandler extends Handler {
        private WeakReference<DialogInterface> mDialog;

        public ListenersHandler(Dialog dialog) {
            mDialog = new WeakReference<DialogInterface>(dialog);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DISMISS:
                    ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
                    break;
                case CANCEL:
                    ((OnCancelListener) msg.obj).onCancel(mDialog.get());
                    break;
                case SHOW:
                    ((OnShowListener) msg.obj).onShow(mDialog.get());
                    break;
            }
        }
    }
}

二、扩展系统Dialog步骤

  • 定义Dialog将要显示的布局xml文件
  • 继承Dialog 并实现相关的构造方法
  • 重写相关父类的生命周期方法,比如说在onCreate里通过LayoutInflater的LayoutInflater对象的inflate方法把xml布局文件映射成为自定义的view,获取我们自定义对话框的view,然后利用setContentView

1、实现普通的自定义Dialog

定义自定义Dialog 的布局xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        style="@style/TitleStyle"
        android:layout_width="match_parent"
        android:padding="5dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="自定义的Dialog"
        android:drawableLeft="@mipmap/ic_red_launcher"/>
    <ProgressBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

继承Dialog并实现相关构造方法并重写onCreate:

/**
 * Created by cmo on 16-5-5.
 */
public class MyCostomDialog extends Dialog {
    Context mContext;
    public MyCostomDialog(Context context) {
        super(context);
        mContext=context;
    }
    /**
    *另一种形式的使用Theme
    *    public MyCostomDialog(Context context){
        super(context,R.style.myCustomdialog);
        mContext=context;
    }
    */
    //使用到Theme时调用
    public MyCostomDialog(Context context, int theme) {
        super(context, theme);
        mContext = context;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.dialog_my_costom, null);
        this.setContentView(layout);
    }
}

styles.xml:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    <style name="TitleStyle">
        <item name="android:textColor">@color/colorGreen</item>
        <item name="android:textSize">@dimen/activity_title_size</item>
    </style>

    <!--
    android:windowFrame:界面对应的前景图片;
    android:background:背景图片
    android:windowIsFloating:表示浮在屏幕上的,如果在这里使用了,整个layout就会在 屏幕中心,相当于浮在屏幕上,所以这个只适用于dialog
    android:windowContentOverlay:表示标题栏的阴影部分的样式,使用图片或者颜色
    android:windowNoTitle:标题栏是否隐藏
    -->
    <style name="myCustomdialog" parent="android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:background">@drawable/shape_dialog_bcg</item>
    </style>
</resources>
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    //调用代码显示无Theme的Dialog
    public void showDialog(View view){
        MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this);
        ///MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this, R.style.myCustomdialog);显示自定义Theme的的Dialog
        dialog.show();
    }
}

2、显示具有交互功能的Dialog

布局很简单就不贴了,既然需要交互,那肯定得注册监听,so 参考Activity上的处理肯定是在界面初始化的时候设置对应的监听


/**
 * Created by cmo on 16-5-5.
 */
public class MyCostomDialog extends Dialog {
    Context mContext;

    public MyCostomDialog(Context context) {
        super(context);
        mContext=context;
    }
    //使用到Theme时调用
    public MyCostomDialog(Context context, int theme) {
        super(context, theme);
        mContext = context;
    }
    //设置RadioGroup的监听
    private void setRadioListener(final View view){
        final RadioGroup radioGroup= (RadioGroup) view.findViewById(R.id.id_radiogroup);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton checkedRadio=(RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());
                switch (checkedId){
                    case R.id.id_android_radiobtn:
                    case R.id.id_ios_radiobtn:
                    case R.id.id_java_radiobtn:
                         Log.d("TAG",checkedRadio.getText().toString());
                        break;
                    default:
                        break;
                }
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.dialog_my_costom, null);
        setRadioListener(layout);//设置监听
        this.setContentView(layout);
    }
}

3、与Activity之间的通信

3.1、通过构造函数把Activity里的数据传递至Dialog

package com.crazymo.costomstyledialog;
/**
 * Created by cmo on 16-5-5.
 */
public class MyCostomDialog extends Dialog {
    Context mContext;
    String mText;
    public MyCostomDialog(Context context) {
        super(context);
        mContext=context;
    }
    //使用到Theme时调用
    public MyCostomDialog(Context context, int theme) {
        super(context, theme);
        mContext = context;
    }
    //其中txt则是从Activity传递至DIalog的数据
    public MyCostomDialog(Context context, String txt,int theme) {
        super(context,theme);
        mContext = context;
        mText=txt;
    }

    private void setRadioListener(final View view){
        final RadioGroup radioGroup= (RadioGroup) view.findViewById(R.id.id_radiogroup);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton checkedRadio=(RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());
                switch (checkedId){
                    case R.id.id_android_radiobtn:
                    case R.id.id_ios_radiobtn:
                    case R.id.id_java_radiobtn:
                        Log.d("TAG", checkedRadio.getText().toString());
                        break;
                    default:
                        break;
                }
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.dialog_my_costom, null);
        setRadioListener(layout);
        TextView tv = (TextView)layout.findViewById(R.id.id_dialog_title_txt);
        tv.setText(mText);//设置Activity传递来的数据
        this.setContentView(layout);
    }
}

在MainActivity里显示:

public void showDialog(View view){
        MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this, "我来自Activity",R.style.myCustomdialog);
        dialog.show();
    }

3.2、通过回调方式把Dialog里的数据回传至Activity

package com.crazymo.costomstyledialog;

/**
 * Created by cmo on 16-5-5.
 */
public class MyCostomDialog extends Dialog {
    Context mContext;
    String mText;
    private  IShowPicByIndexListener mIShowPicByIndexListener;//声明一个回调接口函数变量,用于调用
    //定义一个回调接口,用于接收Activity返回的值
    public interface IShowPicByIndexListener{
        public void onShowPicIndex(int index);
    }

    public MyCostomDialog(Context context) {
        super(context);
        mContext=context;
    }
    //使用到Theme时调用
    public MyCostomDialog(Context context, int theme) {
        super(context, theme);
        mContext = context;
    }
    //把回调也传递到构造方法中
    public MyCostomDialog(Context context, String txt,int theme,IShowPicByIndexListener listener) {
        super(context,theme);
        mContext = context;
        mText=txt;
        mIShowPicByIndexListener=listener;
    }
    public MyCostomDialog(Context context, String txt,int theme) {
        super(context,theme);
        mContext = context;
        mText=txt;
    }

    private void setRadioListener(final View view){
        final RadioGroup radioGroup= (RadioGroup) view.findViewById(R.id.id_radiogroup);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                int index=0;
                RadioButton checkedRadio=(RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());
                switch (checkedId){
                    case R.id.id_android_radiobtn:
                        index=1;
                        break;
                    case R.id.id_ios_radiobtn:
                        index=2;
                        break;
                    case R.id.id_java_radiobtn:
                        index=3;
                        break;
                    default:
                        index=0;
                }
                mIShowPicByIndexListener.onShowPicIndex(index);
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.dialog_my_costom, null);
        setRadioListener(layout);
        TextView tv = (TextView)layout.findViewById(R.id.id_dialog_title_txt);
        tv.setText(mText);
        this.setContentView(layout);
    }
}
package com.crazymo.costomstyledialog;

public class MainActivity extends Activity {
    private int[] imgs={R.mipmap.ic_blue_launcher,R.mipmap.ic_red_launcher,R.mipmap.ic_toy,R.mipmap.ic_launcher};
    private RadioGroup mRadioGroup;
    private ImageView mImageView;
    private int index=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init(){
        getViews();
    }
    private void getViews(){
        mImageView= (ImageView) findViewById(R.id.id_pic_imgv);
    }
    public void showDialog(View view){
        MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this, "我来自Activity", R.style.myCustomdialog, new MyCostomDialog.IShowPicByIndexListener() {
            @Override
            public void onShowPicIndex(int index) {
                mImageView.setImageResource(imgs[index]);
            }
        });
        dialog.show();
    }

    private void setImageViewBcg(int index){
        mImageView.setImageResource(imgs[index]);
    }
}

4、自主控制自定义Dialog

4.1、动态设置Dialog的显示位置

对话框默认显示于屏幕中心位置,但是我们可以通过Window对象来动态设置Dialog的位置

public void showDialog(View view){
        MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this, "我来自Activity", R.style.myCustomdialog, new MyCostomDialog.IShowPicByIndexListener() {
            @Override
            public void onShowPicIndex(int index) {
                mImageView.setImageResource(imgs[index]);
            }
        });
        Window window=dialog.getWindow();//获取Window对象
        window.setGravity(Gravity.TOP|Gravity.LEFT);//设置显示位置
        dialog.show();
    }

4.2、改变对话框的透明度

改变对话框的透明度也可以通过设置Window的alpha属性。

  Window window=dialog.getWindow();//先获取Window对象
        WindowManager.LayoutParams layoutParams=window.getAttributes();//再获取属性集
        layoutParams.alpha=0.6f;//设置alpha属性
        window.setAttributes(layoutParams);

4.3、自主控制对话框的关闭状态

    public void showDialog(View view){
        MyCostomDialog dialog = new  MyCostomDialog(MainActivity.this, "我来自Activity", R.style.myCustomdialog, new MyCostomDialog.IShowPicByIndexListener() {
            @Override
            public void onShowPicIndex(int index) {
                mImageView.setImageResource(imgs[index]);
            }
        });
        Window window=dialog.getWindow();
        window.setGravity(Gravity.TOP | Gravity.LEFT);
        WindowManager.LayoutParams layoutParams=window.getAttributes();
        layoutParams.alpha=0.6f;
        window.setAttributes(layoutParams);
        try {
            Field field=dialog.getClass().getSuperclass().getDeclaredField("mShowing");
            field.setAccessible(true);
            try {
                field.set(dialog,false);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        dialog.show();
    }
时间: 2024-10-10 01:00:28

Android进阶——自定义View之扩展系统Dialog的相关文章

Android进阶——自定义View之自己绘制彩虹圆环调色板

引言 前面几篇文章都是关于通过继承系统View和组合现有View来实现自定义View的,刚好由于项目需要实现一个滑动切换LED彩灯颜色的功能,所以需要一个类似调色板的功能,随着手在调色板有效区域滑动,LED彩灯随即显示相应的颜色,也可以通过左右的按钮,按顺序切换显示一组颜色,同时都随着亮度的改变LED彩灯的亮度随即变化,这篇基本上把继承View重绘实现自定义控件的大部分知识总结了下(当然还有蛮多没有涉及到,比如说自适应布局等),源码在Github上 一.继承View绘制自定义控件的通用步骤 自定

Android中自定义View的MeasureSpec使用

有时,Android系统控件无法满足我们的需求,因此有必要自定义View.具体方法参见官方开发文档:http://developer.android.com/guide/topics/ui/custom-components.html 一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定该控件在屏幕上的大小. protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) onMeasure传

android中自定义view涉及到的绘制知识

android中自定义view的过程中,需要了解的绘制知识. 1.画笔paint: 画笔设置: <span style="font-size:14px;"> paint.setAntiAlias(true);//抗锯齿功能 paint.setColor(Color.RED); //设置画笔颜色 paint.setStyle(Style.FILL);//设置填充样式 paint.setStrokeWidth(30);//设置画笔宽度 paint.setShadowLayer(

Android高手进阶教程(三)之----Android 中自定义View的应用.

大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习惯了Android 传统的页面布局方式,如下代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertic

Android之自定义View的实现

对于学习Android开发的小童鞋对于自定义View一定不会陌生,相信大家对它是又爱又恨,爱它可以跟随我们的心意设计出漂亮的效果:恨它想要完全流畅掌握,需要一定的功夫.对于初学者来说确实很不容易,网上有很多相关的博客文档之类的资料,但是往往对于初学者,只知拷贝修改,不理解其中的深意,最后还是无法更具自己的需要,进行自定义的开发,本篇我们就一同来了解下自定义View的神秘面纱. 开发自定义控件的步骤: 1.了解View的工作原理 2. 编写继承自View的子类 3. 为自定义View类增加属性 4

Android笔记自定义View之制作表盘界面

前言 最近我跟自定义View杠上了,甚至说有点上瘾到走火入魔了.身为菜鸟的我自然要查阅大量的资料,学习大神们的代码,这不,前两天正好在郭神在微信公众号里推送一片自定义控件的文章--一步步实现精美的钟表界面.正适合我这种菜鸟来学习,闲着没事,我就差不多依葫芦画瓢也写了一个自定义表盘View,现在纯粹最为笔记记录下来.先展示下效果图: 下面进入正题 自定义表盘属性 老规矩,先在attrs文件里添加表盘自定义属性 <declare-styleable name="WatchView"&

关于android开发自定义view

Android App开发过程中,很多时候会遇到系统框架中提供的控件无法满足我们产品的设计需求,那么这时候我们可以选择先Google下有没有比较成熟的开源项目可以让我们用,或者Github上面的项目也非常丰富,能够满足我们绝不多数的开发需求,但是在使用这些炫酷的第三方控件时,需要我们掌控里面实现的细节,所以就滋生了今天“关于android开发中自定义view的探索” 粗体是我个人的疑问,下面小字部分是结合查阅资料以及实际操作的归纳理解. 什么是View? Android所有的控件都是View或者

我的Android进阶之旅------&gt;如何获取系统中定义了那些权限

在Window控制台中输入如下命令可以看到Android系统中列出的所有权限(如果自定义权限注册成功,在这里也会找到这些自定义的权限) adb shell pm list permissions C:\Users\Administrator>adb shell pm list permissions All Permissions: permission:android.permission.INTERNAL_SYSTEM_WINDOW permission:android.permission

Android 中自定义View的初步总结

概述 在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了.对于自定义View,可以分为两种,一种是自定义控件(继承View),另一种是自定义布局容器(继承ViewGroup),下面就针对自定义控件View的应用进行简单的总结. 自定义View 自定义View时,我们大部分只需要重写两个方法onMeasure(),onDraw().onMeasure()负责对当前View尺寸进行测量,onDraw()负责把当前这个View绘