文章目录
- 1.手机防盗——密码加密过程 & 加密后的验证
- 2.手机防盗——对话框展示样式兼容低版本
- 3.手机防盗——设置界面 & 功能列表界面跳转逻辑处理
- 4.手机防盗——导航界面的布局编写
- 5.手机防盗——编写选择器
- 6.手机防盗——.9格式的图片拖拽区域 & 文字所在区域
- 7.手机防盗——第二个导航界面
- 8.手机防盗——导航界面和功能列表界面跳转逻辑处理
- 9.手机防盗——绑定sim卡序列号
- 10.手机防盗——第二个导航界面跳转到第三个导航界面
- 11.手机防盗——第三个导航界面编写
- 12.手机防盗——联系人内容提供者分析过程
- 13.手机防盗——获取联系人唯一性id
- 14.手机防盗——关联查询data表 & 数据封装分析
- 15.手机防盗——联系人数据封装 & 填充数据适配器
- 16.手机防盗——选择联系人 & 结束activity没有传递intent
- 17.手机防盗——联系人回显过程
- 18.手机防盗——第四个导航界面编写
- 19.手机防盗——平移动画分析
- 20.手机防盗——平移动画集成
1.手机防盗——密码加密过程 & 加密后的验证
上一篇博客的最后,我们编写了一个MD5加密工具类,这一节里,我们需要完善密码加密过程以及加密后的验证
- 修改MD5Util,为了安全性,这里做了个加盐处理,并且制定返回值,代码如下:
package com.example.mobilesafe.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
/**
* 给指定字符串按照MD5算法进行加密
* @param password 待加密的字符型
* @return 加密过后的字符串
*/
public static String encoder(String password){
try {
// 0.加盐处理
password = password + "password";
// 1.指定加密算法类型
MessageDigest digest = MessageDigest.getInstance("MD5");
// 2.将需要加密的字符串中转换成byte类型的数组,然后进行随机的哈希过程
byte[] bs = digest.digest(password.getBytes());
// 3.循环遍历数组,然后让其生成32位字符串,固定写法
StringBuffer stringBuffer = new StringBuffer();
for (byte b : bs) {
int i = b & 0xff;
// 4.将int类型的i转换成16进制字符
String hexString = Integer.toHexString(i);
if (hexString.length() < 2){
hexString = "0" + hexString;
}
// 5.字符串拼接
stringBuffer.append(hexString);
return stringBuffer.toString();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
- 修改HomeActivity,修改showSetPasswordDialog()和showConfirmPasswordDialog()方法,调用MD5工具类对密码进行相应的加密和解密处理,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.MD5Util;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.utils.ToastUtil;
public class HomeActivity extends AppCompatActivity {
/**
* 存储标题
*/
private String[] mTitleStrs;
/**
* 存储图像
*/
private int[] mDrawableIds;
/**
* 网格对象
*/
private GridView gv_home;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// 初始化UI
initUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void initUI() {
gv_home = findViewById(R.id.gv_home);
}
/**
* 2.初始化数据
*/
private void initData() {
// 1.初始化每个图标的标题
mTitleStrs = new String[]{"手机防盗","通信卫士","软件管理","进程管理","流量统计","手机杀毒","缓存清理","高级工具","设置中心"};
// 2.初始化每个图标的图像
mDrawableIds = new int[]{R.drawable.home_safe,R.drawable.home_callmsgsafe,R.drawable.home_apps,R.drawable.home_taskmanager,R.drawable.home_netmanager,R.drawable.home_trojan,R.drawable.home_sysoptimize,R.drawable.home_tools,R.drawable.home_settings};
// 3.为GridView设置数据适配器
gv_home.setAdapter(new MyAdapter());
// 4.注册GridView中单个条目的点击事件
gv_home.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
// 手机防盗
showDialog();
break;
case 8:
// 设置中心
Intent intent = new Intent(getApplicationContext(), SettingActivity.class);
startActivity(intent);
break;
default:
break;
}
}
});
}
/**
* 3.自定义的数据适配器类
*/
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// 统计条目的总数
return mTitleStrs.length;
}
@Override
public Object getItem(int position) {
// 根据索引获取对象
return mTitleStrs[position];
}
@Override
public long getItemId(int position) {
// 获取索引
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 获取视图
View view = View.inflate(getApplicationContext(), R.layout.gridview_item, null);
TextView tv_title = view.findViewById(R.id.tv_title);
ImageView iv_icon = view.findViewById(R.id.iv_icon);
tv_title.setText(mTitleStrs[position]);
iv_icon.setBackgroundResource(mDrawableIds[position]);
return view;
}
}
/**
* 4.手机防盗——密码对话框
*/
private void showDialog() {
// 1.通过判断本地是否有存储密码来确定显示哪个对话框(sp)
String password = SharedPreferencesUtil.getString(this, ConstantValue.MOBILE_SAFE_PASSWORD, "");
if (TextUtils.isEmpty(password)){
// 2.初始设置密码对话框
showSetPasswordDialog();
}else {
// 3.确认密码对话框
showConfirmPasswordDialog();
}
}
/**
* 5.初次设置密码对话框
*/
private void showSetPasswordDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertDialog dialog = builder.create();
final View view = View.inflate(this, R.layout.dialog_set_password, null);
dialog.setView(view);
dialog.show();
Button btn_submit = view.findViewById(R.id.btn_submit);
Button btn_cancel = view.findViewById(R.id.btn_cancel);
btn_submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText et_set_password = view.findViewById(R.id.et_set_password);
EditText et_confirm_password = view.findViewById(R.id.et_confirm_password);
String password = et_set_password.getText().toString();
String confirmpassword = et_confirm_password.getText().toString();
if (!TextUtils.isEmpty(password) && !TextUtils.isEmpty(confirmpassword)){
if(password.equals(confirmpassword)){
// 进入手机防盗模块
Intent intent = new Intent(getApplicationContext(), TestActivity.class);
startActivity(intent);
dialog.dismiss();
// 将密码存储到sp中
SharedPreferencesUtil.putString(getApplicationContext(),ConstantValue.MOBILE_SAFE_PASSWORD, MD5Util.encoder(password));
}else {
// 提示用户确认密码有误
ToastUtil.show(getApplicationContext(),"确认密码错误");
}
}else {
// 提示用户密码输入有为空
ToastUtil.show(getApplicationContext(),"请输入密码");
}
}
});
btn_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
/**
* 6.再次设置密码对话框
*/
private void showConfirmPasswordDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertDialog dialog = builder.create();
final View view = View.inflate(this, R.layout.dialog_confirm_password, null);
dialog.setView(view);
dialog.show();
Button btn_submit = view.findViewById(R.id.btn_submit);
Button btn_cancel = view.findViewById(R.id.btn_cancel);
btn_submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText et_confirm_password = view.findViewById(R.id.et_confirm_password);
String confirmpassword = et_confirm_password.getText().toString();
if (!TextUtils.isEmpty(confirmpassword)){
// 从sp中获取加密过后的密码,然后将输入的密码同样进行MD5算法,再进行比对
String password = SharedPreferencesUtil.getString(getApplicationContext(), ConstantValue.MOBILE_SAFE_PASSWORD, "");
if(password.equals(MD5Util.encoder(confirmpassword))){
// 进入手机防盗模块
Intent intent = new Intent(getApplicationContext(), TestActivity.class);
startActivity(intent);
dialog.dismiss();
}else {
// 提示用户确认密码有误
ToastUtil.show(getApplicationContext(),"确认密码错误");
}
}else {
// 提示用户密码输入有为空
ToastUtil.show(getApplicationContext(),"请输入密码");
}
}
});
btn_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
}
2.手机防盗——对话框展示样式兼容低版本
大致的密码验证逻辑以及完成了,现在来做进一步的优化:为了在低版本的Android手机上也具有相同的显示效果,我们来做一些相关的处理
核心思路是:
- 把根布局的界面背景渲染成白色,替换掉低版本的黑色
- 在调用
setView(view)
这个api时,使用另一个构造方法,即setView(view,0,0,0,0)
,即将边距全部设置为0
因为当前的Android手机版本都已经很高了(不会低于2.3),所以这个优化仅在此处作为记录,就不实际运用到项目中了
3.手机防盗——设置界面 & 功能列表界面跳转逻辑处理
有关于密码验证的逻辑已经完成了,接下来就需要编写手机防盗内的核心功能页面了,该页面由四个页面组成,如图所示:
- 页面一:描述功能
- 页面二:手机卡绑定(必须绑定才能进入下一个界面)
- 页面三:设置安全号码(必须设置才能进入下一个界面)
- 页面四:设置完成(只有开启这个选项,前三项的配置才会生效)
- 页面五:手机防盗功能列表界面
当第一次进入手机防盗模块时,界面出现的顺序是:12345,当全部设置完成后,再次进入手机防盗模块,则会直接进入界面5
现在开始编写代码
- 修改ConstantValue,新增常量SETUP_OVER,表示手机防盗界面是否全部设置完成,代码如下;
package com.example.mobilesafe.constant;
public class ConstantValue {
/**
* 记录更新的状态
*/
public static final String OPEN_UPDATE = "open_update";
/**
* 手机防盗——设置密码的状态
*/
public static final String MOBILE_SAFE_PASSWORD = "mobile_safe_password";
/**
* 手机防盗——四个界面是否设置完成的状态
*/
public static final String SETUP_OVER = "setup_over";
}
- 在activity下新建SetupOverActivity,作为手机防盗中功能列表的Activity,完善相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
public class SetupOverActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean setup_over = SharedPreferencesUtil.getBoolean(this, ConstantValue.SETUP_OVER, false);
if (setup_over){
// 密码输入成功,并且四个导航界面均设置完成,才停留在设置完成后的功能列表
setContentView(R.layout.activity_setupover);
}else {
// 密码输入成功,若四个导航界面没有全部设置完成,则跳转到第一个导航界面
Intent intent = new Intent(this, SetupOneActivity.class);
startActivity(intent);
finish();
}
}
}
- 在activity下新建SetupOneActivity,作为手机防盗中设置时出现的第一个Activity,暂时先套用Empty Activity模板即可
4.手机防盗——导航界面的布局编写
上一节我们写了导航界面的Activity,现在我们来完善相应的布局
修改activity_setup_one.xml,添加相应控件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupOneActivity">
<TextView
style="@style/TitleStyle"
android:text="1.欢迎使用手机防盗"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_margin="5dp"
android:text="您的手机防盗卫士:"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="sim卡变更报警"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="GPS追踪"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程数据销毁"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程锁屏"/>
</LinearLayout>
5.手机防盗——编写选择器
上一节里,我们完成了第一个界面的部分编写,现在就需要完成另一个部分——灰点指示器
- 修改activity_setup_one.xml,完善页面,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupOneActivity">
<TextView
style="@style/TitleStyle"
android:text="1.欢迎使用手机防盗"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_margin="5dp"
android:text="您的手机防盗卫士:"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="sim卡变更报警"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="GPS追踪"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程数据销毁"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程锁屏"/>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:background="@android:drawable/presence_online"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/setup1"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- 图片选择器,选择时和未选择时显示的图片不同 -->
<Button
android:text="下一页"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:drawableRight="@drawable/next"
android:background="@drawable/selector_next_btn_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</LinearLayout>
- 在drawable下新建selector_next_btn_bg.xml,作为按钮的选择器,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 选中状态:深绿色 -->
<item android:state_pressed="true" android:drawable="@drawable/function_greenbutton_pressed"/>
<!-- 未选中状态:浅绿色 -->
<item android:drawable="@drawable/function_greenbutton_normal"/>
</selector>
6.手机防盗——.9格式的图片拖拽区域 & 文字所在区域
项目里用到了.9格式的图片,.9格式的图片最大的作用就是适配,其更多的性质和制作可以参考百度,这里不再详述
7.手机防盗——第二个导航界面
我们前面完成了第一个导航界面的编写,现在来完成第二个界面的编写
- 修改res/value/style.xml,将按钮的样式抽取出来,命名为NextBtnStyle和PreBtnStyle,方便后面的界面在创建按钮时直接调用该样式,代码如下:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowNoTitle">true</item>
</style>
<style name="TitleStyle">
<item name="android:gravity">center</item>
<item name="android:textSize">20sp</item>
<item name="android:textColor">#000</item>
<item name="android:padding">10dp</item>
<item name="android:background">#0f0</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="PreBtnStyle">
<item name="android:text">上一页</item>
<item name="android:onClick">prePage</item>
<item name="android:layout_alignParentLeft">true</item>
<item name="android:layout_alignParentBottom">true</item>
<item name="android:drawableLeft">@drawable/previous</item>
<item name="android:background">@drawable/selector_next_btn_bg</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
</style>
<style name="NextBtnStyle">
<item name="android:text">下一页</item>
<item name="android:onClick">nextPage</item>
<item name="android:layout_alignParentRight">true</item>
<item name="android:layout_alignParentBottom">true</item>
<item name="android:drawableRight">@drawable/next</item>
<item name="android:background">@drawable/selector_next_btn_bg</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
</style>
</resources>
- 修改activity_setup_one.xml,给按钮调用样式,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupOneActivity">
<TextView
style="@style/TitleStyle"
android:text="1.欢迎使用手机防盗"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_margin="5dp"
android:text="您的手机防盗卫士:"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="sim卡变更报警"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="GPS追踪"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程数据销毁"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:gravity="center_vertical"
android:drawableLeft="@android:drawable/star_big_on"
android:layout_margin="5dp"
android:text="远程锁屏"/>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:background="@android:drawable/presence_online"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/setup1"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- 图片选择器,选择时和未选择时显示的图片不同 -->
<Button
style="@style/NextBtnStyle"/>
</RelativeLayout>
</LinearLayout>
- 修改SetupOneActivity,添加点击事件的跳转方法,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.mobilesafe.R;
public class SetupOneActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_one);
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
}
}
- 新建名为SetupTwoActivity的Activity,布局如图所示:
首先编写相应的布局文件activity_setup_two.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupTwoActivity">
<TextView
style="@style/TitleStyle"
android:text="2.手机卡绑定"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_margin="5dp"
android:text="通过绑定SIM卡:\n下次重启手机如果发现SIM卡变化,就会发送报警短信"/>
<com.example.mobilesafe.view.SettingItemView
xmlns:mobilesafe="http://schemas.android.com/apk/res/com.example.mobilesafe"
android:id="@+id/siv_sim_bound"
android:layout_width="match_parent"
android:layout_height="wrap_content"
mobilesafe:destitle="点击绑定sim卡"
mobilesafe:desoff="sim卡未绑定"
mobilesafe:deson="sim卡已绑定"/>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_online"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/bind"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- 图片选择器,选择时和未选择时显示的图片不同 -->
<Button
style="@style/PreBtnStyle"/>
<Button
style="@style/NextBtnStyle"/>
</RelativeLayout>
</LinearLayout>
8.手机防盗——导航界面和功能列表界面跳转逻辑处理
上一节中我们完成了第二个导航界面的编写,现在来完善该界面的相应逻辑
- 修改SetupTwoActivity,完善跳转的相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.mobilesafe.R;
public class SetupTwoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_two);
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupThreeActivity.class);
startActivity(intent);
finish();
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupOneActivity.class);
startActivity(intent);
finish();
}
}
- 在Activity新建SetupThreeActivity,作为第三个导航页面,同样完善跳转逻辑,其布局文件和类代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupThreeActivity">
<TextView
style="@style/TitleStyle"
android:text="3.设置安全号码"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="18sp"
android:layout_margin="5dp"
android:text="SIM卡变更后:\n报警短信会发送给安全号码"/>
<EditText
android:id="@+id/et_phone_number"
android:hint="请输入电话号码"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_select_number"
android:background="@drawable/selector_number_btn_bg"
android:text="选择联系人"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_online"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/bind"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- 图片选择器,选择时和未选择时显示的图片不同 -->
<Button
style="@style/PreBtnStyle"/>
<Button
style="@style/NextBtnStyle"/>
</RelativeLayout>
</LinearLayout>
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.mobilesafe.R;
public class SetupThreeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_three);
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupFourActivity.class);
startActivity(intent);
finish();
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
}
}
- 在drawable下新建selector_number_btn_bg.xml,作为第三个导航界面中按钮的状态选择器,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/function_greenbutton_pressed"/>
<item android:drawable="@drawable/function_greenbutton_normal"/>
</selector>
- 在Activity新建SetupFourActivity,作为第四个导航页面,同样完善跳转逻辑,其布局文件和类代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.SetupFourActivity">
<TextView
style="@style/TitleStyle"
android:text="4.恭喜您,设置完成"/>
<CheckBox
android:id="@+id/cb_box"
android:text="您没有开启防盗保护"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@android:drawable/presence_online"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="@drawable/phone"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- 图片选择器,选择时和未选择时显示的图片不同 -->
<Button
style="@style/PreBtnStyle"/>
<Button
style="@style/NextBtnStyle"/>
</RelativeLayout>
</LinearLayout>
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
public class SetupFourActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_four);
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupOverActivity.class);
startActivity(intent);
finish();
// 存储标识
SharedPreferencesUtil.putBoolean(this, ConstantValue.SETUP_OVER,true);
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupThreeActivity.class);
startActivity(intent);
finish();
}
}
9.手机防盗——绑定sim卡序列号
上一节中我们完善了手机防盗的四个界面的视图,这一节里我们来逐步完善对应逻辑,首先来完善第二个导航界面的逻辑,即绑定sim卡序列号
- 修改ConstantValue,添加静态常量SIM_NUMBER,作为本机SIM卡的标识符,代码如下:
package com.example.mobilesafe.constant;
public class ConstantValue {
/**
* 记录更新的状态
*/
public static final String OPEN_UPDATE = "open_update";
/**
* 手机防盗——设置密码的状态
*/
public static final String MOBILE_SAFE_PASSWORD = "mobile_safe_password";
/**
* 手机防盗——四个界面是否设置完成的状态
*/
public static final String SETUP_OVER = "setup_over";
/**
* 手机防盗——SIM卡绑定序列号
*/
public static final String SIM_NUMBER = "sim_number";
}
- 修改SharedPreferencesUtil,添加remove(),作为移除SharedPreferences中特定节点数据的方法,代码如下:
package com.example.mobilesafe.utils;
import android.content.Context;
import android.content.SharedPreferences;
public class SharedPreferencesUtil {
private static SharedPreferences sp;
/**
* 1.写入(boolean)
* @param ctx 上下文
* @param key 键
* @param value 值
*/
public static void putBoolean(Context ctx,String key,boolean value){
if (sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
sp.edit().putBoolean(key,value).commit();
}
/**
* 2.读取(boolean)
* @param ctx 上下文
* @param key 键
* @param defValue (默认)值
* @return 默认值或者相应结果
*/
public static boolean getBoolean(Context ctx,String key,boolean defValue){
if (sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
return sp.getBoolean(key,defValue);
}
/**
* 3.写入(string)
* @param ctx 上下文
* @param key 键
* @param value 值
*/
public static void putString(Context ctx,String key,String value){
if (sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
sp.edit().putString(key,value).commit();
}
/**
* 4.读取(string)
* @param ctx 上下文
* @param key 键
* @param defValue (默认)值
* @return 默认值或者相应结果
*/
public static String getString(Context ctx,String key,String defValue){
if (sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
return sp.getString(key,defValue);
}
/**
* 5.移除节点
* @param ctx 上下文
* @param key 键
*/
public static void remove(Context ctx, String key) {
if (sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
sp.edit().remove(key).commit();
}
}
- 修改SetupTwoActivity,完善相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.view.SettingItemView;
public class SetupTwoActivity extends AppCompatActivity {
/**
* SettingItemView实例
*/
private SettingItemView siv_sim_bound;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_two);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view) {
Intent intent = new Intent(getApplicationContext(), SetupThreeActivity.class);
startActivity(intent);
finish();
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view) {
Intent intent = new Intent(getApplicationContext(), SetupOneActivity.class);
startActivity(intent);
finish();
}
/**
* 3.初始化UI
*/
private void initUI() {
siv_sim_bound = findViewById(R.id.siv_sim_bound);
// 1.回显(读取已有的绑定状态,用作显示,看sp中是否存储了sim卡的序列号)
String sim_number = SharedPreferencesUtil.getString(this, ConstantValue.SIM_NUMBER, "");
// 2.判断是否序列卡号为空
if (TextUtils.isEmpty("")) {
siv_sim_bound.setCheck(false);
} else {
siv_sim_bound.setCheck(true);
}
siv_sim_bound.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 3.获取原有的状态
boolean isCheck = siv_sim_bound.isCheck();
// 4.将原有状态取反,设置给当前条目
siv_sim_bound.setCheck(!isCheck);
// 5.存储序列卡号
if (!isCheck) {
// 6.存储
// 6.1 获取sim卡序列号
TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// 6.2 获取sim卡的序列卡号,注意在Android 6.0版本以上要动态申请权限
if (ActivityCompat.checkSelfPermission(SetupTwoActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return;
}
String simSerialNumber = manager.getSimSerialNumber();
// 6.3 存储
SharedPreferencesUtil.putString(getApplicationContext(),ConstantValue.SIM_NUMBER,simSerialNumber);
Log.i("SetupTwoActivity","存储成功!" + simSerialNumber);
}else {
// 7.不存储,并且删除
SharedPreferencesUtil.remove(getApplicationContext(),ConstantValue.SIM_NUMBER);
Log.i("SetupTwoActivity","存储失败!");
}
}
});
}
}
10.手机防盗——第二个导航界面跳转到第三个导航界面
我们完善了绑定sim卡的逻辑,现在需要完善跳转逻辑
修改SetupTwoActivity,修改nextPage()方法,完善跳转逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.utils.ToastUtil;
import com.example.mobilesafe.view.SettingItemView;
public class SetupTwoActivity extends AppCompatActivity {
/**
* SettingItemView实例
*/
private SettingItemView siv_sim_bound;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_two);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view) {
String serialNumber = SharedPreferencesUtil.getString(this, ConstantValue.SIM_NUMBER, "");
if (!TextUtils.isEmpty(serialNumber)){
Intent intent = new Intent(getApplicationContext(), SetupThreeActivity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
}else {
ToastUtil.show(this,"请绑定sim卡");
}
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view) {
Intent intent = new Intent(getApplicationContext(), SetupOneActivity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.pre_in_anim,R.anim.pre_out_anim);
}
/**
* 3.初始化UI
*/
private void initUI() {
siv_sim_bound = findViewById(R.id.siv_sim_bound);
// 0.动态获取授权
if (ContextCompat.checkSelfPermission(SetupTwoActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(SetupTwoActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
}
// 1.回显(读取已有的绑定状态,用作显示,看sp中是否存储了sim卡的序列号)
String sim_number = SharedPreferencesUtil.getString(this, ConstantValue.SIM_NUMBER, "");
// 2.判断是否序列卡号为空
if (TextUtils.isEmpty(sim_number)) {
siv_sim_bound.setCheck(false);
} else {
siv_sim_bound.setCheck(true);
}
siv_sim_bound.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 3.获取原有的状态
boolean isCheck = siv_sim_bound.isCheck();
// 4.将原有状态取反,设置给当前条目
siv_sim_bound.setCheck(!isCheck);
// 5.存储序列卡号
if (!isCheck) {
// 6.存储
// 6.1 获取sim卡序列号
TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// 6.2 获取sim卡的序列卡号,注意在Android 6.0版本以上要动态申请权限
if (ContextCompat.checkSelfPermission(SetupTwoActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return;
}
// String simSerialNumber = manager.getSimSerialNumber(); 获取不到SIM卡号,故而写死
String simSerialNumber = "SIM卡号";
// 6.3 存储
SharedPreferencesUtil.putString(getApplicationContext(),ConstantValue.SIM_NUMBER,simSerialNumber);
Log.i("SetupTwoActivity","存储成功!" + simSerialNumber);
}else {
// 7.不存储,并且删除
SharedPreferencesUtil.remove(getApplicationContext(),ConstantValue.SIM_NUMBER);
Log.i("SetupTwoActivity","存储失败!");
}
}
});
}
}
11.手机防盗——第三个导航界面编写
之前我们完成了第二个导航界面的编写,现在需要完成第三个导航界面的编写,首先来完成布局
- 新增ContactListActivity,作为显示联系人列表的Activity,其布局和类代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.ContactListActivity">
<TextView
style="@style/TitleStyle"
android:text="选择联系人"/>
<ListView
android:id="@+id/lv_contact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import com.example.mobilesafe.R;
public class ContactListActivity extends AppCompatActivity {
private ListView lv_contact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
// 初始化UI
intiUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void intiUI() {
lv_contact = findViewById(R.id.lv_contact);
}
/**
* 2.初始化数据
*/
private void initData() {
}
}
- 修改SetupThreeActivity,添加initUI(),作为初始化ui的方法,代码如下:
package com.example.mobilesafe.activity;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.mobilesafe.R;
public class SetupThreeActivity extends AppCompatActivity {
/**
* "电话号码"编辑框
*/
private EditText et_phone_number;
/**
* "选择联系人"按钮
*/
private Button btn_select_number;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_three);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupFourActivity.class);
startActivity(intent);
finish();
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
}
/**
* 3.初始化UI
*/
private void initUI() {
et_phone_number = findViewById(R.id.et_phone_number);
btn_select_number = findViewById(R.id.btn_select_number);
btn_select_number.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), ContactListActivity.class);
startActivityForResult(intent,0);
}
});
}
/**
* 4.Activity回调
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
}
12.手机防盗——联系人内容提供者分析过程
上一节里我们完成了第三个导航界面的布局编写,现在来完善相关的代码逻辑,主要使用到内容解析器去匹配Uri地址
透过源码得知,系统联系人数据库中的核心表有三张:
- raw_contact:联系人表,
- data:用户信息表
- mimetype:类型表
而Uri的格式为:content://com.android.contacts/表名
分析过后,我们可以开始编写代码了
13.手机防盗——获取联系人唯一性id
前面我们分析了获取联系人信息的相关逻辑,现在需要开始编写相应代码
修改ContactListActivity,完善相应逻辑,注意在Android 6.0版本以上要动态获取授权,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import com.example.mobilesafe.R;
public class ContactListActivity extends AppCompatActivity {
private ListView lv_contact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
// 初始化UI
intiUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void intiUI() {
lv_contact = findViewById(R.id.lv_contact);
if (ContextCompat.checkSelfPermission(ContactListActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ContactListActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
}
}
/**
* 2.初始化数据
*/
private void initData() {
// 读取联系人是一个耗时操作,可以放在线程中执行
new Thread(){
@Override
public void run() {
// 1.获取内容解析器对象
ContentResolver contentResolver = getContentResolver();
// 2.封装查询过程
Cursor cursor = contentResolver.query(
Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},
null, null, null);
// 3.循环游标,直到没有数据为止
while (cursor.moveToNext()){
String id = cursor.getString(0);
Log.i("ContactListActivity",id);
}
// 4.关闭游标
cursor.close();
}
}.start();
}
}
14.手机防盗——关联查询data表 & 数据封装分析
上一节中我们获取到了所有联系人的id,现在需要通过关联查询获取联系人的具体信息
修改ContactListActivity,进一步完善相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import com.example.mobilesafe.R;
public class ContactListActivity extends AppCompatActivity {
private ListView lv_contact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
// 初始化UI
intiUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void intiUI() {
lv_contact = findViewById(R.id.lv_contact);
if (ContextCompat.checkSelfPermission(ContactListActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ContactListActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
}
}
/**
* 2.初始化数据
*/
private void initData() {
// 读取联系人是一个耗时操作,可以放在线程中执行
new Thread(){
@Override
public void run() {
// 1.获取内容解析器对象
ContentResolver contentResolver = getContentResolver();
// 2.封装查询过程
Cursor cursor = contentResolver.query(
Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},
null, null, null);
// 3.循环游标,直到没有数据为止
while (cursor.moveToNext()){
String id = cursor.getString(0);
Log.i("ContactListActivity",id);
// 4.根据用户唯一性id值,查询data表和mimetype表生成的视图,获取data以及mimetype字段
Cursor indexCursor = contentResolver.query(
Uri.parse("content://com.android.contacts/data"),
new String[]{"data1", "mimetype"},
"raw_contact_id = ?", new String[]{id}, null);
while (indexCursor.moveToNext()){
// 5.循环获取每一个联系人的电话号码以及姓名
String data1 = indexCursor.getString(0);
String mimetype = indexCursor.getString(1);
Log.i("ContactListActivity",data1);
Log.i("ContactListActivity",mimetype);
}
// 6.关闭游标
indexCursor.close();
}
// 7.关闭游标
cursor.close();
}
}.start();
}
}
15.手机防盗——联系人数据封装 & 填充数据适配器
上一节里我们获取到了联系人的数据,现在需要将这些数据进行封装,并填充到数据适配器中
- 在res/layout布局下新增listview_contact_item.xml,作为显示联系人内容的子布局,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:textColor="#f00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_phone"
android:textColor="#000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
- 修改ContactListActivity,进一步完善相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.example.mobilesafe.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ContactListActivity extends AppCompatActivity {
/**
* ListView
*/
private ListView lv_contact;
/**
* 存放联系人的集合
*/
private List<HashMap<String,String>> mContactList = new ArrayList<>();
/**
* Handler对象
*/
private Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
// 10.填充数据适配器
MyAdapter adapter = new MyAdapter();
lv_contact.setAdapter(adapter);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
// 初始化UI
intiUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void intiUI() {
lv_contact = findViewById(R.id.lv_contact);
if (ContextCompat.checkSelfPermission(ContactListActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ContactListActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
}
}
/**
* 2.初始化数据
*/
private void initData() {
// 读取联系人是一个耗时操作,可以放在线程中执行
new Thread(){
@Override
public void run() {
// 1.获取内容解析器对象
ContentResolver contentResolver = getContentResolver();
// 2.封装查询过程
Cursor cursor = contentResolver.query(
Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},
null, null, null);
mContactList.clear();
// 3.循环游标,直到没有数据为止
while (cursor.moveToNext()){
String id = cursor.getString(0);
Log.i("ContactListActivity",id);
// 4.根据用户唯一性id值,查询data表和mimetype表生成的视图,获取data以及mimetype字段
Cursor indexCursor = contentResolver.query(
Uri.parse("content://com.android.contacts/data"),
new String[]{"data1", "mimetype"},
"raw_contact_id = ?", new String[]{id}, null);
HashMap<String, String> hashMap = new HashMap<>();
while (indexCursor.moveToNext()){
// 5.循环获取每一个联系人的电话号码以及姓名
String data1 = indexCursor.getString(0);
String mimetype = indexCursor.getString(1);
// 区分类型填充数据
if (mimetype.equals("vnd.android.cursor.item/phone_v2")){
// 数据非空
if (!TextUtils.isEmpty(data1)){
hashMap.put("phone",data1);
}
}else if(mimetype.equals("vnd.android.cursor.item/name")){
// 数据非空
if (!TextUtils.isEmpty(data1)){
hashMap.put("name",data1);
}
}
}
// 6.关闭游标
indexCursor.close();
// 7.添加数据
mContactList.add(hashMap);
}
// 8.关闭游标
cursor.close();
// 9.发送消息给主线程
mHandler.sendEmptyMessage(0);
}
}.start();
}
/**
* 3.数据适配器内部类
*/
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return mContactList.size();
}
@Override
public HashMap<String, String> getItem(int position) {
return mContactList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(getApplicationContext(), R.layout.listview_contact_item, null);
TextView tv_name = view.findViewById(R.id.tv_name);
TextView tv_phone = view.findViewById(R.id.tv_phone);
tv_name.setText(getItem(position).get("name"));
tv_phone.setText(getItem(position).get("phone"));
return view;
}
}
}
16.手机防盗——选择联系人 & 结束activity没有传递intent
上一节中我们获取到了所有联系人的信息,现在需要为这些信息注册点击事件
- 修改ContactListActivity,修改initUI()方法,完善相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.example.mobilesafe.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ContactListActivity extends AppCompatActivity {
/**
* ListView
*/
private ListView lv_contact;
/**
* 存放联系人的集合
*/
private List<HashMap<String,String>> mContactList = new ArrayList<>();
/**
* 适配器对象
*/
private MyAdapter mAdapter = new MyAdapter();
/**
* Handler对象
*/
private Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
// 10.填充数据适配器
MyAdapter adapter = new MyAdapter();
lv_contact.setAdapter(adapter);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
// 初始化UI
intiUI();
// 初始化数据
initData();
}
/**
* 1.初始化UI
*/
private void intiUI() {
lv_contact = findViewById(R.id.lv_contact);
if (ContextCompat.checkSelfPermission(ContactListActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ContactListActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
}
lv_contact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 1.获取点中条目的索引,指向集合中的对象
if (mAdapter != null){
HashMap<String, String> item = mAdapter.getItem(position);
// 2.获取当前条目指向集合对应的电话号码
String phone = item.get("phone");
// 3.此电话号码需要给第三个导航界面使用
Intent intent = new Intent();
intent.putExtra("phone",phone);
setResult(0,intent);
// 4.结束当前Activity
finish();
}
}
});
}
/**
* 2.初始化数据
*/
private void initData() {
// 读取联系人是一个耗时操作,可以放在线程中执行
new Thread(){
@Override
public void run() {
// 1.获取内容解析器对象
ContentResolver contentResolver = getContentResolver();
// 2.封装查询过程
Cursor cursor = contentResolver.query(
Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},
null, null, null);
mContactList.clear();
// 3.循环游标,直到没有数据为止
while (cursor.moveToNext()){
String id = cursor.getString(0);
Log.i("ContactListActivity",id);
// 4.根据用户唯一性id值,查询data表和mimetype表生成的视图,获取data以及mimetype字段
Cursor indexCursor = contentResolver.query(
Uri.parse("content://com.android.contacts/data"),
new String[]{"data1", "mimetype"},
"raw_contact_id = ?", new String[]{id}, null);
HashMap<String, String> hashMap = new HashMap<>();
while (indexCursor.moveToNext()){
// 5.循环获取每一个联系人的电话号码以及姓名
String data1 = indexCursor.getString(0);
String mimetype = indexCursor.getString(1);
// 区分类型填充数据
if (mimetype.equals("vnd.android.cursor.item/phone_v2")){
// 数据非空
if (!TextUtils.isEmpty(data1)){
hashMap.put("phone",data1);
}
}else if(mimetype.equals("vnd.android.cursor.item/name")){
// 数据非空
if (!TextUtils.isEmpty(data1)){
hashMap.put("name",data1);
}
}
}
// 6.关闭游标
indexCursor.close();
// 7.添加数据
mContactList.add(hashMap);
}
// 8.关闭游标
cursor.close();
// 9.发送消息给主线程
mHandler.sendEmptyMessage(0);
}
}.start();
}
/**
* 3.数据适配器内部类
*/
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return mContactList.size();
}
@Override
public HashMap<String, String> getItem(int position) {
return mContactList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(getApplicationContext(), R.layout.listview_contact_item, null);
TextView tv_name = view.findViewById(R.id.tv_name);
TextView tv_phone = view.findViewById(R.id.tv_phone);
tv_name.setText(getItem(position).get("name"));
tv_phone.setText(getItem(position).get("phone"));
return view;
}
}
}
- 修改SetupThreeActivity,修改onActivityResult()方法,完善接收数据的相应逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.mobilesafe.R;
public class SetupThreeActivity extends AppCompatActivity {
/**
* "电话号码"编辑框
*/
private EditText et_phone_number;
/**
* "选择联系人"按钮
*/
private Button btn_select_number;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_three);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
Intent intent = new Intent(getApplicationContext(), SetupFourActivity.class);
startActivity(intent);
finish();
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
}
/**
* 3.初始化UI
*/
private void initUI() {
et_phone_number = findViewById(R.id.et_phone_number);
btn_select_number = findViewById(R.id.btn_select_number);
btn_select_number.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), ContactListActivity.class);
startActivityForResult(intent,0);
}
});
}
/**
* 4.Activity回调
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (data != null){
// 1.返回到当前界面后接收数据
String phone = data.getStringExtra("phone");
// 2.过滤特殊字符(中划线转换成空字符串)
phone.replace("-","").replace(" ","").trim();
et_phone_number.setText(phone);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
17.手机防盗——联系人回显过程
获取联系人信息后,我们应该将联系人信息存储到SharedPreferences中
- 修改ConstantValue,增加成员常量CONTACT_PHONE,表示被联系人的电话号码,代码如下:
package com.example.mobilesafe.constant;
public class ConstantValue {
/**
* 记录更新的状态
*/
public static final String OPEN_UPDATE = "open_update";
/**
* 手机防盗——设置密码的状态
*/
public static final String MOBILE_SAFE_PASSWORD = "mobile_safe_password";
/**
* 手机防盗——四个界面是否设置完成的状态
*/
public static final String SETUP_OVER = "setup_over";
/**
* 手机防盗——SIM卡绑定序列号
*/
public static final String SIM_NUMBER = "sim_number";
/**
* 手机防盗——联系人电话号码
*/
public static final String CONTACT_PHONE = "contact_phone";
}
- 修改SetupThreeActivity,修改onActivityResult()和nextPage()方法,完善存储逻辑,最后再修改initUI()方法,增加回显逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.utils.ToastUtil;
public class SetupThreeActivity extends AppCompatActivity {
/**
* "电话号码"编辑框
*/
private EditText et_phone_number;
/**
* "选择联系人"按钮
*/
private Button btn_select_number;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_three);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
// 点击按钮以后,需要获取输入框中的联系人,再做下一页操作
String phone = et_phone_number.getText().toString();
// sp中存储了相关联系人以后才可以跳转到下一个界面
// String contact_phone = SharedPreferencesUtil.getString(getApplicationContext(), ConstantValue.CONTACT_PHONE, "");
if (!TextUtils.isEmpty(phone)){
Intent intent = new Intent(getApplicationContext(), SetupFourActivity.class);
startActivity(intent);
finish();
// 如果是输入电话号码,同样需要保存
SharedPreferencesUtil.putString(getApplicationContext(), ConstantValue.CONTACT_PHONE,phone);
}else {
ToastUtil.show(this,"请输入电话号码!");
}
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupTwoActivity.class);
startActivity(intent);
finish();
}
/**
* 3.初始化UI
*/
private void initUI() {
et_phone_number = findViewById(R.id.et_phone_number);
// 回显过程
String phone = SharedPreferencesUtil.getString(this, ConstantValue.CONTACT_PHONE, "");
et_phone_number.setText(phone);
btn_select_number = findViewById(R.id.btn_select_number);
btn_select_number.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), ContactListActivity.class);
startActivityForResult(intent,0);
}
});
}
/**
* 4.Activity回调
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (data != null){
// 1.返回到当前界面后接收数据
String phone = data.getStringExtra("phone");
// 2.过滤特殊字符(中划线转换成空字符串)
phone.replace("-","").replace(" ","").trim();
et_phone_number.setText(phone);
// 3.存储联系人
SharedPreferencesUtil.putString(getApplicationContext(), ConstantValue.CONTACT_PHONE,phone);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
18.手机防盗——第四个导航界面编写
之前的小节中,我们完成了三个导航界面的编写,现在需要完成最后一个导航界面的编写
- 修改ConstatValue,增加OPEN_SECURITY常量,表示是否开启防盗保护,代码如下:
package com.example.mobilesafe.constant;
public class ConstantValue {
/**
* 设置中心——记录更新的状态
*/
public static final String OPEN_UPDATE = "open_update";
/**
* 手机防盗——设置密码的状态
*/
public static final String MOBILE_SAFE_PASSWORD = "mobile_safe_password";
/**
* 手机防盗——四个界面是否设置完成的状态
*/
public static final String SETUP_OVER = "setup_over";
/**
* 手机防盗——SIM卡绑定序列号
*/
public static final String SIM_NUMBER = "sim_number";
/**
* 手机防盗——联系人电话号码
*/
public static final String CONTACT_PHONE = "contact_phone";
/**
* 手机防盗——是否开启防盗保护总开关
*/
public static final String OPEN_SECURITY = "open_security";
}
- 修改SetupFourActivity,增加initUI()方法,完善对其视图的操作逻辑,最后再完善跳转逻辑,代码如下:
package com.example.mobilesafe.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;
import com.example.mobilesafe.utils.ToastUtil;
public class SetupFourActivity extends AppCompatActivity {
/**
* CheckBox控件
*/
private CheckBox cb_box;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_four);
// 初始化UI
initUI();
}
/**
* 1.“下一页”按钮的点击方法
* @param view
*/
public void nextPage(View view){
boolean open_security = SharedPreferencesUtil.getBoolean(this, ConstantValue.OPEN_SECURITY, false);
if (open_security){
Intent intent = new Intent(getApplicationContext(), SetupOverActivity.class);
startActivity(intent);
finish();
// 存储标识
SharedPreferencesUtil.putBoolean(this, ConstantValue.SETUP_OVER,true);
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
}else {
ToastUtil.show(getApplicationContext(),"请开启防盗保护");
}
}
/**
* 2.“上一页”按钮的点击方法
* @param view
*/
public void prePage(View view){
Intent intent = new Intent(getApplicationContext(), SetupThreeActivity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.pre_in_anim,R.anim.pre_out_anim);
}
/**
* 3.初始化UI
*/
private void initUI() {
cb_box = findViewById(R.id.cb_box);
// 1.是否选中状态的回显
boolean open_security = SharedPreferencesUtil.getBoolean(this, ConstantValue.OPEN_SECURITY, false);
// 2.根据状态,修改checkbox后续的文字显示
cb_box.setChecked(open_security);
if (open_security){
cb_box.setText("安全设置已开启");
}else {
cb_box.setText("安全设置已关闭");
}
// 3.点击过程中,checkbox状态的切换
cb_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// 4.状态切换后的存储
SharedPreferencesUtil.putBoolean(getApplicationContext(),ConstantValue.OPEN_SECURITY,isChecked);
// 5.根据开启关闭状态,去修改显示的文字
if (isChecked){
cb_box.setText("安全设置已开启");
}else {
cb_box.setText("安全设置已关闭");
}
}
});
}
}
19.手机防盗——平移动画分析
之前我们已经完成了四个导航界面的逻辑实现,现在需要做一个进一步优化——即让四个界面跳转时增加一个平移动画的效果
这里主要做出“上一页”和“下一页‘两个按钮在点击时所触发的效果,这一节主要分析平移动画
- "上一页"的动画逻辑图:
- "下一页"的动画逻辑图:
- 整体动画逻辑图:
平移动画总体可以划分为:
- 上一页
- 移入动画:(-屏幕宽度,y) ——> (0,y)
- 移出动画:(0,y) ——> (屏幕宽度,y)
- 下一页
- 移入动画:(屏幕宽度,y) ——> (0,y)
- 移出动画:(0,y) ——> (-屏幕宽度,y)
20.手机防盗——平移动画集成
经过上一节的分析后,我们现在开始着手实现平移动画
-
在res目录下新建anim,作为存放动画的文件夹,分别创建next_in_anim.xml,next_out_anim.xml,pre_in_anim.xml,pre_out_anim.xml
-
分别编写next_in_anim.xml,next_out_anim.xml,pre_in_anim.xml,pre_out_anim.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- -100%p 负一屏幕的宽度大小值-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="500">
</translate>
<?xml version="1.0" encoding="utf-8"?>
<!-- -100%p 负一屏幕的宽度大小值-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="-100%p"
android:duration="500">
</translate>
<?xml version="1.0" encoding="utf-8"?>
<!-- -100%p 负一屏幕的宽度大小值-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p"
android:toXDelta="0"
android:duration="500">
</translate>
<?xml version="1.0" encoding="utf-8"?>
<!-- -100%p 负一屏幕的宽度大小值-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="100%p"
android:duration="500">
</translate>
- 分别修改SetupOneActivity,SetupTwoActivity,SetupThreeActivity,SetupFourActivity,在nextPage()和prePage()中分别添加以下代码:
overridePendingTransition(R.anim.next_in_anim,R.anim.next_out_anim);
overridePendingTransition(R.anim.pre_in_anim,R.anim.pre_out_anim);