【0063】【项目实战】-【手机安全卫士】-【2】
1. 增加淡入淡出的透明动画效果的添加
1.1 异常的报错
【说明】因为没有开启服务器,服务器上的数据无法读取,因此会出现读取异常;

1.2 初始化动画

1.3 动画对当前控件的选择
【说明】选择动画的控件:就是当前的空间的相对布局;



1.4 源码

1.5 实际的效果:逐渐变深,3秒钟

2.Home的主界面的布局
2.1 界面效果
【布局分析】
【1】包含标题:功能列表
【2】滚动的字幕
【3】九宫格的点击按钮

2.2 标题布局的显示


2.3 样式的抽取





2.4 滚动文字的显示
2.4.1 添加省略点的位置属性
【默认值】默认是在尾部





2.4.2 字体跑马灯的效果
【注意】只是设置的下面的属性,仍然不会自然的滚动;
【原因】因为焦点不在文字上,因为不会进行自动滚动;

【改进】默认的是滚动三次之后就不滚动了;

【效果】字幕进行了滚动

【一直不停滚动属性的设置】

2.5 自定义获取焦点的TextView




【使用测试】

【效果】

2.6 自定义控件的总结

3.九宫格使用
3.1 九宫格的效果

3.2 九宫格的书写


【默认值】默认是一列

【指定列数】3列


3.3 初始化
3.4 数据的准备
【数据】包括文字和图片,需要准备两组数组,一个放置文字,一个放置图片;


3.5 单个条目的布局




3.6 适配器数据的填充

3.7 间距的调整
【说明】水平方向间距大于竖直方向的间距


【效果】

4【设置中心】设置界面一个条目布局结构
【说明】设置中心包含一个自动更新的设置,只有此选项勾选上才可以进行自动更新;
4.1 效果
4.2 设置点击监听

【新建类】

【在清单中配置】

【新建布局文件】
【使用线性布局进行拼接】每个条目的样式不一致,使用线性布局;当然也可以使用listView;







4.3 黑线的添加
【1】View的继承关系

4.4 黑线的效果


5.自定义组合控件构件布局结构
5.1【自定义的原因】
因为在同一个界面中使用到了多个相同的布局;
可以抽取出来,对代码进行优化;


5.2自定义控件的布局




1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" > 5 <RelativeLayout 6 android:padding="5dp" 7 android:layout_width="match_parent" 8 android:layout_height="wrap_content"> 9 <TextView 10 android:id="@+id/tv_title" 11 android:textColor="#000" 12 android:textSize="18sp" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content"/> 15 <TextView 16 android:id="@+id/tv_des" 17 android:layout_below="@id/tv_title" 18 android:textColor="#000" 19 android:textSize="18sp" 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content"/> 22 <!-- android:clickable="false" 23 android:focusable="false" 24 android:focusableInTouchMode="false" 25 让当前的 CheckBox不能被点击,即不能响应事件--> 26 <CheckBox 27 android:id="@+id/cb_box" 28 android:clickable="false" 29 android:focusable="false" 30 android:focusableInTouchMode="false" 31 android:layout_alignParentRight="true" 32 android:layout_centerVertical="true" 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content"/> 35 <View 36 android:background="#000" 37 android:layout_below="@id/tv_des" 38 android:layout_width="match_parent" 39 android:layout_height="1dp"/> 40 </RelativeLayout> 41 </RelativeLayout>
5.3 通过类加载布局文件


5.3.1【问题】怎样使得三个构造方法调用同一个构造方法?

【解决办法】

5.3.2 xml文件转换为class类

【代码执行的过程】

5.3.3【自定义布局的使用】全路径的包名

【生成的效果】


5.3.5【多个条目的创建】
【可能出现的问题】

【程序运行之后的效果】

【问题的查找】



【正确的代码】

【最终的效果】

【注意】如果是线性布局,可能被挤到了右边;

6.自定义组合控件中相关方法
6.1 效果演示


6.2【源码】根据是否选中绑定文字的改变

7.选中SettingItemView条目状态切换
【说明】SettingItemView条目也是View,因此可以增加监听方法
7.1 增加id;

7.2 监听事件的的添加

7.3 现在的效果
【说明】点击条目的部分时候状态会发生改变;

7.4 BUG
【说明】点击CheckBox的选中与未选中没有反应;文字不会发生改变;

7.4.2 出现问题的原因
【说明】点击事件被拦截了,点击checkBox的事件被拦截了;
【拦截的过程】

【事件回传的过程】

==================================
【事件回传的再讲解】

7.4.5 解决方法
【思路1】

【说明】实际的点击效果是点击在了SettingItemView上了;

【效果】

【思路2】在智慧北京中进行讲解

8. sp工具类编写
8.1 选中的状态没有记录
【效果】本来选中的状态,在返回之后再点击进入之后,状态没有记录;

8.2 编写工具类进行记录设置值
【解决的办法】编写工具类进行记录
【工具类实现的功能】读写功能

