Android自定义Dialog带Dialog的显示消失动画(一)

来源:互联网 发布:中华书局 知乎 编辑:程序博客网 时间:2024/05/01 20:51

效果图

这里写图片描述

博客绝大时候还是为了记录自己的一些想法,跟心得,我也不指望有什么人看我的博客,我抽空回来往往能提醒自己要学的还有很多,在自定义一个组件之前,最好得先明白这个组件的工作原理,在之前曾发了一个自定义Toast的文章

这里对于Toast就不赘述了,当一个Dialog弹出的时候,处于下面的Activity会失去焦点, 负责显示Dialog的布局接受所有的用户交互.Dialog的官方API

在看Dialog源码之前先说下Android的UI视图层

这里写图片描述

当我们调用Dialog的show方法的时候系统会做哪些事情,我们点开源码看一下

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

我们可以直接参考系统的AlertDialog来自定义自己的Dialog,系统的AlertDialog采用了Builder模式来构造,我们也参考系统的这种方式来定义我们的Dialog,上我们的代码,要调用的几个比较核心的方法

1,将我们想要让Dialog显示的View添加到phonewindow中,addContentView只是一个view的叠加,不会删除之前的View    /**     * Add an additional content view to the screen.  Added after any existing     * ones in the screen -- existing views are NOT removed.     *      * @param view The desired content to display.     * @param params Layout parameters for the view.     */    public void addContentView(View view, ViewGroup.LayoutParams params) {        mWindow.addContentView(view, params);    }
2,"预显示"我们添加到phoneWindow的View,setContentView会将之前的View给移除掉,显示当前的View  /**     * Set the screen content to an explicit view.  This view is placed     * directly into the screen's view hierarchy.  It can itself be a complex     * view hierarchy.     *      * @param view The desired content to display.     */    public void setContentView(View view) {        mWindow.setContentView(view);    }
"我们的Dialog"public class CustomDialog extends Dialog {    public CustomDialog(Context context) {        super(context);    }    public CustomDialog(Context context, int themeResId) {        super(context, themeResId);    }    protected CustomDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {        super(context, cancelable, cancelListener);    }    //用Builder模式来构造Dialog    public static class Builder {        private Context mContext;        private View contentView;        private String title;        private String message;        private String positiveText;        private String negativeText;        private DialogInterface.OnClickListener positiviOnclickListener;        private DialogInterface.OnClickListener negativeOnclickListener;        public Builder(Context mContext) {            this.mContext = mContext;        }        public Builder setContentView(View contentView) {//设置dialog的主view            this.contentView = contentView;            return this;        }        public Builder setTitle(String title) {//设置dialog的标题            this.title = title;            return this;        }        public Builder setMessage(String msg) {//设置dialig的内容            this.message = msg;            return this;        }        public Builder setPositiveButton(String text, DialogInterface.OnClickListener positiviOnclickListener) {//dialog的确认按钮            this.positiveText = text;            this.positiviOnclickListener = positiviOnclickListener;            return this;        }        public Builder setNegativeButton(String text, DialogInterface.OnClickListener negativeOnclickListener) {//dialog的取消按钮            this.negativeText = text;            this.negativeOnclickListener = negativeOnclickListener;            return this;        }        /**         * 1,加载要显示的布局         * 2,通过dialog的addContentView将布局添加到window中         * 3,基本逻辑处理         * 4,显示dialog的布局         */        public CustomDialog build() {            LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);            final CustomDialog mCustomDialog = new CustomDialog(mContext, R.style.CustomDialog);//默认调用带style的构造            mCustomDialog.setCanceledOnTouchOutside(false);//默认点击布局外不能取消dialog            View view = mInflater.inflate(R.layout.custom_dialog, null);            mCustomDialog.addContentView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));//将我们的View添加到phonewindow里,这句话最后调用的是window.addContentView(view);            if (!TextUtils.isEmpty(title)) {                TextView titleView = (TextView) view.findViewById(R.id.tv_title);                titleView.setText(title);            }            if (!TextUtils.isEmpty(positiveText)) {//这是确认按钮                Button btn_cofirm = (Button) view.findViewById(R.id.btn_confirm);                btn_cofirm.setText(positiveText);                if (positiviOnclickListener != null) {                    btn_cofirm.setOnClickListener(new View.OnClickListener() {                        @Override                        public void onClick(View v) {                            positiviOnclickListener.onClick(mCustomDialog, BUTTON_POSITIVE);                        }                    });                }            } else {                view.findViewById(R.id.btn_confirm).setVisibility(View.GONE);            }            if (!TextUtils.isEmpty(negativeText)) {//这是取消按钮逻辑处理                Button btn_cancle = (Button) view.findViewById(R.id.btn_cancle);                btn_cancle.setText(negativeText);                if (negativeOnclickListener != null) {                    btn_cancle.setOnClickListener(new View.OnClickListener() {                        @Override                        public void onClick(View v) {                            negativeOnclickListener.onClick(mCustomDialog, BUTTON_NEGATIVE);                        }                    });                }            } else {                view.findViewById(R.id.btn_cancle).setVisibility(View.GONE);            }            if (!TextUtils.isEmpty(message)) {                TextView messageView = (TextView) view.findViewById(R.id.tv_message);                messageView.setText(message);//显示的内容            } else if (contentView != null) {//如果内容区域要显示其他的View的话                LinearLayout mContentLayout = (LinearLayout) view.findViewById(R.id.content);                mContentLayout.removeAllViews();                mContentLayout.addView(contentView);            }            mCustomDialog.setContentView(view);            return mCustomDialog;        }    }}
"Dialog的布局文件"<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:background="@drawable/dialog_shape"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:orientation="vertical" >        <TextView            android:id="@+id/tv_title"            android:layout_width="fill_parent"            android:layout_height="40dp"            android:gravity="center"            android:text="title"            android:visibility="visible" />        <LinearLayout            android:id="@+id/content"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:background="@drawable/dialog_shape"            android:gravity="center" >            <TextView                android:id="@+id/tv_message"                android:text="message"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:gravity="left|center"                android:minHeight="120dp"                android:paddingBottom="20dp"                android:paddingLeft="20dp"                android:paddingRight="20dp"                android:paddingTop="15dp" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="60dp"            android:layout_gravity="bottom"            android:gravity="center"            android:orientation="horizontal" >            <Button                android:id="@+id/btn_confirm"                android:layout_width="114dp"                android:layout_height="40dp"                android:gravity="center"                android:text="确认" />            <Button                android:id="@+id/btn_cancle"                android:layout_width="120dp"                android:layout_height="40dp"                android:layout_marginLeft="20dp"                android:gravity="center"                android:text="取消" />        </LinearLayout>    </LinearLayout></FrameLayout>

另外是Dialog的动画跟shape

"进入动画,从左进"<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <translate        android:fromXDelta="-100%p"        android:toXDelta="0"        android:fromYDelta="0"        android:toYDelta="0"        android:duration="1000"        /></set>"从右出"<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <translate        android:fromXDelta="0"        android:toXDelta="100%p"        android:fromYDelta="0"        android:toYDelta="0"        android:duration="1000"        /></set> <style name="Dialog_Anim_Style" parent="android:Animation" >        <item name="@android:windowEnterAnimation">@anim/left_in</item>  //进入时的动画        <item name="@android:windowExitAnimation">@anim/left_out</item>    //退出时的动画    </style>

"Dialog的shape及Style""shape"<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <stroke        android:width="1px"        android:color="@android:color/black" />    <solid android:color="@android:color/background_light" /></shape>"style"   <style name="CustomDialog" parent="android:style/Theme.Dialog">        <item name="android:background">#00000000</item>        <item name="android:windowBackground">@android:color/transparent</item>        <item name="android:windowNoTitle">true</item>        <item name="android:windowIsFloating">true</item>    </style>

调用我们的Dialog

public class MainActivity extends AppCompatActivity {    private CustomDialog mDialog;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);        setContentView(R.layout.activity_main);        mDialog = new CustomDialog.Builder(this).setTitle("标题").setMessage("这是内容")                .setNegativeButton("取消", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        if (mDialog != null && mDialog.isShowing())                            mDialog.dismiss();                    }                }).setPositiveButton("确认", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        Toast.makeText(MainActivity.this, "确认", Toast.LENGTH_SHORT).show();                    }                }).build();        mDialog.getWindow().setWindowAnimations(R.style.Dialog_Anim_Style);    }    public void showDialog(View view) {        if (mDialog != null && !mDialog.isShowing())            mDialog.show();    }}

最后把源码献上吧,源码在这

4 1