- 寫一個歸屬地查詢的DAOandroid
// 根據手機號查詢歸屬地
public static String getAddress(Context ctx, String number) {
SQLiteDatabase db = SQLiteDatabase.openDatabase(new File(ctx.getFilesDir(),
"address.db").getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY);
String sql = "select cardtype from info where mobileprefix = ?";
String address = "未知";
// 判斷是否是手機號
// 正則 1 3/4/5/7/8 9位數字 ^1[34578]\d{9}$
if (number.matches("^1[34578]\\d{9}$")) {
String num = number.substring(0, 7);
String[] selectionArgs = new String[] { num };
Cursor cursor = db.rawQuery(sql, selectionArgs);
if (cursor != null) {
if (cursor.moveToNext()) {
address = cursor.getString(0);
}
cursor.close();
}
return address;
} else {
// 非手機號
int length = number.length();
switch (length) {
case 3:
address = "緊急電話";
break;
case 4:
address = "模擬器";
break;
case 5:
address = "服務電話";
break;
case 7:
case 8:
address = "本地電話";
break;
case 10:
case 11:
case 12:
sql = "select distinct city from info where area = ?";
String num = number.substring(0, 3);
String[] selectionArgs = new String[] { num };
Cursor cursor = db.rawQuery(sql, selectionArgs);
if (cursor != null) {
if (cursor.moveToNext()) {
address = cursor.getString(0);
}
cursor.close();
}
if (TextUtils.equals(address, "未知")) {
num = number.substring(0, 4);
selectionArgs = new String[] { num };
cursor = db.rawQuery(sql, selectionArgs);
if (cursor != null) {
if (cursor.moveToNext()) {
address = cursor.getString(0);
}
cursor.close();
}
}
break;
default:
break;
}
// 3 110 120 119 緊急電話
// 4 5556 模擬器
// 5 10086 10010 服務電話
// 7 本地固定電話 6212888
// 8 本地固定電話 62128889
// 10 010 6212888 帶區號的固定電話
// 11 010 62128889 0535 6212888 帶區號的固定電話
// 12 0535 62128889 帶區號的固定電話
}
return address;
}sql
- 在歸屬地查詢界面 實現查詢數組
String address = AddressADO.getAddress(getApplicationContext(), number);
tvLoc.setText(address);ide
- 根據輸入框輸入文字的改變實時查詢,要監聽輸入框的變化佈局
// 監聽文字改變
etNum.addTextChangedListener(new TextWatcher() {
// 顯示在輸入框上
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {post
}動畫
// 將要顯示在輸入框上
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {this
}orm
// 顯示在輸入框後
@Override
public void afterTextChanged(Editable s) {
String num = s.toString();
// 每次輸入框文字改變後 實時查詢更新
String address = AddressADO.getAddress(getApplicationContext(), num);
tvLoc.setText(address);
}
});xml
## 歸屬地顯示服務 ##
- 建立一個service 在設置頁面 開關
sivAddr.toggle();
// 判斷歸屬地顯示服務是否打開
if (ServiceState.isRunning(getApplicationContext(), AddressService.class)) {
// 關閉服務
stopService(new Intent(this, AddressService.class));
} else {
// 打開服務
startService(new Intent(this, AddressService.class));
}
在onresume 或onstart裏面顯示開關狀態
// 剛進入頁面判斷歸屬地顯示服務是否打開 設置對應的開關狀態
boolean isAddrRun = ServiceState.isRunning(getApplicationContext(), AddressService.class);
sivAddr.setToggleOn(isAddrRun);
- 經過查看toast源碼知道 能夠顯示在任意頁面上面的view 是添加到window上的
> 自定義一個toast 經過 WindowManager的addview方法給窗體添加一個view --------------會添加
// WindowManager 窗口管理器 能夠給窗口添加view
mWM = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
// 指定添加進窗口的view的佈局參數
params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
params.format = PixelFormat.TRANSLUCENT;
調整顯示級別 添加權限 SYSTEM_ALERT_WINDOW
params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
mWM.addView(viewAddress, params);
> 把view從窗體移除
if (viewAddress != null) {
// note: checking parent() just to make sure the view has
// been added... i have seen cases where we get here when
// the view isn't yet added, so let's try not to crash.
if (viewAddress.getParent() != null) {
mWM.removeView(viewAddress);
}
viewAddress = null;
}
> 自定義toast的顯示和消失,封裝到一個單獨的類裏 AddrToast
> 在服務裏監聽撥打電話和接聽電話
// 監聽來電
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
// 註冊一個播發電話的廣播接收者 權限 PROCESS_OUTGOING_CALLS
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
registerReceiver(receiver, filter);
> 在服務關閉的時候取消監聽
@Override
public void onDestroy() {
super.onDestroy();
// 服務關閉的時候 關掉來電和去電的監聽
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
unregisterReceiver(receiver);
}
> 在去電的廣播接收者接收者 和來電的監聽接口裏 控制自定義toast的顯示和取消
private PhoneStateListener listener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
// TelephonyManager#CALL_STATE_IDLE 空閒 沒有來電
// TelephonyManager#CALL_STATE_RINGING 來電
// TelephonyManager#CALL_STATE_OFFHOOK 摘機/接聽
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:// 來電
String address = AddressDao.queryAddress(getApplicationContext(),
incomingNumber);
addressToast.showAddress(address);
break;
case TelephonyManager.CALL_STATE_IDLE:// 空閒
addressToast.hide();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 接聽
// 什麼都不作 保持顯示狀態
break;
default:
break;
}
}
};
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 獲取撥打的電話號碼
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
String address = AddressDao.queryAddress(getApplicationContext(), number);
addressToast.showAddress(address);
}
};
- 自定義toast的觸摸移動 -----重點重點重點重點重點重點重點重點重點重點重點
> 首先設置view的觸摸監聽 --------重點重點重點重點重點重點重點重點重點重點重點重點
viewAddress.setOnTouchListener(this);
> 在監聽方法裏 監聽按下 移動 和擡起事件 計算手指移動距離 去移動view ------- 重點重點重點重點重點重點重點重點重點重點重點
// view 的觸摸事件 本身處理的話 返回true
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 手指按下
startX = (int) event.getRawX();
startY = (int) event.getRawY();
// System.out.println("起點座標x" + startX + "y" + startX);
break;
case MotionEvent.ACTION_MOVE:// 手指移動
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
// System.out.println("移動後坐標x" + moveX + "y" + moveY);
int distanceX = moveX - startX;
int distanceY = moveY - startY;
params.x = params.x + distanceX;// 更改view的佈局參數的位置爲移動後的位置
params.y = params.y + distanceY;
mWM.updateViewLayout(viewAddress, params);// 更新view的位置
startX = moveX;// 每次移動後 指向最新的起始點
startY = moveY;
break;
case MotionEvent.ACTION_UP:// 手指擡起
break;
default:
break;
}
return true;
}
- 防止通話中 又打來電話 顯示多個view 在顯示歸屬地以前 先刪除已經顯示的
## 歸屬地顯示風格設置 ##
- 選擇風格的 自定義dialog --------------要求會寫
> 繼承系統dialog類 public class AddressDialog extends Dialog
--
> 在oncreate方法裏調用 setContentView 實現佈局 相似於activity
> 將dialog設置顯示在屏幕下方 在構造方法裏 獲取window 調整window顯示位置
// 獲取dialog對應窗體
Window window = getWindow();
// 獲取佈局參數 設置dialog顯示在最下方 而且左右居中
LayoutParams layoutParams = window.getAttributes();
layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
window.setAttributes(layoutParams);
> 去標題欄 換背景色 和dialog的彈出消失動畫 須要設置對應的樣式
<style name="addr_style" parent="@android:style/Theme.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/white</item>
<item name="android:windowAnimationStyle">@style/AddrAnimationDialog</item>
</style>
<style name="AddrAnimationDialog">
<item name="android:windowEnterAnimation">@anim/input_method_enter</item>
<item name="android:windowExitAnimation">@anim/input_method_exit</item>
</style>
這裏拷貝了鍵盤的彈出消失動畫的文件
> 調用父類構造方法 設置樣式
public AddressDialog(Context context) {
super(context, R.style.addr_style);// 經過調用父類構造方法穿進去自定義dialog樣式
> 填充listview
1設置條目點擊事件
2保存選中的背景
3在撥號頁面顯示正確的背景
- listview 常量數組 背景id不一樣的話本身修改
private static final String[] mTitles = new String[] { "半透明", "活力橙", "衛士藍", "金屬灰", "蘋果綠" };
private static final int[] mBgs = new int[] { R.drawable.address_bg_normal,
R.drawable.address_bg_orange, R.drawable.address_bg_blue, R.drawable.address_bg_gray,
R.drawable.address_bg_green };
## 騰訊小火箭 ##
- 思路和自定義toast差很少 增長了座標的判斷 去發射小火箭
- 小火箭的火焰 幀動畫 兩張圖片不停切換
> 寫一個xml的動畫
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item
android:drawable="@drawable/desktop_rocket_launch_1"
android:duration="200"/>
<item
android:drawable="@drawable/desktop_rocket_launch_2"
android:duration="200"/>
</animation-list>
> 把xml的動畫設置爲小火箭imageview的背景
android:background="@drawable/rocket_animation"
> 獲取小火箭的幀動畫 並開啓
AnimationDrawable animationDrawable = (AnimationDrawable) imgRocket
.getBackground();
animationDrawable.start();
- mParams.gravity = Gravity.LEFT | Gravity.TOP;// 更改小火箭的顯示位置 讓原點和屏幕原點重合
- 小火箭的發射動畫 值動畫
值動畫 沒有view一些狀態改變 只是值的一個變化過程
ValueAnimator valueAnimator = ValueAnimator.ofInt(params.y, 0);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
System.out.println(animation.getAnimatedValue());
params.y = (Integer) animation.getAnimatedValue();
mWM.updateViewLayout(viewRocket, params);// 更新view的位置
}
});
valueAnimator.start();
- 小火箭的冒煙背景 是一個透明主題的activity
> 建立一個activity 設置主題爲透明
android:theme="@android:style/Theme.Translucent.NoTitleBar"
> 小夥箭發射後 打開背景activity 注意從service開啓activity的問題
Intent intent = new Intent(mContext, RocketBgActivity.class);
//從service開啓一個actvity 添加一個標誌 建立一個新的棧
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
> 讓背景漸變顯示 800毫秒後背景activity 消失
// 讓煙 漸變顯示出來
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(500);
imgTop.startAnimation(alphaAnimation);
imgM.startAnimation(alphaAnimation);
//動畫監聽
aa.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
//動畫結束 當前頁面消失
finish();
}
});
// 延時任務 800毫秒後執行 new Handler().postDelayed(new Runnable() { @Override public void run() { finish(); } }, 800);