大家好,我是爱吃土豆的土豆,不知道大家七夕晚上过得咋样啊,有对象的注意不要搞出人命了,没对象的来和土豆一起 new 对象。咳咳,因为公司事情确实多,所以就算我完成了一些案例,比如popupwindow啊 获取本地相册或者使用手机拍照啊 使用百度地图获取定位什么的,但是没什么时间记录一下,既然今天放假了,就不能再拖延下去了。既然前面都提到了popupwindow,地图定位什么的,那我们今天就不讲这些了,em。。,毕竟要对的起我们文章的标题嘛。
进入正题,说起dialog,应该是安卓里面的常客了,因其小巧方便的特性,可以在程序的任何地方都可以使用。因此安卓程序也为我们提供默认样式的dialog,比如这样:
所以昨天它是一个人过七夕的,别问我为什么。
在实际项目中,我们大多使用自己定制的dialog,也就是所谓的自定义dialog。不过这篇文章不纯粹将如何去实现自定义的dialog,这时候又有好事者要问了,土豆,你是不是话痨,别人的文章都只说如何去实现自定义的dialog,你还要自己加点东西上去blabla。。。这位同学,你听我慢慢道来。
其实项目中dialog基本用在比如网络请求时,告诉用户要耐心等待一下或者用户进行某项比较重要的操作时,弹出dialog让其确认,而土豆今天写的,就是项目中最常见的,confirmDialog,这样的dialog有一个title、一个msg、两个按钮组成,就像文章开头的系统默认样式的dialog一样,先来看看效果:
em。。。虽然我使用了自己定义的样式,但是美观上。。。。。。。。
可以看到在一个activity中,我们使用了两次自定义的dialog,神经比较大条的同学可能会写两次创建dialog的代码,因为标题啊,内容啊,button的点击事件都不一样,很难封装在一个方法中。这时候脑子转的快的同学会说了,如果真要封装的话,标题和内容我们可以通过方法传参解决,但是因为业务不同,所以button的点击事件很可能不同,所以还是较难封装。具体如何封装在一个activity,土豆这里不详细讲了,因为就算你实现了在一个activity中封装了dialog,但是如果其他activity如果也要使用相同的dialog,是不是直接以前写好的代码复制过去呢?(后面那个一直点头的同学,你不要太过分啊)再夸大点讲,如果一万个activity中都要用这个dialog,我们难道复制一万次相同的代码吗,当然是不,所以土豆今天要讲的是,一人购买,全家使用,呸,一次创建,各地使用。
但是但是,在这之前,还是需要先说点其他东西,使用android studio的伙伴们都知道,在android studio中创建activity时,ide会为我们自动创建相应的布局并且自动关联,而且很贴心的为我们自动注册了活动,很方便。不知道各位有没有发现,其自动创建的活动是继承自AppCompatActivity,当然,你也可以手动修改让其继承Activity,那么,我们为什么不创建一个属于自己的activity,在这个activity中封装项目中所有activity都会进行的操作,比如,initData(),initView()这两个我们规范代码的方法,每次创建activity都要手动创建,太麻烦,封装封住,又比如,我们即将要讲的dialog,这个方法每个activity都可能会使用,所以也封装进去,这样我们所有的只要继承自这个activity的都可以使用此方法
在这里,土豆把我们自己创建的activity命名为BaseActivity,意思是所有的activity的根据地,先放代码:
package com.example.administrator.potato.activity;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.example.administrator.potato.interfaces.ConfirmDialogInterface;
import com.example.administrator.potato.R;
public abstract class BaseActivity extends Activity {
protected Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取上下文对象
mContext=this;
}
/**
* 初始视图
* */
protected abstract void initView();
/**
* 初始数据
* */
protected abstract void initData();
/**
* 显示确认框形式的dialog
* @param title dialog的标题
* @param msg dialog的消息
* @param confirmDialogInterface 监听dialog确认键以及取消键的点击事件
* */
protected void showConfirmDialog(@Nullable String title, @Nullable String msg, @NonNull final ConfirmDialogInterface confirmDialogInterface){
final AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
//加载布局
View view=View.inflate(mContext,R.layout.dialog_confirm,null);
//获取组件实例
TextView textTitle=view.findViewById(R.id.textTitle);
TextView textContent=view.findViewById(R.id.textContent);
TextView textConfirm=view.findViewById(R.id.textConfirm);
TextView textCancel=view.findViewById(R.id.textCancel);
//设置标题
textTitle.setText(title);
//设置消息内容
textContent.setText(msg);
//设置需要显示的view
builder.setView(view);
//赋值给其父类以获取dismiss方法
final AlertDialog alertDialog=builder.create();
//显示dialog
alertDialog.show();
//设置确定按钮内容
textConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//确认键业务逻辑处理接口
confirmDialogInterface.onConfirmClickListener();
//业务逻辑处理完毕使dialog消失
alertDialog.dismiss();
}
});
//设置取消按钮内容
textCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//取消键业务逻辑处理接口
confirmDialogInterface.onCancelClickListener();
//业务逻辑处理完毕使dialog消失
alertDialog.dismiss();
}
});
}
}
接口的代码:
package com.example.administrator.potato.interfaces;
/**
* 作者:土豆
* 创建日期:2018/8/16
* 邮箱:[email protected]
*/
public interface ConfirmDialogInterface {
//监听确认按钮点击事件
void onConfirmClickListener();
//监听取消按钮点击事件
void onCancelClickListener();
}
可以看到,我们把BaseActivity设置为抽象类,并且有两个抽象方法initData以及initView,还有一个属性Context,至于为啥要这样写,这里不详细讲,因为我们今天的主角是这个方法:
/**
* 显示确认框形式的dialog
* @param title dialog的标题
* @param msg dialog的消息
* @param confirmDialogInterface 监听dialog确认键以及取消键的点击事件
* */
protected void showConfirmDialog(@Nullable String title, @Nullable String msg, @NonNull final ConfirmDialogInterface confirmDialogInterface){
final AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
//加载布局
View view=View.inflate(mContext,R.layout.dialog_confirm,null);
//获取组件实例
TextView textTitle=view.findViewById(R.id.textTitle);
TextView textContent=view.findViewById(R.id.textContent);
TextView textConfirm=view.findViewById(R.id.textConfirm);
TextView textCancel=view.findViewById(R.id.textCancel);
//设置标题
textTitle.setText(title);
//设置消息内容
textContent.setText(msg);
//设置需要显示的view
builder.setView(view);
//赋值给其父类以获取dismiss方法
final AlertDialog alertDialog=builder.create();
//显示dialog
alertDialog.show();
//设置确定按钮内容
textConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//确认键业务逻辑处理接口
confirmDialogInterface.onConfirmClickListener();
//业务逻辑处理完毕使dialog消失
alertDialog.dismiss();
}
});
//设置取消按钮内容
textCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//取消键业务逻辑处理接口
confirmDialogInterface.onCancelClickListener();
//业务逻辑处理完毕使dialog消失
alertDialog.dismiss();
}
});
}
这个方法就是用于实现自定义dialog的方法,如何实现的话,程序里面注释也写的很完善,我就不再赘述了,我这里只讲思路,讲逻辑。咳咳,大家都暂时不要睡觉了,下面的是重点,期末要考的:
布局代码就不贴出来了,很简单
2、由于我们使用了自己的view,所以我们只能先自己找到我们view的id,然后使用代码去操控它,比如
//获取组件实例
TextView textTitle=view.findViewById(R.id.textTitle);
。。。。
//设置标题
textTitle.setText(title);
就像这样,title我们就可以通过从方法外部传入,这样我们就可以随心所欲让它显示我们想显示的内容了。同理,消息内容也可以这样设置
3、显示文字性的可以通过Textview.setText实现,但是点击事件的内容却是难以掌控的,但是对接口有了解的同学露出了回心笑容,我们可以把按钮的事件委托给接口,让实现这个接口的activity自己决定细节,有反应慢的同学可能暂时难以理解,暴躁的同学还会说,你说的啥玩意儿啊,听不懂。没关系,就打个比方吧,比如说土豆是一个饲养员,饲养了很多不同种类的动物,这些动物呢也很善解人意,我说啥它们都能听懂,我闲着无事,就给它们发了一个指令----“叫”,动物们收到指令了,于是鸭子就“嘎嘎”叫,鸡就“大爷,来玩啊”,呸,鸡就“咯咯咯”的叫,羊就“咩咩”的叫,那么,我只是定义了“叫”这个方法,但如何'叫",该怎么“叫”,不是我自己叫的吧,是接收到命令的动物们自己根据自己的实际情况发出了相应叫声。那好了,在这个例子中,我们来理一下对应关系:
饲养员土豆对应的是BaseActivity
指令“叫”对应的是 confirmDialogInterface.onConfirmClickListener();也就是接口
动物们不同的叫声对应的是不同的实现了调用了该接口的activity,因为具体如何叫是这些activity该解决的事情
下面,就贴出其中一个完整的activity的代码
package com.example.administrator.potato.activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.example.administrator.potato.R;
import com.example.administrator.potato.interfaces.ConfirmDialogInterface;
import com.example.administrator.potato.utils.ToastMessage;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class UseDialogActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_use_dialog);
ButterKnife.bind(this);
initView();
initData();
}
@Override
protected void initView() {
}
@Override
protected void initData() {
}
@OnClick({R.id.button1, R.id.button2,R.id.button})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button:
AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
builder.setTitle("默认样式dialog")
.setMessage("我是颜值担当!!!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastMessage.toastSuccess("点击了确定键",true);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastMessage.toastSuccess("点击了取消键",true);
}
})
.create()
.show();
break;
case R.id.button1:
showConfirmDialog("来自土豆的提示", "这是第一个dialog", new ConfirmDialogInterface() {
@Override
public void onConfirmClickListener() {
Toast.makeText(mContext,"点击了第一个dialog的确认键",Toast.LENGTH_SHORT).show();
}
@Override
public void onCancelClickListener() {
Toast.makeText(mContext,"点击了第一个dialog的取消键",Toast.LENGTH_SHORT).show();
}
});
break;
case R.id.button2:
showConfirmDialog("温馨提示", "这是第二个dialog!!", new ConfirmDialogInterface() {
@Override
public void onConfirmClickListener() {
ToastMessage.toastSuccess("这是第二个dialog的确认键",true);
}
@Override
public void onCancelClickListener() {
ToastMessage.toastSuccess("这是第二个dialog的取消键",true);
}
});
break;
}
}
}
我们比较关注的应该是这段代码:
showConfirmDialog("来自土豆的提示", "这是第一个dialog", new ConfirmDialogInterface() {
@Override
public void onConfirmClickListener() {
Toast.makeText(mContext,"点击了第一个dialog的确认键",Toast.LENGTH_SHORT).show();
}
@Override
public void onCancelClickListener() {
Toast.makeText(mContext,"点击了第一个dialog的取消键",Toast.LENGTH_SHORT).show();
}
});
可以看到,我们只需要使用BaseActivity中的showConfirmDialog方法,然后将title,msg,以及新建一个接口用于实现button不同的点击事件即可,十分的方便,而且任意一个只要继承自我们自己的BaseActivity的activity都可以使用这个方法,是不是简化了很多代码,也让我们的程序变得更加整洁。当然,在同一个activity中也可以多次调用这个方法,毕竟动物们有不是只能有一种叫声,比如鸡,咳咳。。
总结:
1、有一些追求的完美的同学可能会问,土豆,你这按钮的文字没有封装呀,我要是需要改变两个按钮的文字咋办呢?土豆会告诉你,封装方法和title的原理一样,无非是showConfirmDialog方法外传入一个参数,然后在showConfirmDialog中去改变对应的按钮的文字,你懂的
2、细心的同学可能会发现,我并没有在外部传入context,而是使用的BaseActivity的context,其实主要是为了方便啦,少穿点参数还是舒服的,但是请一定注意,不要用我们上次封装的那种Application的Context去启动dialog,会出错,至于出啥错,为啥会出错呢,自己去了解一下哟
3、启动dialog的时候,activity并没有走onResume生命周期哦
4、本项目的码云地址:https://gitee.com/fightPotato/potato.git
5、下一次讲和dialog同样常用的popupWindow,下次见