介绍
今天我们来学习一下如何自定义一个漂亮、美观且通用的对话框。开始前,我们先了解一下对话框(Dialog),它是Android UI交互的一种形式,通常给予用户一个重要事件的通知,让用户来处理这一个事件。它不同于其他几种通知方式,比如Toast、Notification、Snackbar等。这里的不同指的是事件的重要程度,比如我们需要更新软件,那么这时候弹出一个对话框,让用户选择YES/NO;比如更新成功了,我们弹出一个Toast信息“”更新成功了,欢迎使用“”,这样显得更友好。我们应该根据情景更确切的使用哪种交互方式。
那么,今天我们的主题是一个对话框(Dialog),记得以前刚接触android手机时候,那时的对话框既丑又难看,特别影响整个软件的美观程度,要说以前最好看的还是ios风格。但现在android发展的如此之快,加上google推出的material design风格的各种控件,如果还不够我们还可以自定义定制各种精美样式的控件。现在的android软件UI做的确实挺漂亮的,因为丑的根本没人去用,在这个看脸的时代,软件也是看脸的。
那么看看我们今天要完成的Dialog长什么样吧,这里我录制了一段动态图,更能体现出效果。
效果图
实现步骤
对话框风格就是这个样子了,我个人感觉还是挺美观的。那么我们来说说它是如何实现的吧。首先,我给它设定了一个风格,也就是对我们对话框一些必要属性的设置,它是一个style资源文件,如下
<style name="MyUsualDialog" parent="android:style/Theme.Dialog">
<!--背景颜色及和透明程度-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--是否去除标题 -->
<item name="android:windowNoTitle">true</item>
<!--是否去除边框-->
<item name="android:windowFrame">@null</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
<!--是否模糊-->
<item name="android:backgroundDimEnabled">false</item>
</style>
其次,我们对它的xml布局文件进行绑定,下边是我们布局代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:background="#11ffffff">
<LinearLayout
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/usual_dialog_shape"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="15dp"
android:gravity="center"
tools:text="消息提示"
android:textColor="#38ADFF"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
tools:text="提示消息" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginTop="15dp"
android:background="#E4E4E4" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:singleLine="true"
tools:text="No"
android:textColor="#7D7D7D"
android:textSize="16sp"
tools:ignore="RtlHardcoded" />
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="#E4E4E4" />
<Button
android:id="@+id/btn_confirm"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:singleLine="true"
tools:text="Yes"
android:textColor="#38ADFF"
android:textSize="16sp"
tools:ignore="RtlHardcoded" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
最后,我们继承系统的Dialog,进行设置一些必要的style、点击事件等。我们在构造器里传入我们刚刚新建的style主题,这个设置很重要。然后我个人用了建造者模式对Dialog类进行了封装,至于什么是建造者模式,不懂的小伙伴可以看我之前写的一篇关于建造者模式的使用方式:Android设计模式之建造者模式 —— Builder Pattern
这里贴出整个Dialog类的所有代码,我们命名为UsualDialogger类,就是指通用的对话框。
/**
* 通常都会使用的一种交互对话框
*
* @Created by Mr.Xu on 2018/4/30.
*/
public class UsualDialogger extends Dialog {
private final String TITLE;
private final String MESSAGE;
private final String CONFIRMTEXT;
private final String CANCELTEXT;
private final onConfirmClickListener ONCONFIRMCLICKLISTENER;
private final onCancelClickListener ONCANCELCLICKLISTENER;
public interface onConfirmClickListener {
void onClick(View view);
}
public interface onCancelClickListener {
void onClick(View view);
}
private UsualDialogger(@NonNull Context context, String title, String message, String confirmText, String cancelText,
onConfirmClickListener onConfirmClickListener, onCancelClickListener onCancelClickListener) {
super(context, R.style.MyUsualDialog);
this.TITLE = title;
this.MESSAGE = message;
this.CONFIRMTEXT = confirmText;
this.CANCELTEXT = cancelText;
this.ONCONFIRMCLICKLISTENER = onConfirmClickListener;
this.ONCANCELCLICKLISTENER = onCancelClickListener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.usual_dialog);
setCanceledOnTouchOutside(false);
initView();
}
public static Builder Builder(Context context) {
return new Builder(context);
}
private void initView() {
Button btnConfirm = findViewById(R.id.btn_confirm);
Button btnCancel = findViewById(R.id.btn_cancel);
TextView tvTitle = findViewById(R.id.tv_title);
TextView tvMessage = findViewById(R.id.tv_message);
if (!TextUtils.isEmpty(TITLE)) {
tvTitle.setText(TITLE);
}
if (!TextUtils.isEmpty(MESSAGE)) {
tvMessage.setText(MESSAGE);
}
if (!TextUtils.isEmpty(CONFIRMTEXT)) {
btnConfirm.setText(CONFIRMTEXT);
}
if (!TextUtils.isEmpty(CANCELTEXT)) {
btnCancel.setText(CANCELTEXT);
}
btnConfirm.setOnClickListener(view -> {
if (ONCONFIRMCLICKLISTENER == null) {
throw new NullPointerException("clicklistener is not null");
} else {
ONCONFIRMCLICKLISTENER.onClick(view);
}
});
btnCancel.setOnClickListener(view -> {
if (ONCANCELCLICKLISTENER == null) {
throw new NullPointerException("clicklistener is not null");
} else {
ONCANCELCLICKLISTENER.onClick(view);
}
});
}
public UsualDialogger shown() {
show();
return this;
}
public static class Builder {
private String mTitle;
private String mMessage;
private String mConfirmText;
private String mCancelText;
private onConfirmClickListener mOnConfirmClickListener;
private onCancelClickListener mOnCcancelClickListener;
private Context mContext;
private Builder(Context context) {
this.mContext = context;
}
public Builder setTitle(String title) {
this.mTitle = title;
return this;
}
public Builder setMessage(String message) {
this.mMessage = message;
return this;
}
public Builder setOnConfirmClickListener(String confirmText, onConfirmClickListener confirmclickListener) {
this.mConfirmText = confirmText;
this.mOnConfirmClickListener = confirmclickListener;
return this;
}
public Builder setOnCancelClickListener(String cancelText, onCancelClickListener onCancelclickListener) {
this.mCancelText = cancelText;
this.mOnCcancelClickListener = onCancelclickListener;
return this;
}
public UsualDialogger build() {
return new UsualDialogger(mContext, mTitle, mMessage, mConfirmText, mCancelText,
mOnConfirmClickListener, mOnCcancelClickListener);
}
}
}
关键的是我们的MainActivity在使用这种建造者模式调用我们的UsualDialogger确实很舒服,我们的MainActivity代码如下
public class MainActivity extends AppCompatActivity {
@BindView(R.id.btn_Dialog_Usual)
Button btnDialogUsual;
private UsualDialogger dialog2 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
/**
* 通用的确定和取消对话框
*/
@OnClick(R.id.btn_Dialog_Usual)
public void showUsualDialog() {
dialog2 = UsualDialogger.Builder(this)
.setTitle("通用对话框")
.setMessage("这是一个漂亮的对话框")
.setOnConfirmClickListener("确定", view -> {
Toast.makeText(MainActivity.this, "确定", Toast.LENGTH_SHORT).show();
})
.setOnCancelClickListener("取消", view -> {
Toast.makeText(MainActivity.this, "取消", Toast.LENGTH_SHORT).show();
if (dialog2 != null) {
dialog2.dismiss();
}
})
.build()
.shown();
}
}
可以看到在确定、取消事件中,我们只打了一个Toast来简单的测试,在这里可以处理点击事件。那么这就是我们实现的所有代码,完成了我们的一个简单的自定义对话框。
最后
最后我准备了一些面试的知识汇总,数据结构,计算机网络等等都有。自己整理和分类的,还请尊重知识产出。
分享给大家的资料包括高级架构技术进阶脑图、Android开发面试专题资料,还有高级进阶架构资料包括但不限于【高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术】希望能帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也是可以分享给身边好友一起学习的!
资料免费领取方式:加群797404811
网友评论