自定义土司随意拖动

步骤:

1.到窗口管理器对象WindowManager wm,

2.得到布局文件构造的一个view,

3.构造WindowManager.LayoutParams()布局参数wparam

4.使用窗口布局管理器将view按照wparam的布局来显示mWM.addView(view, params);

代码:

package com.itheima.mobilesafe.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.TextView;

import com.itheima.mobilesafe.R;
import com.itheima.mobilesafe.dao.NumberAddressDao;
import com.itheima.mobilesafe.receiver.OutCallBroadcastReceiver;

public class NumberAddressService extends Service {

	private WindowManager mWM;
	private WindowManager.LayoutParams params;
	private View view;
	private OutCallBroadcastReceiver receiver;
	private SharedPreferences sp;
	


	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();

		TelephonyManager tm = (TelephonyManager) this
				.getSystemService(TELEPHONY_SERVICE);
		// 监听电话的呼叫状态
		tm.listen(new MyPhoneStateListener(),
				PhoneStateListener.LISTEN_CALL_STATE);
		//取消监听代码
		// tm.listen(listener, PhoneStateListener.LISTEN_NONE);

		receiver = new OutCallBroadcastReceiver();
		// 添加接收事件类型
		IntentFilter filter = new IntentFilter();
		filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
		// 注册广播接收者
		registerReceiver(receiver, filter);

	}

	private class MyPhoneStateListener extends PhoneStateListener {

		/**
		 * 电话的呼叫状态发生变化时会调用这个方法
		 */
		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			super.onCallStateChanged(state, incomingNumber);
			switch (state) {
			case TelephonyManager.CALL_STATE_IDLE:// 空闲状态
				// 电话挂断时移除归属地提示框
				if (view != null) {
					mWM.removeView(view);
					view = null;
				}
				break;
			case TelephonyManager.CALL_STATE_RINGING:// 铃声响起状态

				// 查询号码归属地
				String address = NumberAddressDao
						.queryNumberAddress(incomingNumber);
				// Toast.makeText(NumberAddressService.this, address, 0).show();
				getMyToast(address);
				break;
			case TelephonyManager.CALL_STATE_OFFHOOK:// 接通状态

				break;

			default:
				break;
			}
		}
	}

	private void getMyToast(String address) {

		sp = getSharedPreferences("config", Context.MODE_PRIVATE);
		int which = sp.getInt("which", 0);
//		private String[] items = new String[] { "半透明", "活力橙", "金屬灰", "衛士藍",
//				"蘋果綠" };
		int[] ids = new int[] { R.drawable.call_locate_white,
				R.drawable.call_locate_orange, R.drawable.call_locate_gray,
				R.drawable.call_locate_blue, R.drawable.call_locate_green };
		view = View.inflate(this, R.layout.show_toast, null);
		view.setBackgroundResource(ids[which]);
		//给view添加一个触摸的监听器
		view.setOnTouchListener(new OnTouchListener() {
			private int startX = 0;
			private int startY = 0;
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// 得到触摸事件的类型
				int action = event.getAction();
				
				switch (action) {
				case MotionEvent.ACTION_DOWN:// 按下的事件
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();
					
					break;
				case MotionEvent.ACTION_MOVE:// 移动的事件
					//2、在移动的过程中得到结束坐标点
					int endX = (int) event.getRawX();
					int endY = (int) event.getRawY();
					
					//3、计算移动的偏移量
					int dX = endX - startX;
					int dY = endY - startY;
					//4、更新图标的位置
					params.x +=dX;
					params.y +=dY;
					if(params.x < 0){
						params.x = 0;
					}
					
					if(params.y < 0){
						params.y = 0;
					}
					if(params.x > mWM.getDefaultDisplay().getWidth()-view.getWidth()){
						params.x = mWM.getDefaultDisplay().getWidth()-view.getWidth();
					}
					
					if(params.y > mWM.getDefaultDisplay().getHeight()-view.getHeight()){
						params.y = mWM.getDefaultDisplay().getHeight()-view.getHeight();
					}
					//4、更新图标的位置
					mWM.updateViewLayout(view, params);
					
					//5、得到新的开始坐标点
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();
					break;
				case MotionEvent.ACTION_UP:// 抬起的事件
					int lastX = params.x ;
					int lastY = params.y;
					
					Editor editor = sp.edit();
					editor.putInt("lastX", lastX);
					editor.putInt("lastY", lastY);
					editor.commit();
					break;
				}
				return true;
			}
		});
		TextView tv = (TextView) view.findViewById(R.id.tv_address);
		// 在自定义的吐司上显示归属地
		tv.setText(address);
		// 得到系统提供窗口管理器
		mWM = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
		// 得到布局文件的参数对象
		params = new WindowManager.LayoutParams();
		// 设置布局文件显示用到的参数
		//添加显示时参考的位置
		params.gravity = Gravity.LEFT + Gravity.TOP;
		//根据之前保存的显示位置来显示当前位置
		int lastX = sp.getInt("lastX", 0);
		int lastY = sp.getInt("lastY", 0);
		params.x = lastX;
		params.y = lastY;
		
		params.height = WindowManager.LayoutParams.WRAP_CONTENT;
		params.width = WindowManager.LayoutParams.WRAP_CONTENT;
		params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//				| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
				| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
		params.format = PixelFormat.TRANSLUCENT;
		// params.windowAnimations =
		// com.android.internal.R.style.Animation_Toast;
		params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
		// 在窗口中显示自定义的吐司
		mWM.addView(view, params);

		// mWM.removeView(view);

	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// 取消掉已经注册的广播接收者
		unregisterReceiver(receiver);
	}

}
show_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_menu_call" />

    <TextView
        android:layout_marginTop="8dip"
        android:id="@+id/tv_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="北京电信"
        android:textSize="15sp"
        android:gravity="center_vertical"  
        />

</LinearLayout>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Barry__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值