Android自定义吐司(Toast)

一、不多说,老惯例,先上图



二、接下来,代码的讲解

package net.dxs.mobilesafe.service;

import net.dxs.mobilesafe.R;
import net.dxs.mobilesafe.db.dao.AddressDao;
import android.app.Service;
import android.content.BroadcastReceiver;
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.os.SystemClock;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.TextView;

/**
 * 如果要弹出来 可以相应触摸点击事件的窗体,需要做3件事情。
 * 1.params.type 设置为可以相应触摸事件
 * 2.修改窗体类型  电话优先级窗体类型TYPE_PRIORITY_PHONE
 * 3.设置权限  android.permission.SYSTEM_ALERT_WINDOW
 * @author lijian
 *
 */
public class CallAddressService extends Service {
	protected static final String TAG = "CallAddressService";

	/**
	 * 定义一个电话状态的管理器
	 */
	private TelephonyManager tm;
	/**
	 * 电话状态的监听器
	 */
	private PhoneStateListener listener;

	private OutCallInnerReceiver receiver;
	/**
	 * 系统窗体的管理器
	 */
	private WindowManager mWm;
	/**
	 * 类的成员变量 显示出来的土司的view对象
	 */
	private View view;

	private WindowManager.LayoutParams params;

	private SharedPreferences sp;

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

	/**
	 * 在服务的内部创建了一个广播接收者,希望广播接收者的存活周期跟服务一致。
	 * @author lijian
	 *
	 */
	private class OutCallInnerReceiver extends BroadcastReceiver {
		private static final String TAG = "CallAddressService";

		@Override
		public void onReceive(Context context, Intent intent) {
			String number = getResultData();
			Log.i(TAG, "有新的电话打出去了,号码是:" + number);
			String address = AddressDao.find(number);
			if (!TextUtils.isEmpty(address)) {
				// Toast.makeText(getApplicationContext(), address, 1).show();
				showMyToast(address);
			}
		}
	}

	@Override
	public void onCreate() {
		super.onCreate();
		sp = getSharedPreferences("config", MODE_PRIVATE);

		// 初始化窗体管理器
		mWm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
		receiver = new OutCallInnerReceiver();
		// 过滤电话打出去的动作
		IntentFilter filter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
		registerReceiver(receiver, filter);

		tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		listener = new Mylistener();
		// 让监听器监听电话呼叫状态的变化
		tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
	}

	
	long[] mHits = new long[2];
	/**
	 * 显示自定义吐司
	 * @param address 电话号码的归属地
	 */
	public void showMyToast(String address) {
		view = View.inflate(this, R.layout.toast_address, null);
		//给view对象注册一个双击事件
		view.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);//数组向左移位操作
				mHits[mHits.length - 1] = SystemClock.uptimeMillis();//uptimeMillis()手机的开机时间
				if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
					params.x = (mWm.getDefaultDisplay().getWidth()-view.getWidth())/2;
					params.y = (mWm.getDefaultDisplay().getHeight()-view.getHeight())/2;
					mWm.updateViewLayout(view, params);
					Editor edit = sp.edit();
					edit.putInt("paramsx", params.x);
					edit.putInt("paramsy", params.y);
					edit.commit();
				}
			}
		});

		//给view对象组成触摸的监听器
		view.setOnTouchListener(new OnTouchListener() {

			int startX;
			int startY;

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN://手指按下
					Log.i(TAG, "手指按下");
					event.getRawX();
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();
					Log.i(TAG, "oldx:" + startX);
					Log.i(TAG, "oldy:" + startY);

					break;
				case MotionEvent.ACTION_MOVE://手指移动
					Log.i(TAG, "手指移动");
					int newX = (int) event.getRawX();
					int newY = (int) event.getRawY();
					Log.i(TAG, "newX : " + newX);
					Log.i(TAG, "newY : " + newY);

					int dx = newX - startX;
					int dy = newY - startY;
					Log.i(TAG, "手指水平方向偏移量dx : " + dx);
					Log.i(TAG, "手指竖直方向偏移量dy : " + dy);

					//立刻让控件也跟随着手指移动 dx dy。
					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();
					}

					mWm.updateViewLayout(view, params);

					//重复第一步的操作 ,重新初始化手指的开始位置。
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();

					break;
				case MotionEvent.ACTION_UP://手指抬起
					Log.i(TAG, "手指抬起");
					Editor edit = sp.edit();
					edit.putInt("paramsx", params.x);
					edit.putInt("paramsy", params.y);
					edit.commit();
					break;

				}

				return false;//True if the listener has consumed the event, false otherwise.
							//true 代表监听器 处理掉了这个事件,false监听器没有处理这个事件。
			}
		});

		TextView tv_toast_address = (TextView) view.findViewById(R.id.tv_toast_address);
		tv_toast_address.setText(address);

		//土司显示的参数
		params = new WindowManager.LayoutParams();

		//对齐方式
		params.gravity = Gravity.LEFT + Gravity.TOP;

		//指定距离屏幕左边的距离 必须与 Gravity.LEFT同时使用
		params.x = sp.getInt("paramsx", 0);
		//指定距离屏幕上边的距离 必须与 Gravity.TOP同时使用
		params.y = sp.getInt("paramsy", 0);

		// 土司的宽高
		params.height = WindowManager.LayoutParams.WRAP_CONTENT;
		params.width = WindowManager.LayoutParams.WRAP_CONTENT;

		// 土司的参数 不可获取焦点 不可以别点击 保存屏幕常亮
		params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
		//| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

		// 半透明窗体
		params.format = PixelFormat.TRANSLUCENT;
		//吐司显示动画
		//params.windowAnimations = R.anim.toast_show;

		//改用电话优先级的窗体类型,这种类型可以响应触摸事件。
		params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
		mWm.addView(view, params);

	}

	public class Mylistener extends PhoneStateListener {

		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			super.onCallStateChanged(state, incomingNumber);
			switch (state) {
			case TelephonyManager.CALL_STATE_RINGING://响铃状态
				String address = AddressDao.find(incomingNumber);
				if (!TextUtils.isEmpty(address)) {
					//Toast.makeText(getApplicationContext(), address, Toast.LENGTH_LONG).show();
					showMyToast(address);
				}
				break;

			case TelephonyManager.CALL_STATE_IDLE://空闲
				if (view != null) {
					mWm.removeView(view);
					mWm = null;
				}
				break;

			case TelephonyManager.CALL_STATE_OFFHOOK://接听状态

				break;
			}
		}

	}

	// 服务停止的时候调用的方法
	@Override
	public void onDestroy() {
		// 取消电话状态的监听
		tm.listen(listener, PhoneStateListener.LISTEN_NONE);
		listener = null;
		// 服务停止取消注册广播接受者
		unregisterReceiver(receiver);
		receiver = null;

		super.onDestroy();
	}

}


三、源代码路径说明

//找到平台下的资源文件internal.R.代表内部的资源文件即\sdk\platforms\android-19\data\res\


示例源代码下载:http://download.csdn.net/download/shenqingxiaojian/7656909



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值