知识点 | 概念 | 注意事项 |
归属地显示功能 用户外拨 来电 时显示归属地 |
|
|
Service | 运行后台程序: 所有界面都退出 仍然运行程序 | 1.继承 2.重写 3.配置 4.启动 |
来电 | TelephoneManager通讯参数 1.sim卡号码 2.状态 响铃 接通 空闲 PhoneStateListener(来电号码) | 权限 READ_PHONE |
外拨 | BroadcastReceiver拦截外拨电话的广播
| action 权限 PROCESS_OUT_CALL 注意优先级 |
WindowManager | 1.系统级服务getSystemService 2.SYSTEM_ALERT 3.addView remove updateViewLayout | 顶级布局:显示在Activity这个布局 |
Layoutparams | 布局参数对象 宽 高 对齐 背景 ...类型 | x y |
OnTouchListener | 触摸监听器 | 注意事项 一个控件focusable =false clickable=false;或者 not_touchable |
风格设置 | AlertDialog.Builder:对话框快速创建工具 setSingleChoiceItems(); 保存下标 把下标对应一张图片。 |
|
位置设置 | Activity 布局一个视图 TouchListener 保存x,y marginLeft marginRight 显示布局的设置p.x p.y |
|
小火箭 | 1.Service 2.WindowUtils 3.Animaton-List 帧布局 4.TouchListener 5.范围判围 6.Thread+handler修改y-=50; 7.Activity 2000关闭 8.背景设置为透明theme 9.launchMode启动模式singleInstance |
|
两次点击退击 | 监听返回键onKeyDown return true 保存点击时间 时间间隔小于等于2000退出 | 1.系统时钟SystemClock 启动手机 2.System.arraycopy( 源数组,开始,目标数组,开始,个数) |
归属地显示
① 创建Service 1.继承2.重写3.配置4.启动 startService/stopService bindService/unbindService
② 监听来电号码
TelephonyManager:
| 1.系统级别的服务 getSystemService(); 2.权限 READ_PHONE 3.跟通讯参数相关的服务 sim 电话
|
PhoneStateListener | 监听器 状态 响铃 空闲 通话 获取号码 1.On...Listener 2.类 |
<span style="font-size:14px;"><!-- 获取手机状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
// ---------------------来电
// TelephonyManager:
// 1.系统级别的服务 getSystemService();
// 2.权限 READ_PHONE
// 3.跟通讯参数相关的服务 sim 电话
//
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// PhoneStateListener 监听器
// int state
// 状态 响铃 空闲 通话
listener = new PhoneStateListener() {
// 监听电话状态
// String incomingNumber来电话码
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 空闲
Log.i("wzx", "CALL_STATE_IDLE---");
break;
case TelephonyManager.CALL_STATE_RINGING:// 响铃
Log.i("wzx", "CALL_STATE_RINGING---");
Toast.makeText(getBaseContext(), "来电:" + incomingNumber, 0).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 接通
Log.i("wzx", "CALL_STATE_OFFHOOK---");
break;
}
}
};
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);// 添加监听器
// tm.listen(listener, PhoneStateListener.LISTEN_NONE);// 移除监听器</span>
3, 监听外拨号码
BroadcastReciever:广播接收者 接收广播 的对象
广播:Intent
1.继承 2.重写 3.配置
注意事项:1.action类型 例:外拨 boot sms
2.权限
3.优先级priority
注册方式:
a.标签注册
b.代码注册 在service
<span style="font-size:14px;"><!-- 外拨电话 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
// 获取号码
// 1.On...Listener
// 2.类
// ---------------------------外拨------
// BroadcastReciever:广播接收者 接收广播 的对象
// 广播:Intent
// 1.继承 2.重写 3.配置
// 注意事项:1.action类型 例:外拨 boot sms
// 2.权限
// 3.优先级priority
// 注册方式:
// a.标签注册
// b.代码注册 在service
// IntentFilter:给四大组件 绑定参数
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
registerReceiver(receiver, filter);
}
private CallReceiver receiver = new CallReceiver();
private class CallReceiver extends BroadcastReceiver {
// getResultData()获取号码
// 接收广播的时候
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getBaseContext(), "外拨:" + getResultData(), 0).show();
}
}
@Override
public void onDestroy() {
super.onDestroy();
tm.listen(listener, PhoneStateListener.LISTEN_NONE);// 移除监听器
Log.i("wzx", "归属地显示服务 销毁.....$$$$$");
unregisterReceiver(receiver);
}</span>
4, 自定义吐司
顶级布局:显示在Activity之上的一个布局 |
|
WindowManager | 1. 系统级的服务 getSystemService(); vibrator gps sim 2. 工具:可以把视图对象添加顶级布 add remove 3. 权限 |
a. 布局
b. 获取windowManager
c. 添加
<span style="font-size:14px;"><!-- 添加权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
public class WindowUtils {
/**
* 自定义吐司:添加视图到顶级布局
* @param context
* @param layoutId
* @param x
* @param y
* @return
*/
// 添加
public static View show(Context context, int layoutId,int x ,int y) {
// a.布局
// b.获取windowManager
View view = View.inflate(context, layoutId, null);
//
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//
// LayoutParams:布局参数对象
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
// layout_width宽
// layout_height高
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 内容对齐
params.gravity = Gravity.LEFT | Gravity.TOP;
// gravity
// background
// 背景
params.format = PixelFormat.TRANSLUCENT;
// flags其它
// focusable="true"
// clickable="false"
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不支持焦点
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不支持点击 触摸
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;// 屏幕亮
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;// 类型 :层级
params.x = x;
params.y = y;
// 坐标
// c.添加
wm.addView(view, params);// 往顶级布局里面添加视图对象
return view;
}
/**
* 从顶级布局里面移除
* @param context
* @param view
*/
// 删除
public static void remove(Context context, View view) {
// a.布局
// b.获取windowManager
//
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// c.添加
wm.removeView(view);// 往顶级布局里面删除 视图对象
}
}</span>
5,拖动事件
<span style="font-size:14px;">//获取显示对象
final Display display=wm.getDefaultDisplay();
final int SCREE_WIDHT=display.getWidth();
final int SCREE_HEIGHT=display.getHeight();
OnTouchListener listener = new OnTouchListener() {
// 用户触摸屏幕
private float x;
private float y;
// MotionEvent事件参数对象:封装 动作 1.按下 2.移动 3.提起
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 按下
x=event.getRawX();
y=event.getRawY();
break;
case MotionEvent.ACTION_MOVE:// 移动
float newx=event.getRawX();
float newy=event.getRawY();
//偏移量
float offx=newx-x;
float offy=newy-y;
//布局参数对象
WindowManager.LayoutParams params=(LayoutParams) view.getLayoutParams();
params.x+=offx;
params.y+=offy;
//
if(params.x<=0)
{
params.x=0;
}
if(params.y<=0)
{
params.y=0;
}
if(params.x>=(SCREE_WIDHT-view.getWidth()))
{
params.x=(SCREE_WIDHT-view.getWidth());
}
if(params.y>=(SCREE_HEIGHT -view.getHeight()))
{
params.y=(SCREE_HEIGHT -view.getHeight());
}
//更新视图在顶级布局中的位置
wm.updateViewLayout(view, params);
x=event.getRawX();
y=event.getRawY();
break;
case MotionEvent.ACTION_UP:// 提起
x=event.getRawX();
y=event.getRawY();
break;
}
return true;// 处理了事件
}
};
view.setOnTouchListener(listener);//添加事件</span>
params.x+=offx;
params.y+=offy;
//
if(params.x<=0)
{
params.x=0;
}
if(params.y<=0)
{
params.y=0;
}
if(params.x>=(SCREE_WIDHT-view.getWidth()))
{
params.x=(SCREE_WIDHT-view.getWidth());
}
if(params.y>=(SCREE_HEIGHT-view.getHeight()))
{
params.y=(SCREE_HEIGHT-view.getHeight());
}
WindowManager:添加的视图对象一定要注册移除。。
(6) 查询数据库
1.1. 归属地显示风格设置
修改 背景图片。
① 提供素材
② 设置中心添加 设置选项
③ 写点击事件
④ 弹出对话框
⑤ 选择:保存 下标SP-->对应一张图片
<span style="font-size:14px;">private String[] items=new String[]{"半透明","橙","蓝","灰","绿"};
@OnClick(R.id.set_address_style)
public void set_address_style(View view)
{
// ① 提供素材
// ② 设置中心添加 设置选项
// ③ 写点击事件
// ④ 弹出对话框
// AlertDialog.Builder//对话框快速创建 器
// AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog.Builder builder=new AlertDialog.Builder(SetCenterActivity.this);
builder.setTitle("归属地提示框风格");
int which=SharedPreferencesUtils.getInt(this, "set_address_style", 0);
//显示时选中 第几个项
builder.setSingleChoiceItems(items, which, new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferencesUtils.saveInt(getBaseContext(), "set_address_style",which);
//更新显示值 绿
set_address_style.getDesc().setText(items[which]);
dialog.dismiss();
}
});
builder.setNegativeButton("取消", null);
AlertDialog dialog=builder.create();
// ⑤ 选择:保存 下标SP-->对应一张图片
dialog.show();
}
注意回显
//更新显示值 绿
int which=SharedPreferencesUtils.getInt(this, "set_address_style", 0);
set_address_style.getDesc().setText(items[which]);</span>
1.2 归属地显示的位置
1.创建Activity
2.添加移动事件
3.退出页面 时保存
4. 使用保存的x,y
5.根据拖动的位置 显示 按钮
<span style="font-size:14px;">public class DragViewActivity extends Activity {
private int SCREEN_WIDTH;
private int SCREEN_HEGHT;
RelativeLayout view_adress_show;
private TextView top;
private TextView bottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drag_view);
top = (TextView) findViewById(R.id.top);
bottom = (TextView) findViewById(R.id.bottom);
// 获取WindowManager
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
view_adress_show = (RelativeLayout) findViewById(R.id.view_adress_show);
Display display = wm.getDefaultDisplay();
SCREEN_WIDTH = display.getWidth();
SCREEN_HEGHT = display.getHeight();
// 1.创建Activity
// 2.添加移动事件
// left top 120
// android:layout_marginLeft="120dp"
// android:layout_marginTop="120dp"
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) view_adress_show.getLayoutParams();
int x = SharedPreferencesUtils.getInt(this, "x", 0);
int y = SharedPreferencesUtils.getInt(this, "y", 0);
p.leftMargin = x;
p.topMargin = y;
// 以外
if (p.topMargin <= SCREEN_HEGHT / 3) {
top.setVisibility(View.INVISIBLE);
bottom.setVisibility(View.VISIBLE);
} else if (p.topMargin >= SCREEN_HEGHT * 2 / 3) {
top.setVisibility(View.VISIBLE);
bottom.setVisibility(View.INVISIBLE);
}
// view_adress_show.setLayoutParams(p);//方式一
view_adress_show.requestLayout();// 方式二
// OnTouchListener:监听拖动
OnTouchListener listener = new OnTouchListener() {
private float x = 0;
private float y = 0;
// 监听 触摸
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 按下
x = event.getRawX();
y = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:// 移动
float newx = event.getRawX();
float newy = event.getRawY();
// 偏移量
float offx = newx - x;
float offy = newy - y;
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) view_adress_show.getLayoutParams();
p.leftMargin += offx;
p.topMargin += offy;
final int leftMarginMax = SCREEN_WIDTH - view_adress_show.getWidth();
final int topMarginMax = SCREEN_HEGHT - view_adress_show.getHeight();
Log.i("wzx", "leftMarginMax=" + leftMarginMax);
Log.i("wzx", "topMarginMax=" + topMarginMax);
// 处理越界
if (p.leftMargin <= 0) {
p.leftMargin = 0;
}
if (p.leftMargin >= leftMarginMax) {
p.leftMargin = leftMarginMax;
}
if (p.topMargin <= 0) {
p.topMargin = 0;
}
if (p.topMargin >= topMarginMax) {
p.topMargin = topMarginMax;
}
// 以外
if (p.topMargin <= SCREEN_HEGHT / 3) {
top.setVisibility(View.INVISIBLE);
bottom.setVisibility(View.VISIBLE);
} else if (p.topMargin >= SCREEN_HEGHT * 2 / 3) {
top.setVisibility(View.VISIBLE);
bottom.setVisibility(View.INVISIBLE);
}
// 请求刷新
view_adress_show.requestLayout();
//
x = event.getRawX();
y = event.getRawY();
break;
case MotionEvent.ACTION_UP:// 提起
x = event.getRawX();
y = event.getRawY();
break;
}
return true;
}
};
view_adress_show.setOnTouchListener(listener);
// 3.退出页面 时保存
// 4. 使用保存的x,y
// 5.根据拖动的位置 显示 按钮
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) view_adress_show.getLayoutParams();
// p.leftMargin
// p.topMargin ;
SharedPreferencesUtils.saveInt(this, "x", p.leftMargin);
SharedPreferencesUtils.saveInt(this, "y", p.topMargin);
}
}</span>
1. 趣味小火箭
开发步骤
① 素材 (apk解压缩获取)
② 创建Service:运行于后台,没有界面,隐蔽程序(a.继承b.重写c.配置,d启动)
③ 通过WindowManager添加视图(小火箭+发射台)顶级布局。
④ 动画 帧动画。(帧动画(包含素材)+补间动画(旋转 透明度 移动 缩放))
帧动画:创建Animation-list 添加素材 设置时间 让素材快速播放。
⑤ OnTouchListener+修改坐标布局参数对象LayoutParams x ,y
⑥ 火箭移动画。Thread+Handler
⑦ 创建Activity显示云 Activity的透明效果
1. 趣味题:两次点击退出
① 返回的监听
② 保存两次点击的时间值
③ 时间间隔小于等于2000
④ 在主页面进行finish
<span style="font-size:14px;">/ 回调:由开发者重写的方法 但是 由系统去调用。 以on开头,注意:调用条件
// keyCode 键的id
private long[] twotimes = new long[2];
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// return true 处理事件 消费事件 不要系统处理
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 往前移动时间
twotimes[0] = twotimes[1];
twotimes[1] = System.currentTimeMillis();
Log.i("wzx", Arrays.toString(twotimes));
// ① 返回的监听
// ② 保存两次点击的时间值
// ③ 时间间隔小于等于2000
if (twotimes[1] - twotimes[0] <= 2000) {
// ④ 在主页面进行finish
finish();
} else {
Toast.makeText(getBaseContext(), "点击两次退出", 0).show();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
SystemClock.uptimeMillis() 开机时间为0
System.currentMillions 以格林尼治时间准备开始
long[] arrays = new long[] { 1, 2, 3, 4, 5, 6 };
public void arraycopy(View view) {
Log.i("wzx", Arrays.toString(arrays));
// System.arraycopy(源数组, 源数组开始复制的位置, 目标数组, 目标数组的开始复制位置, 个数);
System.arraycopy(arrays, 0, arrays, 3, 3);
Log.i("wzx", "复制后" + Arrays.toString(arrays));
}</span>
SystemClock.uptimeMillis() | 开机时间为0 |
System.currentMillions | 以格林尼治时间准备开始 |