标签:android开发
继续引导页第四个界面的实现 GuideActivity4.class的实现 给activity_guide4.xml的 checkBox加上id TextView也加上id(因为为了改变勾上后的text状态)
activity_guide4.xml
<TextView
style="@style/textview_title_style"
android:text="恭喜您设置完成"
android:textColor="#E2DED8"/>
<CheckBox
android:id="@+id/cb_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打勾,开启防盗保护"
android:textSize="24sp" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
回到GuideActivity4.class继续实现
给checkBox加上监听器(setOnCheckedChangeListener) 完善SharedpreferenceUtils里的存储方法,因为要使用到存储boolean的类型 SharedPreferencesUtil.java
public static void saveBoolean(Context context,String key ,boolean value) {
if(sp == null)
sp = context.getSharedPreferences(SP_NAME, 0);
sp.edit().putBoolean(key, value).commit();
}
public static boolean getBoolean(Context context,String key,boolean defValue){
if(sp == null)
sp = context.getSharedPreferences(SP_NAME, 0);
return sp.getBoolean(key, defValue);
}
上机测试下切换完成没 当点击下一步,我们就跳到手机防盗的界面,但是跳前要判断打勾没,没的话不让下一步 GuideActivity4.java
public class GuideActivity4 extends Activity {
private TextView tv_desc;
private Boolean isCheckedToNext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_guide4);
tv_desc = (TextView) findViewById(R.id.tv_desc);
CheckBox cb_check = (CheckBox) findViewById(R.id.cb_check);
cb_check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isCheckedToNext = isChecked;
if(isChecked){
tv_desc.setText("防盗保护已经开启");
SharedPreferencesUtil.saveBoolean(GuideActivity4.this, "protecting", isChecked);
}else{
tv_desc.setText("防盗保护已经关闭");
SharedPreferencesUtil.saveBoolean(GuideActivity4.this, "protecting", isChecked);
}
}
});
}
public void next(View view){
Boolean CheckStatus = SharedPreferencesUtil.getBoolean(GuideActivity4.this, "protecting",isCheckedToNext);
if(CheckStatus){
System.out.println("protecting"+CheckStatus+"");
Intent intent = new Intent(GuideActivity4.this,FindLostActivity.class);
startActivity(intent);
finish();
}else{
System.out.println("protecting"+CheckStatus+"");
Toast.makeText(this, "请开启防盗保护", 0).show();
}
}
public void pre(View view){
Intent intent = new Intent(GuideActivity4.this,GuideActivity3.class);
startActivity(intent);
finish();
}
}
FindLostActivity(手机防盗界面),注意配清单,加上Activity节点 设计手机防盗界面activityfindlost.xml,由于在布局方面自己的能力比较薄弱,尝试自己去看着实现图来敲,敲完再对比老师的源代码 activityfindlost.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/startpage" >
<TextView
style="@style/textview_title_style"
android:text="手机防盗"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="安全号码"
android:textSize="24sp"
android:textColor="#E2DED8"
/>
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="xxx"
android:textSize="24sp"
android:textColor="#E2DED8"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/list_devider" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="保护是否开启"
android:textSize="24sp"
android:textColor="#E2DED8"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="@drawable/unlock"
android:id="@+id/tv_lockChange"
/>
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/list_devider" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="重新进入设置向导"
android:onClick="bt_reset"
android:textSize="24sp"
android:textColor="#E2DED8"
android:background="@drawable/btn_selector"
/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/list_devider" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="功能简介"
android:textSize="24sp"
android:background="#88000000"
android:textColor="#E2DED8"
/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/list_devider" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GPS追踪:#*location*#"
android:drawableLeft="@android:drawable/star_big_on"
android:textSize="22sp"
android:textColor="#E2DED8"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="播放警报音乐:#*alarm*#"
android:drawableLeft="@android:drawable/star_big_on"
android:textSize="22sp"
android:textColor="#E2DED8"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="远程删除数据:#*wipedata*#"
android:drawableLeft="@android:drawable/star_big_on"
android:textSize="22sp"
android:textColor="#E2DED8"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="远程锁屏:#*lockscreen*#"
android:drawableLeft="@android:drawable/star_big_on"
android:textSize="22sp"
android:textColor="#E2DED8"
/>
</LinearLayout>
在样式里加上没有title的样式
注意在xml布局里,我们要设计线,用View控件设置background 想在同一行显示文字+其他别的东西,就用相对布局把控件扩起来进行调整 在textView左边加图片可以用属性android:drawableLeft="@an....." 完成就注入到FindLostActivity.class里,改变GuideActivity4.class的下一步按钮 实现FindLostActivity.class功能 从GuideActivity4.class获取传来的sp,获取电话号码到textView里
实现小锁图片的切换
从GuideActivity4.class传来的sp里判断去判断小锁的图片切换 在onCreate里补回一个判断,为了下一次访问时的状态显示:sp里是否有finishsetup的值,实现界面的跳转:(如果用户设置了防盗界面,那么用户直接进入到防盗界面,没有就跳回GuideActivity3.class) 在FindLostActivity.class里实现menu的功能,在该界面点击按钮menu会弹出main.xml
FindLostActivity.java
package com.itheima.phonesafeguard;
public class FindLostActivity extends Activity {
private TextView tv_phone;
private ImageView iv_lockChange;
private SharedPreferences sp;
private Boolean lockStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_find_lost);
sp = getSharedPreferences("config", MODE_PRIVATE);
sp.edit().putBoolean("setupcomplete", false).commit();
tv_phone = (TextView) findViewById(R.id.tv_phone);
iv_lockChange = (ImageView) findViewById(R.id.iv_lockChange);
lockStatus = sp.getBoolean("protecting", false);
String phone = SharedPreferencesUtil.getString(this, "phone", "");
tv_phone.setText(phone);
if(lockStatus){
iv_lockChange.setImageResource(R.drawable.lock);
sp.edit().putBoolean("setupcomplete", true).commit();
}
}
public void reset(View view){
Intent intent = new Intent(FindLostActivity.this,GuideActivity1.class);
startActivity(intent);
}
}
MainActivity.class
bt_ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//获取密码里面的值。然后判断2次输入的值是否一样
String et_password = et_pwd.getText().toString().trim();
if(TextUtils.isEmpty(et_password) ){
return ;
}
String pwd = sp.getString("pwd", "");
//如果sp里面缓存的密码和输入的密码一样的话。那么就进入防盗的引导界面
if(et_password.equals(pwd)){
SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);
Boolean setup = sp.getBoolean("setupcomplete", false);
String sim = sp.getString("sim", "");
if(setup && !TextUtils.isEmpty(sim)){
Intent intent = new Intent(MainActivity.this,FindLostActivity.class);
startActivity(intent);
dialog.dismiss();
// finish();
}else{
Intent intent = new Intent(MainActivity.this,GuideActivity1.class);
startActivity(intent);
dialog.dismiss();
// finish();
}
}else{
Toast.makeText(MainActivity.this, "2次密码不一致", 0).show();
}
}
});
strings.xml里修改些属性给main.xml使用,实现
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PhoneSafeguard</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="action_changename">修改手机防盗的名称</string>
</resources>
菜单栏的实现
在manu里的main.xml文档控制了Activity的一个菜单栏功能的布局,然而正常情况下该manu已经被屏蔽了,所以我们要使用的时候首先需要创建出来,然后再添加监听事件。
main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:title="@string/action_changename"/>
</menu>
加上菜单选中的方法:onOptionsItemSelected(MenuItem item),点击后弹出对话框 注意这个选中方法里的实现!
FindLostActivity.java
//菜单选中的方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("设置手机防盗的名称");
final EditText editText = new EditText(this);
builder.setView(editText);
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String result = editText.getText().toString().trim();
SharedPreferencesUtil.saveString(FindLostActivity.this, "changename", result);
}
});
builder.show();
return super.onOptionsItemSelected(item);
}
//创建菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
回到MainActivity,在View getView里改变图标1里的新的名字
MainActivity.class
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(MainActivity.this, R.layout.item_main_gridview, null);
TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
tv_name.setText(names[position]);
//在这里加载图片的时候可以加一个oom的解决机制
ImageView iv_icon = (ImageView) view.findViewById(R.id.iv_icon);
iv_icon.setImageResource(icon[position]);
String newname = SharedPreferencesUtil.getString(MainActivity.this, "changename", null);
//判断是否是第0个位置。如果是修改防盗的名称
if(position == 0){
if(!TextUtils.isEmpty(newname) && !TextUtils.isEmpty(sim)){
tv_name.setText(newname);
}
}
return view;
}
给设置了密码的sp加密 MD5加密算法写成Utils 用小demo(MD5Demo)来测试MD5 在MainActivity里加上MD5加密算法的代码 使用md5网站解密 写成Utils后在手机卫士的MainActivity里加入MD5的工具类给密码加密 测试前注意要清空sp 在应用汇!!!
package com.itheima.mobile47.utils;
public class MD5Util {
public static String encode(String result){
try {
StringBuilder sb = new StringBuilder();
//设置加密摘要
MessageDigest digest = MessageDigest.getInstance("md5");
byte[] digests= digest.digest(result.getBytes());
for(byte b : digests){
//获取到低八位
int number = b&0xff;
String hex = Integer.toHexString(number);
if(hex.length() == 1 ){
sb.append("0" + hex);
}else{
sb.append(hex);
}
}
return sb.toString();
} catch (Exception e) {
// TODO: handle exception
}
return "";
}
}
继续实现FindLostActivity.class里的重新进入设置向导的点击事件 给它加onClick属性:setEnterup和clickable属性等 为每个界面加上手势滑动识别 BaseGuideActivity新建,继承Activity,然后让每个引导界面都继承BaseGuideActivity 在BaseGuideActivity里设置手势识别器 课下总结两种手势识别器的实现方法 改造1到4个引导页的手势滑动方法 在BaseGuideActivity里的滑动过程加上动画效果
BaseGuideActivity.java
detector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
/**
* e1 表示手指第一次触摸到屏幕 e2 表示手指第二次触摸到屏幕 velocityx 表示x轴的速度
* velocityY 表示y轴的速度
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// 表示上一步
if (e2.getRawX() - e1.getRawX() > 0) {
System.out.println("上一步");
pre();
BaseGuideActivity.this.overridePendingTransition(R.anim.pre_in, R.anim.pre_out);
}
if(e2.getRawX() - e1.getRawX() < 0){
System.out.println("表示下一步");
next();
BaseGuideActivity.this.overridePendingTransition(R.anim.next_in, R.anim.next_out);
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
在res底下新建一个动画包anim
prein.xml(translate) preout.xml(translate) pre_in.xml(translate)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
pre_out.xml(translate)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="100%p"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
设计设置中心的功能:取消更新提示 在MainActivity.class里加上case 8的操作
case 8:
intent = new Intent(MainActivity.this,SettingCenterActivity.class);
startActivity(intent);
break;
}
新建SettingCenterActivity.class
SettingCenterActivity.class
public class SettingCenterActivity extends Activity {
private CheckBox cb_state;
private SettingView setting_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting_center);
setting_view = (SettingView) findViewById(R.id.setting_view_update);
//首先进来判断当前是否需要更新
boolean result = SharedPreferencesUtil.getBoolean(SettingCenterActivity.this, "isupdate", false);
if(result){
setting_view.setChecked(true);
}else{
setting_view.setChecked(false);
}
setting_view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//判断当前的settingview里面的cb有没有被选中
if(setting_view.isChecked()){
LogUtil.d(SettingCenterActivity.this, "哈哈");
setting_view.setChecked(false);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", false);
}else{
LogUtil.d(SettingCenterActivity.this, "嘎嘎");
setting_view.setChecked(true);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", true);
}
}
});
}
}
配置清单
<!-- 设置中心的界面 -->
<activity
android:name="com.itheima.mobile47.SettingCenterActivity"
android:screenOrientation="portrait" >
</activity>
设计设置中心的布局activitysettingcenter.xml
activitysettingcenter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.mobile47"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
style="@style/textview_title_style"
android:gravity="center"
android:text="设置中心" />
<com.itheima.mobile47.view.SettingView
android:id="@+id/setting_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
itheima:desc="自动更新已经开启#自动更新已经关闭"
itheima:title="自动更新设置" >
</com.itheima.mobile47.view.SettingView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/list_devider" />
<com.itheima.mobile47.view.SettingView
android:id="@+id/setting_view_black"
android:layout_width="match_parent"
android:layout_height="wrap_content"
itheima:desc="黑名单更新已经开启#黑名单更新已经关闭"
itheima:title="黑名单设置" >
</com.itheima.mobile47.view.SettingView>
</LinearLayout>
我们想点击整个框就可以激活checkbox, 回到SettingCenterActivity.class去设置:获取控件 还有去掉点击checkbox点击时有篮框的样式 在查询完系统默认的checkbox的样式后,我们复制到我们的style.xml里去使用 新增btn_check.xml到drawable里,在checkbox的控件里加上该样式
btn_check.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Enabled states -->
<item android:state_checked="true"
android:drawable="@drawable/btn_check_on" />
<item android:state_checked="false"
android:drawable="@drawable/btn_check_off" />
</selector>
继续设置中心SettingCenterActivity.class的xml布局activitysettingcenter.xml 把里面的每一个相对布局抽取出来settingView.class 继承RelativeLayout
settingView.class
public class SettingView extends RelativeLayout {
private TextView tv_title;
private TextView tv_desc;
private CheckBox cb_states;
private String[] descs;
public SettingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
System.out.println("----->3");
}
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
//设置描述信息
private void setDescs(String[] descs, boolean checked) {
if(checked){
tv_desc.setText(descs[0]);
tv_desc.setTextColor(Color.GREEN);
cb_states.setChecked(true);
}else{
tv_desc.setText(descs[1]);
tv_desc.setTextColor(Color.RED);
cb_states.setChecked(false);
}
}
private void setTitle(String title) {
tv_title.setText(title);
}
public SettingView(Context context) {
super(context);
System.out.println("----->1");
}
public boolean isChecked() {
// TODO Auto-generated method stub
return cb_states.isChecked();
}
public void setChecked(boolean checked) {
if(checked){
if(tv_desc != null){
tv_desc.setText(descs[0]);
tv_desc.setTextColor(Color.GREEN);
cb_states.setChecked(true);
}
}else{
if(tv_desc != null){
tv_desc.setText(descs[1]);
tv_desc.setTextColor(Color.RED);
cb_states.setChecked(false);
}
}
}
}
继续为该布局设计一个布局xml:uisettingview.xml
uisettingview.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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="自动更新设置"
android:textColor="#000"
android:textSize="24sp" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:text="自动更新已经关闭"
android:textColor="#88000000"
android:textSize="20sp" />
<CheckBox
android:id="@+id/cb_states"
android:clickable="false"
android:focusable="false"
android:button="@drawable/btn_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
然后引入到settingView.class里 然后在原来的activitysettingcenter.xml里把原来的Relativelayout改成自定义的控件类 activitysettingcenter.xml
<com.itheima.mobile47.view.SettingView
android:id="@+id/setting_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
itheima:desc="自动更新已经开启#自动更新已经关闭"
itheima:title="自动更新设置" >
</com.itheima.mobile47.view.SettingView>
测试自定义的控件类settingView.class里的构造函数初始化时调用的是哪一个。
找到之后就通过代码把uisettingview.xml注入到控件里来(并获取布局里的控件,在该类settingView.class通过方法控制显示checkbox控制的textView状态)
settingView.class
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
在SettingCenterActivity.class里调用SettingView控件,添加点击监听事件 再把checkbox和textView联动起来,在checkBox里设置下属性(false)
SettingCenterActivity.class
setting_view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//判断当前的settingview里面的cb有没有被选中
if(setting_view.isChecked()){
LogUtil.d(SettingCenterActivity.this, "哈哈");
setting_view.setChecked(false);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", false);
}else{
LogUtil.d(SettingCenterActivity.this, "嘎嘎");
setting_view.setChecked(true);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", true);
}
}
});
写一个LogUtil工具类,用来测试用:通过置换mode来控制我们在代码中嵌入的LogUtil中的日志方法,如果不想输出就在类中修改mode就行 加上开关更新提醒的功能
LogUtil.java
public class LogUtil {
public static final boolean mode = true;
public static void d(Object obj,String msg){
if(mode){
Log.d(obj.getClass().getSimpleName(), msg);
}
}
}
然后修改SplashActivity.class,在里面增加代码检查sp里是否有内容,从而判断是否需要获取更新的数据
SplashActivity.class
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
//获取是否更新的数据
boolean result = SharedPreferencesUtil.getBoolean(SplashActivity.this, "isupdate", false);
if(result){
// 检查版本号
checkVersion();
// checkVersion2();
}else{
//防止进入主界面太快。所以睡一觉
new Thread(){
public void run() {
try {
Thread.sleep(2000);
mainUI();
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
继续修改小bug,在SettingCenterActivity里增加代码检查sp是否更新,是就一个状态,否就另外一个状态(text的内容)
SettingCenterActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting_center);
setting_view = (SettingView) findViewById(R.id.setting_view_update);
//首先进来判断当前是否需要更新
boolean result = SharedPreferencesUtil.getBoolean(SettingCenterActivity.this, "isupdate", false);
if(result){
setting_view.setChecked(true);
}else{
setting_view.setChecked(false);
}
继续在SettingCenterACtivity.class的布局文件activitysettingcenter.xml增加自定义view,即增加条目,显示出自定义的view的方便性
这里有些难,也有些重要! 我们的条目信息又自定义的控件控制数据,但是我们的数据已经写死了 修改自定义控件类,布局引用里的自定义控件加上我们自己的属性 但是这样设置不了,因为自定义控件类是包装了几个控件的, 那么我们观察下系统的源码,找出解决的办法 在value目录底下定义一个attrs.xml,然后回到activitysettingcenter.xml继续修改
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="settingview">
<attr name="title" format="string" />
<attr name="desc" format="string" />
</declare-styleable>
</resources>
然后在自定义的类中增加desc、title
SettingView.java
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
继续修改SettingView.java,在初始化构造函数中加上自定义的命名空间,获取title和desc,从而在该类型中获取到布局中传来的设置信息, 继续把写死的地方进行修改。
理解下自定义控件中的自定义属性的步骤
1、自定义命名空间
2、自定义属性
1、需要在values下面新建一个attrs.xml的配置文件
3、在自定义view的类中的两个参数的构造方法里面设置如下代码
理解不了就查看源码,看lineralayout控件的属性时怎么实现的-->sdk--->plaform--->attrs.xml里查lineralayout
(复制老师的笔记)
1 自定义命名空间
xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.mobile47"
itheima 这个值可以随便定义:随便取名字
com.itheima.mobile47 这个是应用程序的包名
2 自定义属性:
在values下面新建一个attrs.xml的配置文件
<resources>
<declare-styleable name="settingview">
<attr name="title" format="string" />
<attr name="desc" format="string" />
</declare-styleable>
</resources>
settingview : 这个值你可以随便取
title :这个值也可以随便取
string :就是当前值的类型
3 在自定义view的类中的两个参数的构造方法里面设置如下代码
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
为FindLostActivity.class里的提示信息实现功能,即使用广播去控制被盗的手机,即按照规则发送信息到被盗手机(前提是卡没有)
在清单文件里新建receiver
<!-- 手机防盗的广播 -->
<receiver android:name="com.itheima.mobile47.receiver.SmsReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
新建一个接收短信的receiver类继承广播类SmsReceive
public class SmsReceiver extends BroadcastReceiver 配好清单文件
继续配receiver中的intent-filter
<!-- 手机防盗的广播 -->
<receiver android:name="com.itheima.mobile47.receiver.SmsReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
实现报警音乐,在receiver中使用MediaPlayer 把音乐放在raw文件夹里
SmsReceiver.java
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("短信来了");
// 获取到短信的数组
Object[] objs = (Object[]) intent.getExtras().get("pdus");
// 获取到设备管理的Manager
DevicePolicyManager mDPM = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
for (Object obj : objs) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);
// 获取到短信的电话号码
String number = smsMessage.getOriginatingAddress();
// 获取到短信的内容
String body = smsMessage.getMessageBody();
if (body.equals("#*alarm*#")) {
System.out.println("报警音乐");
MediaPlayer mediaPlayer = MediaPlayer.create(context,
R.raw.alarm);
mediaPlayer.setVolume(1.0f, 1.0f);
mediaPlayer.start();
abortBroadcast();
}
实现擦除数据功能:为了防止小偷偷看手机里的数据,即恢复出厂设置 即调用手机里已经实现了的功能就行(恢复出厂设置) (难) - 我们如何导入安卓源码 - sdk-->plaform--->dandroid(版本)-->sample - 在search去找擦除数据功能:建议看回视频 - 把控制擦除数据功能和锁屏功能的清单文件数据复制到清单文件中 - 在res里面新建一个xml - 写一个receiver(DeviceAdminSample)继承DeviceAdminReceiver - 继续在SmsReceiver.java里继续实现擦除数据和锁屏的功能 - 同时锁屏还要加上设置密码的功能
<!-- 系统管理的广播 -->
<receiver
android:name="com.itheima.mobile47.receiver.DeviceAdminSample"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
SmsReceiver.java
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("短信来了");
// 获取到短信的数组
Object[] objs = (Object[]) intent.getExtras().get("pdus");
// 获取到设备管理的Manager
DevicePolicyManager mDPM = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
for (Object obj : objs) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);
// 获取到短信的电话号码
String number = smsMessage.getOriginatingAddress();
// 获取到短信的内容
String body = smsMessage.getMessageBody();
if (body.equals("#*wipedata*#")) {
System.out.println("擦除数据");
mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
abortBroadcast();
}
if (body.equals("#*lockscreen*#")) {
System.out.println("锁屏");
mDPM.lockNow();
abortBroadcast();
}
继续实现地理位置:不能放在广播里面(广播生命周期短,而地理位置是一个耗时的操作),要放在服务里面实现,在广播里打开服务 新建包新建服务类LocationService-->清单文件配置,让SmsReceiver跳到该服务中 新建一个测试地理位置的demo,测试成功后再放到代码中
操作技巧:如何先输入方法,然后快捷键定义变量接收返回值
把代码复制到LocationService里:获取到了位置后通过短信发到目的号码中
<!-- 地理位置的服务 -->
<service android:name="com.itheima.mobile47.service.LocationService" >
</service>
SmsReceiver.java
if (body.equals("#*location*#")) {
System.out.println("地理位置");
Intent mLocationService = new Intent(context,LocationService.class);
context.startService(mLocationService);
abortBroadcast();
}
LocationService.java
public class LocationService extends Service {
private MyLocationListener listener;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
// 第一个是请求的provider
// 第二个参数表示最短时间
// 第三个参数表示最短的距离
// 第四个参数表示监听
listener = new MyLocationListener();
// 设置查询的条件
Criteria criteria = new Criteria();
// 设置精确的
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// 设置允许产生开销
criteria.setCostAllowed(true);
//获取到最好的provider
String provider = lm.getBestProvider(criteria, true);
lm.requestLocationUpdates(provider, 0, 0, listener);
}
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
StringBuilder sb = new StringBuilder();
// 获取到经度
double longitude = location.getLongitude();
// 获取到纬度
double latitude = location.getLatitude();
System.out.println("经度--->" + longitude);
System.out.println("纬度--->" + latitude);
sb.append("jingdu" + longitude + "" + "weidu" + latitude);
String phone = SharedPreferencesUtil.getString(LocationService.this, "phone", "");
SmsManager.getDefault().sendTextMessage(phone, null, sb.toString(), null, null);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
strings.xml里修改些属性给main.xml使用,实现
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PhoneSafeguard</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="action_changename">修改手机防盗的名称</string>
</resources>
菜单栏的实现
在manu里的main.xml文档控制了Activity的一个菜单栏功能的布局,然而正常情况下该manu已经被屏蔽了,所以我们要使用的时候首先需要创建出来,然后再添加监听事件。
main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:title="@string/action_changename"/>
</menu>
加上菜单选中的方法:onOptionsItemSelected(MenuItem item),点击后弹出对话框 注意这个选中方法里的实现!
FindLostActivity.java
//菜单选中的方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("设置手机防盗的名称");
final EditText editText = new EditText(this);
builder.setView(editText);
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String result = editText.getText().toString().trim();
SharedPreferencesUtil.saveString(FindLostActivity.this, "changename", result);
}
});
builder.show();
return super.onOptionsItemSelected(item);
}
//创建菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
在BaseGuideActivity里的滑动过程加上动画效果
BaseGuideActivity.java
detector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
/**
* e1 表示手指第一次触摸到屏幕 e2 表示手指第二次触摸到屏幕 velocityx 表示x轴的速度
* velocityY 表示y轴的速度
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// 表示上一步
if (e2.getRawX() - e1.getRawX() > 0) {
System.out.println("上一步");
pre();
BaseGuideActivity.this.overridePendingTransition(R.anim.pre_in, R.anim.pre_out);
}
if(e2.getRawX() - e1.getRawX() < 0){
System.out.println("表示下一步");
next();
BaseGuideActivity.this.overridePendingTransition(R.anim.next_in, R.anim.next_out);
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
在res底下新建一个动画包anim prein.xml(translate) preout.xml(translate) pre_in.xml(translate)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
pre_out.xml(translate)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="100%p"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
选择器的实现
delet_selector.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/ic_delete_btn_focused" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="@drawable/ic_delete_btn_focused" /> <!-- focused -->
<item android:drawable="@drawable/ic_delete_btn" /> <!-- default -->
</selector>
itemcallsafe.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="wrap_content"
>
<ImageView
android:id="@+id/iv_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/delet_selector"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
/>
</RelativeLayout>
自定义控件的实现(难点)
继续设置中心SettingCenterActivity.class的xml布局activitysettingcenter.xml 把里面的每一个相对布局抽取出来settingView.class 继承RelativeLayout
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="settingview">
<attr name="title" format="string" />
<attr name="desc" format="string" />
</declare-styleable>
</resources>
settingView.class
public class SettingView extends RelativeLayout {
private TextView tv_title;
private TextView tv_desc;
private CheckBox cb_states;
private String[] descs;
public SettingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
System.out.println("----->3");
}
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
//设置描述信息
private void setDescs(String[] descs, boolean checked) {
if(checked){
tv_desc.setText(descs[0]);
tv_desc.setTextColor(Color.GREEN);
cb_states.setChecked(true);
}else{
tv_desc.setText(descs[1]);
tv_desc.setTextColor(Color.RED);
cb_states.setChecked(false);
}
}
private void setTitle(String title) {
tv_title.setText(title);
}
public SettingView(Context context) {
super(context);
System.out.println("----->1");
}
public boolean isChecked() {
// TODO Auto-generated method stub
return cb_states.isChecked();
}
public void setChecked(boolean checked) {
if(checked){
if(tv_desc != null){
tv_desc.setText(descs[0]);
tv_desc.setTextColor(Color.GREEN);
cb_states.setChecked(true);
}
}else{
if(tv_desc != null){
tv_desc.setText(descs[1]);
tv_desc.setTextColor(Color.RED);
cb_states.setChecked(false);
}
}
}
}
继续为该布局设计一个布局xml:uisettingview.xml
uisettingview.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="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="自动更新设置"
android:textColor="#000"
android:textSize="24sp" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:text="自动更新已经关闭"
android:textColor="#88000000"
android:textSize="20sp" />
<CheckBox
android:id="@+id/cb_states"
android:clickable="false"
android:focusable="false"
android:button="@drawable/btn_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
然后引入到settingView.class里 然后在原来的activitysettingcenter.xml里把原来的Relativelayout改成自定义的控件类 activitysettingcenter.xml
<com.itheima.mobile47.view.SettingView
android:id="@+id/setting_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
itheima:desc="自动更新已经开启#自动更新已经关闭"
itheima:title="自动更新设置" >
</com.itheima.mobile47.view.SettingView>
测试自定义的控件类settingView.class里的构造函数初始化时调用的是哪一个。
找到之后就通过代码把uisettingview.xml注入到控件里来(并获取布局里的控件,在该类settingView.class通过方法控制显示checkbox控制的textView状态)
settingView.class
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
在SettingCenterActivity.class里调用SettingView控件,添加点击监听事件 再把checkbox和textView联动起来,在checkBox里设置下属性(false)
SettingCenterActivity.class
setting_view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//判断当前的settingview里面的cb有没有被选中
if(setting_view.isChecked()){
LogUtil.d(SettingCenterActivity.this, "哈哈");
setting_view.setChecked(false);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", false);
}else{
LogUtil.d(SettingCenterActivity.this, "嘎嘎");
setting_view.setChecked(true);
SharedPreferencesUtil.saveBoolean(SettingCenterActivity.this, "isupdate", true);
}
}
});
继续修改小bug,在SettingCenterActivity里增加代码检查sp是否更新,是就一个状态,否就另外一个状态(text的内容)
SettingCenterActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting_center);
setting_view = (SettingView) findViewById(R.id.setting_view_update);
//首先进来判断当前是否需要更新
boolean result = SharedPreferencesUtil.getBoolean(SettingCenterActivity.this, "isupdate", false);
if(result){
setting_view.setChecked(true);
}else{
setting_view.setChecked(false);
}
继续在SettingCenterACtivity.class的布局文件activitysettingcenter.xml增加自定义view,即增加条目,显示出自定义的view的方便性
这里有些难,也有些重要!
我们的条目信息又自定义的控件控制数据,但是我们的数据已经写死了 修改自定义控件类,布局引用里的自定义控件加上我们自己的属性 但是这样设置不了,因为自定义控件类是包装了几个控件的, 那么我们观察下系统的源码,找出解决的办法 在value目录底下定义一个attrs.xml,然后回到activitysettingcenter.xml继续修改 attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="settingview">
<attr name="title" format="string" />
<attr name="desc" format="string" />
</declare-styleable>
</resources>
然后在自定义的类中增加desc、title
SettingView.java
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("----->2");
//第一个参数是命名空间 ,第二个参数是自定义属性的名字
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
String desc = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "desc");
View view = View.inflate(context, R.layout.ui_setting_view, null);
this.addView(view);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_states = (CheckBox) view.findViewById(R.id.cb_states);
setTitle(title);
descs = desc.split("#");
setDescs(descs,false);
}
继续修改SettingView.java,在初始化构造函数中加上自定义的命名空间,获取title和desc,从而在该类型中获取到布局中传来的设置信息, 继续把写死的地方进行修改。
理解下自定义控件中的自定义属性的步骤 1、自定义命名空间 2、自定义属性 1、需要在values下面新建一个attrs.xml的配置文件 3、在自定义view的类中的两个参数的构造方法里面设置如下代码
理解不了就查看源码,看lineralayout控件的属性时怎么实现的-->sdk--->plaform--->attrs.xml里查lineralayout
(复制老师的笔记)
1 自定义命名空间(这个非常重要,如果不加,itheima就无法和attrs.xml里的item关联起来:即下面的实例itheima:desc="自动更新已经开启#自动更新已经关闭"无效)
xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.mobile47"
itheima 这个值可以随便定义:随便取名字
com.itheima.mobile47 这个是应用程序的包名
2 自定义属性:
在values下面新建一个attrs.xml的配置文件
<resources>
<declare-styleable name="settingview">
<attr name="title" format="string" />
<attr name="desc" format="string" />
</declare-styleable>
</resources>
settingview : 这个值你可以随便取
title :这个值也可以随便取
string :就是当前值的类型
3 在自定义view的类中的两个参数的构造方法里面设置如下代码 //第一个参数是命名空间 ,第二个参数是自定义属性的名字 String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itheima.mobile47", "title");
定义完之后的直接展示
<com.itheima.mobile47.view.SettingView
android:id="@+id/setting_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
itheima:desc="自动更新已经开启#自动更新已经关闭"
itheima:title="自动更新设置" >
</com.itheima.mobile47.view.SettingView>
标签:android开发
原文地址:http://blog.csdn.net/faith_yee/article/details/44917935