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);

相关文章
相关标签/搜索