好,今天天我们在完成我们这个项目里面的一个自定义对话框的功能啦,它是在我们的第一个功能,手机防盗里面的,我们在给手机防盗那里加一个登陆的操作,这样会更安全一些,所以我们就用到了一个对话框,为了让它更好看一些,而且也学习一下怎样自定义对话框,所以我们就开始学习一下啦
首先,我们先给我们的手机防盗的启动界面,加一个快捷启动的方式,就是在拨打电话的时候,输入一个特定的号码,然后就会启动手机防盗那个界面,听起来,是不是很酷呢,其实很简单的,就是用一个广播接收都,来接收打电话时发出来的广播,然后捕获它,然后就可以进行我们想要的操作啦,好,直接上代码
先新建一个类com.xiaobin.security.receiver.CallPhoneReceiver
package com.xiaobin.security.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import com.xiaobin.security.ui.LostProtectedActivity; public class CallPhoneReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String outPhoneNumber = this.getResultData(); if(outPhoneNumber.equals("1314")) //当监听到用户拨打的是1314的时候,就进行下面的操作,你可以把拨打的号码做成参数的形式,让用户可配置 { Intent i = new Intent(context, LostProtectedActivity.class); //这个很重要,如果没有这一句,那就会报错,这一句是因为我们是在一个Receiver里面启动一个activity的,但activity的启动,都是放到一个栈里面的, //但Receiver里面没有那个栈,所以我们要在这里启动一个activity,那就必须要指定这行代码啦 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); setResultData(null); //这行代码是把广播的数据设置为null,这样就不会把刚刚那个号码拨打出去啦,只会启动我们的activity } } }
现在还不行的,我们还要在AndroidMainfest文件里面注册这个广播接收者
<receiver android:name="com.xiaobin.security.receiver.CallPhoneReceiver"> <intent-filter android:priority="1000"><!-- 把优先级设置高一些,以便第一个拿到广播 --> <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> </intent-filter> </receiver>
当然,我们还要加上相应的权限呢
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
好啦,到现在为止,我们通过拨打电话,来启动手机防盗这个功能就完成的啦,各位可以去试试
现在进入我们今天的重点,那就是自定义对话框啦,先上图,看看我们的效果
其实,我们想自定义自己的对话框,那么就有必要先去了解系统的对话框是怎样写的,在我们用到的android.jar这个包里面,就有系统自己写的对话框的啦
我们可以通过apktool这个工具来得到系统自己定义的资源文件
apktool下载地址
为了能运行apktool,我们要下载两东西 apktool1.5.2.tar还有apktool-install-windows-r05-ibot.tar
下载完之后,直接它两个解压出来,然后把apktool1.5.2.tar里面的那个jar包,放到apktool-install-windows-r05-ibot.tar这个目录下面,如图
这样子就会有3个文件的啦,现在我们把android.jar出拷贝到这个目录下面,然后在dos下面进行这个目录,然后就运行apktool d android.jar
就这样,我们就会在刚刚那个目录下面看到有一个解析出来的资源文件夹的啦,而我们系统自己写的UI资源全在里面啦,我们有空的话,可以去看看,系统是怎样自己写的,然后自己就可以相应的进行修改啦
好啦,说回我们今天的对话框,系统自己写的对话框,其实就是一个主题,要用的时候,就使用那个主题,那么,它就是在res/value/styles.xml里面的,我们把那个文件打开,然后搜索Theme.Dialog,然后就可以看到系统自己写的对话框啦
好啦,知道这些之后,我们有空就可以参考一下怎样写啦
现在我们自己来写,我们在我们的项目里面的styles.xml文件里面写上我们自己的对话框的样式啦
<style name="MyDialog" parent="@android:style/Theme.Dialog"><!-- 要继承系统原来的对话框 --> <item name="android:windowBackground">@drawable/title_background</item><!-- 指定背景颜色 --> <item name="android:windowNoTitle">true</item><!-- 隐藏系统原来的标题栏 --> </style>
因为我是教大家怎样自定义对话框,所以为了简单,我只是写了这两个属性而已,有兴趣的,你们可以参考一下系统自己的,然后写多一点,写好我们的样式之后,怎样用呢
其实很简单,只要在new一个dialog的时候,指定一下它的样式就行的啦
dialog = new Dialog(this, R.style.MyDialog);
好啦,我们现在就结合我们今天的逻辑来看一下,我们的对话框的效果,我们今天要做的是,当用户第一次启动这个手机防盗这个功能的时候,要求用户输入一个登录密码,然后以后进入这个功能的时候,都要输入以前设置的密码,而且我们的密码是以MD5加密后,存放到SharedPreferences里面的
既然是加密,那么我们现在就先来写一个加密的工具类啦
com.xiaobin.security.utils.MD5Encoder
package com.xiaobin.security.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Encoder { public static String encode(String pwd) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5");//拿到MD5加密的对象 byte[] bytes = messageDigest.digest(pwd.getBytes());//返回一个加密后的字节数组 StringBuffer sb = new StringBuffer(); String tmp; for(int i = 0; i < bytes.length; i++) { tmp = Integer.toHexString(0xff & bytes[i]);//把字节转换为16进制的字符串 if(tmp.length() == 1) //如果这个字符串,只有一个字符,就要补0 { sb.append("0" + tmp); } else { sb.append(tmp); } } return sb.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("没有这个加密算法" + e); } } }
好啦,接下来,都是一些很简单的逻辑处理而已,我们直接上代码
com.xiaobin.security.ui.LostProtectedActivity
package com.xiaobin.security.ui; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.xiaobin.security.R; import com.xiaobin.security.utils.MD5Encoder; public class LostProtectedActivity extends Activity implements OnClickListener { private SharedPreferences sp; private Dialog dialog; private EditText password; private EditText confirmPassword; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sp = getSharedPreferences("cofig", Context.MODE_PRIVATE); if(isSetPassword()) { showLoginDialog(); } else { showFirstDialog(); } } private void showLoginDialog() { dialog = new Dialog(this, R.style.MyDialog); View view = View.inflate(this, R.layout.login_dialog, null); password = (EditText) view.findViewById(R.id.et_protected_password); Button yes = (Button) view.findViewById(R.id.bt_protected_login_yes); Button cancel = (Button) view.findViewById(R.id.bt_protected_login_no); yes.setOnClickListener(this); cancel.setOnClickListener(this); dialog.setContentView(view); dialog.show(); } private void showFirstDialog() { dialog = new Dialog(this, R.style.MyDialog); //dialog.setContentView(R.layout.first_dialog); View view = View.inflate(this, R.layout.first_dialog, null); //这样来填充一个而已文件,比较方便 password = (EditText) view.findViewById(R.id.et_protected_first_password); confirmPassword = (EditText) view.findViewById(R.id.et_protected_confirm_password); Button yes = (Button) view.findViewById(R.id.bt_protected_first_yes); Button cancel = (Button) view.findViewById(R.id.bt_protected_first_no); yes.setOnClickListener(this); cancel.setOnClickListener(this); dialog.setContentView(view); dialog.show(); } private boolean isSetPassword() { String pwd = sp.getString("password", ""); if(pwd.equals("") || pwd == null) { return false; } return true; } @Override public void onClick(View v) { switch(v.getId()) { case R.id.bt_protected_first_yes : String fp = password.getText().toString().trim(); String cp = confirmPassword.getText().toString().trim(); if(fp.equals("") || cp.equals("")) { Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show(); return; } else { if(fp.equals(cp)) { Editor editor = sp.edit(); editor.putString("password", MD5Encoder.encode(fp)); editor.commit(); } else { Toast.makeText(this, "两次密码不相同", Toast.LENGTH_SHORT).show(); return; } } dialog.dismiss(); break; case R.id.bt_protected_first_no : dialog.dismiss(); finish(); break; case R.id.bt_protected_login_yes : String pwd = password.getText().toString().toString(); if(pwd.equals("")) { Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show(); } else { String str = sp.getString("password", ""); if(MD5Encoder.encode(pwd).equals(str)) { dialog.dismiss(); } else { Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show(); } } break; case R.id.bt_protected_login_no : dialog.dismiss(); finish(); break; default : break; } } }
另外,还有两个布局文件,一个是第一次登录时,设置密码的,一个是以后登录时,输入密码的
first_dialog
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="300dip" android:layout_height="280dip" android:gravity="center_horizontal" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textSize="24sp" android:text="@string/setPassword"/> <LinearLayout android:layout_width="300dip" android:layout_height="180dip" android:background="#ffc8c8c8" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/setPasswordDescription"/> <EditText android:id="@+id/et_protected_first_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/againPassword"/> <EditText android:id="@+id/et_protected_confirm_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword"/> <LinearLayout android:layout_width="300dip" android:layout_height="50dip" android:gravity="center" android:orientation="horizontal"> <Button android:id="@+id/bt_protected_first_yes" android:layout_width="140dip" android:layout_height="40dip" android:text="@string/protectedYes"/> <Button android:id="@+id/bt_protected_first_no" android:layout_width="140dip" android:layout_height="40dip" android:layout_marginLeft="10dip" android:text="@string/protectedNo"/> </LinearLayout> </LinearLayout> </LinearLayout>
login_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="300dip" android:layout_height="180dip" android:gravity="center_horizontal" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textSize="24sp" android:text="@string/login"/> <LinearLayout android:layout_width="300dip" android:layout_height="120dip" android:background="#ffc8c8c8" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/inputPassword"/> <EditText android:id="@+id/et_protected_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword"/> <LinearLayout android:layout_width="300dip" android:layout_height="50dip" android:gravity="center" android:orientation="horizontal"> <Button android:id="@+id/bt_protected_login_yes" android:layout_width="140dip" android:layout_height="40dip" android:text="@string/protectedYes"/> <Button android:id="@+id/bt_protected_login_no" android:layout_width="140dip" android:layout_height="40dip" android:layout_marginLeft="10dip" android:text="@string/protectedNo"/> </LinearLayout> </LinearLayout> </LinearLayout>
好啦,今天的代码就到这里啦,代码有点多,有什么不明白的,欢迎留言,有什么要指导的,也欢迎留言!!!
今天源码下载