360項目-06

- 寫一個歸屬地查詢的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);

相關文章
相關標籤/搜索