【源码】
1 package com.itheima.mobilesafe74.utils; 2 3 import android.content.Context; 4 import android.content.SharedPreferences; 5 6 public class SpUtil { 7 private static SharedPreferences sp; 8 /** 9 * 写入boolean变量至sp中 10 * @param ctx 上下文环境 11 * @param key 存储节点名称 12 * @param value 存储节点的值 boolean 13 */ 14 public static void putBoolean(Context ctx,String key,boolean value){ 15 //(存储节点文件名称,读写方式) 16 if(sp == null){ 17 sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE); 18 } 19 sp.edit().putBoolean(key, value).commit(); 20 } 21 /** 22 * 读取boolean标示从sp中 23 * @param ctx 上下文环境 24 * @param key 存储节点名称 25 * @param defValue 没有此节点默认值 26 * @return 默认值或者此节点读取到的结果 27 */ 28 public static boolean getBoolean(Context ctx,String key,boolean defValue){ 29 //(存储节点文件名称,读写方式) 30 if(sp == null){ 31 sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE); 32 } 33 return sp.getBoolean(key, defValue); 34 }
8.3 sp类的使用-sp存储更新状态

【新建类】


【效果】在返回之后的设置值仍然存在;再次打开程序的设置值仍然存在;

9.在加载时的根据设置值判断功能添加
9.1 判断功能的添加

9.2 进入主界面的延时



【到目前为止的效果】

10.自定义属性
10.1 自定义属性的意义

10.2 参照别人的源码




10.3 模仿源码进行书写


10.4 自定义属性的使用:构造方法中获取自定义属性值

【说明】在xml中可以使用属性的前提是:
【1】具有命名空间的指定;
【2】在属性文件中进行了配置;

11 给自定义组合控件内部控件赋值

11.1 属性赋值的位置


11.2 打印属性的个数


11.3 查看自定义属性的名称和值

11.3.1 id值的打印
【注意】



11.3.2 宽度和高度的属性值



【源码的修改】



11.4 自定义组合控件属性回顾




12 是否有密码区分对话框类型
【手机防盗模块】
12.1【功能分析】
【1】点击手机防盗会弹出密码框,在第一次回输入密码之后进入到第二个界面;
【2】在第二个界面点击返回按钮之后返回到第一个功能列表界面;




12.2 手机防盗功能模块的代码逻辑
【弹出对话框的框架】


【密码数据的存储和读取】

【密码数据的读取和框架的完善】




13.密码对话框的设置
13.1 效果
【说明】使我们自己设置的对话框,不是调用系统原有的,因此需要自己定义布局;

13.2 逻辑框架的搭建

13.3 布局的设置
【说明】使用线性布局,按钮需要使用权重;


【布局源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <TextView 7 style="@style/TitleStyle" //使用原来定义的样式 8 android:text="设置密码" 9 android:background="#f30"/> //原来自定义的样式的颜色是绿色的,现在将其覆盖掉为红色; 10 <!-- android:hint=""提示用户输入内容 --> 11 <EditText 12 android:id="@+id/et_set_psd" 13 android:hint="设置密码" 14 android:inputType="textPassword" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content"/> 17 <EditText 18 android:id="@+id/et_confirm_psd" 19 android:hint="确认密码" 20 android:inputType="textPassword" 21 android:layout_width="match_parent" 22 android:layout_height="wrap_content"/> 23 <LinearLayout 24 android:layout_width="match_parent" 25 android:layout_height="wrap_content"> 26 <Button 27 android:id="@+id/bt_submit" 28 android:text="确认" 29 android:layout_width="0dp" 30 android:layout_weight="1" //权重为1 31 android:layout_height="wrap_content"/> 32 <Button 33 android:text="取消" 34 android:id="@+id/bt_cancel" 35 android:layout_width="0dp" 36 android:layout_weight="1" //权重为1 37 android:layout_height="wrap_content"/> 38 </LinearLayout> 39 </LinearLayout>

【效果】

13.4 对话初次设置密码验证过程
【取消事件的逻辑】

【源码】如果密码确认一致,此处跳转的是测试界面
1 /** 2 * 设置密码对话框 3 */ 4 private void showSetPsdDialog() { 5 //因为需要去自己定义对话框的展示样式,所以需要调用dialog.setView(view); 6 //view是由自己编写的xml转换成的view对象xml----->view 7 Builder builder = new AlertDialog.Builder(this); 8 final AlertDialog dialog = builder.create(); 9 10 final View view = View.inflate(this, R.layout.dialog_set_psd, null); 11 //让对话框显示一个自己定义的对话框界面效果 12 dialog.setView(view); 13 dialog.show(); 14 15 Button bt_submit = (Button) view.findViewById(R.id.bt_submit); 16 Button bt_cancel = (Button) view.findViewById(R.id.bt_cancel); 17 18 bt_submit.setOnClickListener(new OnClickListener() { 19 @Override 20 public void onClick(View v) { 21 EditText et_set_psd = (EditText) view.findViewById(R.id.et_set_psd); 22 EditText et_confirm_psd = (EditText)view.findViewById(R.id.et_confirm_psd); 23 24 String psd = et_set_psd.getText().toString(); 25 String confirmPsd = et_confirm_psd.getText().toString(); 26 27 if(!TextUtils.isEmpty(psd) && !TextUtils.isEmpty(confirmPsd)){ //如果密码和确实密码不为空 28 if(psd.equals(confirmPsd)){ //如果测试密码等于确认密码 29 //进入应用手机防盗模块,开启一个新的activity 30 Intent intent = new Intent(getApplicationContext(), TestActivity.class); 31 startActivity(intent); 32 //跳转到新的界面以后需要去隐藏对话框 33 dialog.dismiss(); 34 35 SpUtil.putString(getApplicationContext(), ConstantValue.MOBILE_SAFE_PSD, psd); 36 }else{ 37 ToastUtil.show(getApplicationContext(),"确认密码错误"); 38 } 39 }else{ 40 //提示用户密码输入有为空的情况 41 ToastUtil.show(getApplicationContext(), "请输入密码"); 42 } 43 } 44 }); 45 46 bt_cancel.setOnClickListener(new OnClickListener() { 47 @Override 48 public void onClick(View v) { 49 dialog.dismiss(); 50 } 51 }); 52 }
13.5 测试Activity的书写


13.6 注意的问题
13.6.1 BUG1
【出现的问题1】空指针异常;

【问题的原因】

【修改】

13.6.2 BUG2
【出现的问题】空确认密码会出现空指针异常

【解决方法】

【输入密码的正常的效果】

【取消的代码逻辑的效果】

13.7 在测试页面点击返回按钮的逻辑
【问题】应该返回之后不要再弹出密码对话框

【修改源码】


【效果】

13.8 密码的存储功能增加
【源码的增加】

13.9 确认密码对话框的添加

【布局源码】直接复制填写密码框的布局,然后修改即可;
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <TextView 7 style="@style/TitleStyle" 8 android:text="确认密码" //修改此处 9 android:background="#f30"/> 10 <!-- android:hint=""提示用户输入内容 --> 11 <EditText //删除原来的填写密码框 12 android:id="@+id/et_confirm_psd" 13 android:hint="确认密码" 14 android:inputType="textPassword" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content"/> 17 <LinearLayout 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content"> 20 <Button 21 android:id="@+id/bt_submit" 22 android:text="确认" 23 android:layout_width="0dp" 24 android:layout_weight="1" 25 android:layout_height="wrap_content"/> 26 <Button 27 android:text="取消" 28 android:id="@+id/bt_cancel" 29 android:layout_width="0dp" 30 android:layout_weight="1" 31 android:layout_height="wrap_content"/> 32 </LinearLayout> 33 </LinearLayout>
【逻辑代码】直接复制原来的填写密码框,然后直接修改即可



【运行的效果】
14. 对密码的md5的加密过程
14.1 密码保存存在的问题
【说明】密码是明文,非常容易被破解;需要加密;


14.2 加密解决


【Java程序的运行】




【补0】因为在转化出来的字符中存在一位的数字,需要在前面补0;

【最后生辰的结果】

【md5解密收费】

【md5密码加盐】防止被破译,可以在本身的密码之后再添加自己定义的字符串;

【md5源码】
1 import java.beans.Encoder; 2 import java.security.MessageDigest; 3 import java.security.NoSuchAlgorithmException; 4 5 6 public class Md5Util { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 //加盐 13 String psd = "123"+"abc"; 14 encoder(psd); 15 } 16 17 /**给指定字符串按照md5算法去加密 18 * @param psd 需要加密的密码 19 */ 20 private static void encoder(String psd) { 21 try { 22 //1,指定加密算法类型 23 MessageDigest digest = MessageDigest.getInstance("MD5"); 24 //2,将需要加密的字符串中转换成byte类型的数组,然后进行随机哈希过程 25 byte[] bs = digest.digest(psd.getBytes()); 26 // System.out.println(bs.length); 27 //3,循环遍历bs,然后让其生成32位字符串,固定写法 28 //4,拼接字符串过程 29 StringBuffer stringBuffer = new StringBuffer(); 30 for (byte b : bs) { 31 int i = b & 0xff; 32 //int类型的i需要转换成16机制字符 33 String hexString = Integer.toHexString(i); 34 // System.out.println(hexString); 35 if(hexString.length()<2){ 36 hexString = "0"+hexString; 37 } 38 stringBuffer.append(hexString); 39 } 40 //5,打印测试 41 System.out.println(stringBuffer.toString()); 42 } catch (NoSuchAlgorithmException e) { 43 e.printStackTrace(); 44 } 45 } 46 }
浙公网安备 33010602011771号