Skip to content

Latest commit

 

History

History
318 lines (277 loc) · 13.3 KB

来电号码归属地提示框.md

File metadata and controls

318 lines (277 loc) · 13.3 KB

来电号码归属地提示框

模仿Toast实现提示框

Toast提示只要提示的时间够长,就可以浮动到其他任何界面之上,所以我们可以模仿Toast来实现来电号码归属地的提示框

  1. WindowManager
    The interface that apps use to talk to the window manager. Use Context.getSystemService(Context.WINDOW_SERVICE) to get one of these. Each window manager instance is bound to a particular Display.

    1. void addView(View view,ViewGroup.LayoutParams params)
      将一个View视图显示到当前窗口,LayoutParams are used by views to tell their parents how they want to be laid out.

    2. void removeView(View view); 将一个View视图从当前窗口中移除。

  2. 自定义窗体提示框(参考Toast源码)

    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); 
    View view = View.inflate(getApplicationContext(), R.layout.toast_location,
    				null); 
    TextView tv = (TextView) view.findViewById(R.id.tv_toast_address);
    tv.setText(address);
    LayoutParams params = new LayoutParams();
    params.height = WindowManager.LayoutParams.WRAP_CONTENT;
    params.width = WindowManager.LayoutParams.WRAP_CONTENT;
    params.gravity = Gravity.LEFT | Gravity.TOP;
    params.x = sp.getInt("lastx", 0);
    params.y = sp.getInt("lasty", 0);
    //本来还有一个FLAG_NOTUCHALBE为了让下面能触摸把这个给去掉了
    params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
    		| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
    params.format = PixelFormat.TRANSLUCENT;	//源码中这里是TYPE_TAOST但是这里为了下面要进行点击拖动事件,而Toast不能拖动,
    所以这里改成了TYPE_PRIORITY_PHONE,这是个系统类型的提示框,使用这个提示框必须要申请权限,android.permission.SYSTEM_ALERT_WINDOW
    params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; 
    wm.addView(view, params); 
  3. WindowManager添加的显示框的简单拖动
    该这个View注册一个onTouchListener

    public void showLocation(String address) {
        view = View.inflate(getApplicationContext(), R.layout.toast_location,
                null);
        // 得到sp
        int which = sp.getInt("which", 0);
        view.setBackgroundResource(bgs[which]);
        view.setOnTouchListener(new OnTouchListener() {
            int startX ,startY;
    
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG,"摸到");
                    startX = (int) event.getRawX();
                    startY  = (int) event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i(TAG,"移动");
                    int newX = (int) event.getRawX();
                    int newY  = (int) event.getRawY();
                    int dx = newX - startX;
                    int dy = newY - startY;
                    params.x+=dx;
                    params.y+=dy;	//这里在WindowManager中不能够使用layout方法了,无效,只能使用layoutparams来更新位置,这里的params就是上面的那个params
                    wm.updateViewLayout(view, params);
                    //重新初始化 手指的位置
                    startX = (int) event.getRawX();
                    startY  = (int) event.getRawY();
                    break;
                }
                return true;
            }
        });
    }
  4. 普通ImageView随手指拖动改变位置

    iv_drag_view.setOnTouchListener(new OnTouchListener() {
    	//记录住最初手指按下时的位置
    	int startX , startY; 
    	//onTouch方法的返回值如果是true监听器会把这个事件给消费掉, false则监听器不会消费掉这个事件
    	public boolean onTouch(View v, MotionEvent event) {
    		switch (event.getAction()) {  
    			case MotionEvent.ACTION_DOWN:
    				Log.i(TAG,"摸到这个控件了");
    				startX = (int) event.getRawX();//记录手指第一次点击到屏幕时候距离x和y轴的距离
    				startY = (int) event.getRawY();
    			break;
    			case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动的事件
    				Log.i(TAG,"移动");
    				int newX = (int) event.getRawX(); //在移动的过程中不断的获取到手指当前移动到的位置
    				int newY = (int) event.getRawY();
    				int dx = newX - startX;           //计算出手指移动了多少
    				int dy = newY - startY;
    				int l = iv_drag_view.getLeft(); //获取图片上下左右的长度
    				int r = iv_drag_view.getRight();
    				int b = iv_drag_view.getBottom();
    				int t = iv_drag_view.getTop();
    						
    				int newl = l+dx; //计算图片应该移动的距离
    				int newr = r+dx;
    				int newt = t+dy;//imageview 在窗体中新的位置
    				int newb = b+dy;
    						
    				//判断如果图片准备移动到的位置超出了屏幕就不让它移动,这里减去30是减去窗体上面的状态栏的高度
    				if(newl<0||newt < 0 ||newb>display.getHeight()-30||newr>display.getWidth()){
    					break;
    				}            
    				//将图片移动到新的位置。直接调用ImageView的layout方法
    				iv_drag_view.layout(newl,  newt, newr, newb); 
    				//一旦图片移动到新的位置就重新计算手指当前的位置,这样循环下去就能实现随着手指的拖动
    				startX = (int) event.getRawX();
    				startY = (int) event.getRawY();
    			break;
    			case MotionEvent.ACTION_UP: // 手指在离开屏幕的一瞬间对应的事件.
    			Log.i(TAG,"放手");
    			int lasty = iv_drag_view.getTop();//得到最后在离屏幕上方的距离
    			int lastx = iv_drag_view.getLeft();//得到最后离屏幕左边的距离
    			Editor editor = sp.edit();
    			editor.putInt("lastx", lastx);
    			editor.putInt("lasty", lasty);
    			editor.commit();
    			break;
    		}
    			return true; //这地方一定要返回true告诉系统这个事件做完了
    	}
    });

    注意:在onCreate方法中使用layout方法是没有效果的,因为在进入一个Activity中系统首先会执行一个计算的操作,计算各个控件的布局,然后调用setContentView方法显示出来这个控件,第二步才会执行这个layout方法,但是在onCreate方法中设置了layout,在执行layout这段代码的时候,窗体有可能还没有计算完控件的布局,所以先执行了这个layout,然后又执行了计算控件布局来显示,这样layout就没效了,这里要怎么弄呢只能是通过设置这个控件的layout布局,这样在计算位置的时候就能计算了,这样设置布局能让它在计算的时候就计算了。如下,在onCreate方法中去这样设置。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sp = getSharedPreferences("config", MODE_PRIVATE);
        // Have the system blur any windows behind this one.
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        wm = (WindowManager) getSystemService(WINDOW_SERVICE);//窗体管理者
        display = wm.getDefaultDisplay();
        
        setContentView(R.layout.activity_drag_view);
        tv_drag_view = (TextView) findViewById(R.id.tv_drag_view);
        iv_drag_view = (ImageView) findViewById(R.id.iv_drag_view);
        
        int lastx = sp.getInt("lastx", 0);
        int lasty = sp.getInt("lasty", 0);
        
        RelativeLayout.LayoutParams params = (LayoutParams) iv_drag_view.getLayoutParams();
        params.leftMargin = lastx;
        params.topMargin = lasty;
        iv_drag_view.setLayoutParams(params); 
    }

    注意:在WindowManager中要想更新控件的距离就不能用layout方法了,只能用mWindowManager.updateViewLayout(view, params);

  5. 实现双击事件

    1. 双击的定义 Android中没有提供双击的点击事件,双击就是单位时间内的两次点击

    2. 触摸和点击事件的区别 点击事件: 一组动作的集合 点击 - 停留 - 离开. 触摸事件: 手指按下屏幕 手指在屏幕上移动 手指离开屏幕的一瞬间

    public class DragViewActivity extends Activity {
    	protected static final String TAG = "DragViewActivity";
    	private ImageView iv_drag_view;
    	private TextView tv_drag_view;
    	private SharedPreferences sp;
    
    	private WindowManager wm;
    	private Display  display; //窗体的显示的分辨率
    
    	private long firstClickTime;//第一次点击时候的事件
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		sp = getSharedPreferences("config", MODE_PRIVATE);
    		// Have the system blur any windows behind this one.
    		getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
    				WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
    		wm = (WindowManager) getSystemService(WINDOW_SERVICE);//窗体管理者
    		display = wm.getDefaultDisplay();
    
    		setContentView(R.layout.activity_drag_view);
    		tv_drag_view = (TextView) findViewById(R.id.tv_drag_view);
    		iv_drag_view = (ImageView) findViewById(R.id.iv_drag_view);
    
    		int lastx = sp.getInt("lastx", 0);
    		int lasty = sp.getInt("lasty", 0);
    
    		RelativeLayout.LayoutParams params = (LayoutParams) iv_drag_view.getLayoutParams();
    		params.leftMargin = lastx;
    		params.topMargin = lasty;
    		iv_drag_view.setLayoutParams(params);
    
    		iv_drag_view.setOnClickListener(new OnClickListener() {
    
    			public void onClick(View v) {
    				Log.i(TAG,"被点击了.");
    				if(firstClickTime>0){//说明这是第二次点击.
    					long secondTime = System.currentTimeMillis();
    					long dtime = secondTime - firstClickTime;
    					if(dtime<500){
    						//双击事件.
    						Log.i(TAG,"双击居中");
    						int iv_width = iv_drag_view.getRight() - iv_drag_view.getLeft();
    						iv_drag_view.layout(display.getWidth()/2-iv_width/2, iv_drag_view.getTop(), display.getWidth()/2+iv_width/2, iv_drag_view.getBottom());
    						int lasty = iv_drag_view.getTop();//得到最后在离屏幕上方的距离
    						int lastx = iv_drag_view.getLeft();//得到最后离屏幕左边的距离
    						Editor editor = sp.edit();
    						editor.putInt("lastx", lastx);
    						editor.putInt("lasty", lasty);
    						editor.commit();
    					}
    					firstClickTime = 0;//将第一次点击的时间还原成0。
    					return;
    				} else {
    				//第一次点击
    					firstClickTime = System.currentTimeMillis();//  记录第一次点击的时间
    						//新开一个线程,在这个子线程中如果是500毫秒内没有再点击就将第一次点击的时间设置为0
    					new Thread(){
    						public void run() {
    							try {
    								Thread.sleep(500);
    								firstClickTime = 0;
    							} catch (InterruptedException e) {
    								e.printStackTrace();
    							}
    						};
    					}.start();
    				}				
    			}
    		});
    	}
    }
  6. 触摸和双击同时发生时候的返回值

    //onTouch方法的返回值,True if the listener has consumed the event, false otherwise,true 监听器会把这个事件给消费掉, false 不会消费掉这个事件
    iv_drag_view.setOnTouchListener(new OnTouchListener() {
    
    	int startX , startY;
    	public boolean onTouch(View v, MotionEvent event) {
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:// 手指触摸到屏幕的事件
    			Log.i(TAG,"摸到这个控件了");
    			startX = (int) event.getRawX();
    			startY = (int) event.getRawY();
    			break;
    		case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动的事件
    			Log.i(TAG,"移动");
    			int newX = (int) event.getRawX();
    			int newY = (int) event.getRawY();
    			int dx = newX - startX;
    			int dy = newY - startY;
    			int l = iv_drag_view.getLeft();
    			int r = iv_drag_view.getRight();
    			int b = iv_drag_view.getBottom();
    			int t = iv_drag_view.getTop();
    
    			int newl = l+dx;
    			int newr = r+dx;
    			int newt = t+dy;//imageview 在窗体中新的位置
    			int newb = b+dy;
    
    			if(newl<0||newt < 0 ||newb>display.getHeight()-30||newr>display.getWidth()){
    				break;
    			}
    
    			int tv_height = tv_drag_view.getBottom() - tv_drag_view.getTop();
    
    			if(newt>display.getHeight()/2){//imageview在窗体的下方
    				//textview在窗体的上方
    				tv_drag_view.layout(tv_drag_view.getLeft(), 0, tv_drag_view.getRight(), tv_height);
    			}else{
    				tv_drag_view.layout(tv_drag_view.getLeft(), display.getHeight()-tv_height-30, tv_drag_view.getRight(), display.getHeight()-30);
    				//textview在窗体的下方
    			}
    
    			iv_drag_view.layout(newl,  newt, newr, newb);
    
    			//更新手指开始的位置.
    			startX = (int) event.getRawX();
    			startY = (int) event.getRawY();
    			break;
    		case MotionEvent.ACTION_UP: // 手指在离开屏幕的一瞬间对应的事件.
    			Log.i(TAG,"放手");
    			int lasty = iv_drag_view.getTop();//得到最后在离屏幕上方的距离
    			int lastx = iv_drag_view.getLeft();//得到最后离屏幕左边的距离
    			Editor editor = sp.edit();
    			editor.putInt("lastx", lastx);
    			editor.putInt("lasty", lasty);
    			editor.commit();
    			break;
    		}
    		// 这里对于触摸事件应该是返回true为什么这里返回false呢,因为这里这一个控件同时实现了点击和触摸这两个事件,如果返回true,
    		// 那么就不可能发生点击事件了,所以对于同时实现点击和触摸的控件返回值要为false
    		return false;
    	}
    });