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

时间:2022-11-01 13:11:35

效果图

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

博客绝大时候还是为了记录自己的一些想法,跟心得,我也不指望有什么人看我的博客,我抽空回来往往能提醒自己要学的还有很多,在自定义一个组件之前,最好得先明白这个组件的工作原理,在之前曾发了一个自定义Toast的文章,对于Toast就不赘述了,当一个Dialog弹出的时候,处于下面的Activity会失去焦点, 负责显示Dialog的布局接受所有的用户交互.Dialog的官方API

在看Dialog源码之前先说下Android的UI视图层
Android自定义Dialog带Dialog的显示消失动画(一)

当我们调用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,上我们的代码,要调用的几个比较核心的方法

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


}

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