Toast的另类应用及另类“拦截”Home键

        我们都知道Toast的几种用法,像什么居中啊,添加图片显示啊等等。不过这里我要说的是能够全屏显示和永远不会消失的另类Toast。全屏显示和之前大家了解的居中有点类似,只要修改setGravity(int gravity, int xOffset,int yOffset)中的第一个参数值为Gravity.FILL就ok了。麻烦的是要让Toast永远不消失,这里我们要用到反射机制。

        我们要了解一件事,那就是我们在弹出Toast的时候,必须加上.show()。顾名思义,大家可能都会以为,这里的.show()是去显示这个Toast。不过遗憾的是,事实并非如此。我们可以看看如下show()的源代码:

public void show() {
    if (mNextView == null) {
        throw new RuntimeException("setView must have been called");
    }
    INotificationManager service = getService();
    String pkg = mContext.getPackageName();
    TN tn = mTN;
    try {
        //  将当前Toast加入到Toast队列
        service.enqueueToast(pkg, tn, mDuration);
    } catch (RemoteException e) {
        // Empty
    }
}
        正如 service.enqueueToast(pkg, tn, mDuration);这一句所说,我们只是通过.show()来把当前Toast加入到Toast队列中, 再由系统根据Toast队列来显示Toast信息提示框, 并不是去显示当前Toast。因为我们不能去直接控制系统中要做的事,所以我们不能再去调用show()方法了。如果不调用show()方法,我们知道,Toast是不会显示出来的。所以,这里我们就要去自己写一个方法让我们当前的Toast显示出来。我们是用反射来解决这个问题的。关键代码如下:

private Object mTN;
	private Method mShow;
	private Method mHide;
	private Field mViewFeild;
	private View mLayout;
	private HomeKeyEventBroadCastReceiver receiver; // 监听HOME键

	/**
	 * 开启永不消失的Toast
	 */
	private void showForeverToast() {
		mLayout = getLayoutInflater().inflate(R.layout.newtoast, null);
		Toast toast = new Toast(getApplicationContext());
		toast.setGravity(Gravity.FILL, 0, 0);
		toast.setDuration(0);
		Field field = null;
		try {
			field = toast.getClass().getDeclaredField("mTN");
			field.setAccessible(true);
			mTN = field.get(toast);
			mShow = mTN.getClass().getDeclaredMethod("show");
			mHide = mTN.getClass().getDeclaredMethod("hide");
			mViewFeild = mTN.getClass().getDeclaredField("mNextView");
			mViewFeild.setAccessible(true);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		}
		
		show(mLayout); // 显示Toast
	}
显示Toast的代码如下:

private void show(View layout) {
		try {
			mViewFeild.set(mTN, layout);
			mShow.invoke(mTN, new Object[] {});
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
隐藏Toast的代码如下:

private void hide(View layout) {
		try {
			mHide.invoke(mTN, new Object[] {});
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
通过以上的代码就可以让我们的Toast全屏显示和永不消失了。

下面我就来说说关于拦截Home键的方法。之前我也是找了很多关于拦截和屏蔽Home键的方法,自己都试过,根本行不通(当然也可能是我自己的问题,如果大家有什么好的方法,可以给我留言)。所以,这里我就取了个巧(其实是一个假的拦截和屏蔽),我是采用了当我们点击Home键的时候,退回桌面,同时程序转入后台,一定时间后程序再从后台转入前台。关键代码正下:

class HomeKeyEventBroadCastReceiver extends BroadcastReceiver {
		static final String SYSTEM_REASON = "reason";
		static final String SYSTEM_HOME_KEY = "homekey"; // home key
		static final String SYSTEM_RECENT_APPS = "recentapps"; // long home key

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
				String reason = intent.getStringExtra(SYSTEM_REASON);
				if (reason != null) {
					if (reason.equals(SYSTEM_HOME_KEY)) {
						// 从桌面启动app(利用RestartService过渡)
						Intent newIntent = new Intent();
	                    newIntent.setClass(context, RestartService.class);
	                    context.startService(newIntent);
	                    
						showToastByHome();
					} else if (reason.equals(SYSTEM_RECENT_APPS)) {
						hideToastByHome();
					}
				}
			}
		}
	}
点击Home键后,弹出全屏的Toast.5秒后又自动消失:

private void showToastByHome() {
		showForeverToast(); // 显示全屏的Toast
		if (mThread == null || !mThread.isAlive() || mThread.isInterrupted()) {
			mThread = new Thread() {
				@Override
				public void run() {
					try {
						sleep(5000);
						hide(mLayout);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			mThread.start();
		}
	}
看上面的第一段代码,可以很容易地发现我是在退回桌面的同时,跳转到一个RestartService,这个Service会在5秒后再进行一次跳转(从Service跳转程序的前台Activity),这样就实现了假的拦截Home了,如果亲们对这个拦截Home键的功能比较急,要求又不是很苛刻的话,可以先用这样的方法顶一下。而Service中的代码也很简单,几句话,如下:

public void onStart(Intent intent, int startId) {
        Intent newIntent = new Intent(getApplicationContext(), MainActivity.class);
        newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(newIntent);
        super.onStart(intent, startId);
    }
这里是本篇博客的工程连接: http://download.csdn.net/detail/u013761665/8015397

本博客参考博文:
Android开发技巧:永不关闭的Toast信息框

Android开发技巧:永不关闭的Toast信息框(修正版)android4.x



转载于:https://www.cnblogs.com/fengju/p/6336140.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android的Toast是一个简单的消息弹出窗口,通常用于向用户显示短暂的消息。但是,Toast默认情况下不支持添加按钮。如果您想在Toast中添加一个按钮,您可以考虑使用自定义布局和自定义Toast。 以下是一些示例代码,可以帮助您创建一个带有按的自定义Toast: 1. 首先,创建一个自定义的布局文件,包含一个TextView和一个Button。 ```xml <!-- custom_toast.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#AA000000" android:orientation="horizontal" android:padding="8dp"> <TextView android:id="@+id/text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:textColor="#FFFFFF" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="OK" /> </LinearLayout> ``` 2. 在您的Activity中,使用LayoutInflater加载自定义布局文件,并使用Toast显示它。您还可以在按钮上设置一个OnClickListener来处理点击事件。 ```java // 定义Toast的显示时间 private static final int TOAST_DURATION = Toast.LENGTH_SHORT; // 显示一个带有按Toast public void showCustomToast() { // 加载自定义布局文件 LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.custom_toast, null); // 获取布局中的TextView和Button TextView text = (TextView) layout.findViewById(R.id.text); Button button = (Button) layout.findViewById(R.id.button); // 设置TextView的文本内容 text.setText("这是一个带有按Toast"); // 创建一个新的Toast对象 Toast toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); toast.setDuration(TOAST_DURATION); toast.setView(layout); // 设置Button的OnClickListener button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 处理按钮的点击事件 Toast.makeText(getApplicationContext(), "按钮已点击", Toast.LENGTH_SHORT).show(); } }); // 显示Toast toast.show(); } ``` 这样,您就可以创建一个带有按的自定义Toast了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值