Android Application级别自定义Toast

在Android开发过程中,有时会需要一些消息提示,大多数情况可以用dialog来做,但有些消息不需要用户去点击取消并且不能对用户体验产生影响的提示,就需要toast来做了。但可惜的是,toast是系统级的,凡是涉及到系统的又会涉及到其他APP,有些定制系统可以对App的消息通知进行设置,一旦禁止了APP的通知toast则不会显示。而且在Android 7以后toast还需要申请权限麻烦死了有木有,劳资就想安安静静的提示一下有这么麻烦吗!所以,本人特地研究了下能在Application级别不受限制提示的toast。

先看效果:

效果很简单,就是一个头部即现即隐的提示,外加过渡动画。其实自定义系统级的toast也能实现这种效果,但之前已经说了系统级的toast有限制。

话不多说,现在介绍下这是如何实现的吧!

首先申明这是基于WindowManager产生的view,本人看了系统级toast的源码好像也是基于WindowManager的。WindowManager是个神奇的东西,在这就不多做介绍了,我们只需要知道activity.getWindowManager().addView(layout, params)可以给整个Activity界面添加一个view层,这一层可以不影响activity的操作。竟然有这个功能瞬间涨姿势了有不有!细心人的应该察觉到了这和FrameLayout挺像,其实Activity的root就是一个FrameLayout。

好了,既然Activity有这个功能,那tosat做起来就有头绪了。

先实现java类代码(个人爱好,喜欢先主后次):

/**
 * App级toast
 */
public class AppToast
{
  private Activity activity;

  private ViewGroup layout;
  private ViewGroup content;
  private TextView textView;

  private Animation startAnimation;
  private Animation centerAnimation;
  private Animation endAnimation;

  private DelayTask task;
  private boolean isShow;

  private LayoutParams params;

  /**
   * APP级别Toast
   */
  public AppToast(Activity activity)
  {
    this.activity = activity;

    layout = (ViewGroup) LayoutInflater.from(activity).inflate(R.layout.toast, null);
    content = (ViewGroup) layout.getChildAt(0);
    textView = (TextView) content.getChildAt(0);
    params = new LayoutParams();
    params.height = LayoutParams.WRAP_CONTENT;
    params.width = LayoutParams.MATCH_PARENT;
    params.gravity = Gravity.TOP;
    params.type = LayoutParams.TYPE_APPLICATION;
    params.format = PixelFormat.TRANSLUCENT;
    params.flags = LayoutParams.FLAG_KEEP_SCREEN_ON | LayoutParams.FLAG_NOT_FOCUSABLE |
        LayoutParams.FLAG_NOT_TOUCHABLE;
    activity.getWindowManager().addView(layout, params);
    layout.setVisibility(View.GONE);

    // 开始动画
    startAnimation = new AlphaAnimation(0, 1);
    startAnimation.setDuration(500);

    // 中间动画
    centerAnimation = new AlphaAnimation(0.92f, 1);
    centerAnimation.setDuration(500);

    // 结束动画
    endAnimation = new AlphaAnimation(1, 0);
    endAnimation.setDuration(500);
    endAnimation.setInterpolator(new AccelerateInterpolator());

    // 结束动画监听
    endAnimation.setAnimationListener(new Animation.AnimationListener()
    {
      @Override
      public void onAnimationStart(Animation animation)
      {
      }

      @Override
      public void onAnimationEnd(Animation animation)
      {
        layout.setVisibility(View.GONE);
      }

      @Override
      public void onAnimationRepeat(Animation animation)
      {
      }
    });
  }

  /**
   * 显示Toast
   */
  public void show(String s)
  {
    show(s, 1500);
  }

  /**
   * 显示Toast
   */
  public void show(String s, int delay)
  {
    textView.setText(s);
    start();
    if (task != null)
    {
      task.stop();
    }
    task = new DelayTask(delay)
    {
      @Override
      public void logic()
      {
        end();
      }
    };
    task.start();
  }

  /**
   * 开始
   */
  private void start()
  {
    if (!isShow)
    {
      layout.setVisibility(View.VISIBLE);
      content.startAnimation(startAnimation);
      isShow = true;
    } else
    {
      content.startAnimation(centerAnimation);
    }
  }

  /**
   * 结束
   */
  private void end()
  {
    content.startAnimation(endAnimation);
    isShow = false;
  }
}

先在构造方法AppToast(Activity activity)中加载自定义toast的布局以及初始化params参数。然后添加各个过程所需的动画。这其中有个重点,就是params.type = LayoutParams.TYPE_APPLICATION,记住一定要是TYPE_APPLICATION,而不是TYPE_TOAST,TYPE_TOAST会在Android 7上被莫名其妙的限制。
有些人可能会注意到除了开始动画和结束动画,为什么还有个中间动画?其实这是为了多重toast提示做的一个辨别机制,我们在用系统级toast的时候有些人应该能感受到toast并不是重叠显示,但也不是直接替换内容,而是在替换内容的时候微微的闪一下表示内容变更了,所以在这里就用了一个中间动画来执行那“闪一下”的效果。

关于其中用到的一个延时器类DelayTask,这是本人为了方便自行设计的一个工具类,其效果就是延时执行一段UI逻辑,其代码如下:

/**
 * 延时器类
 *
 * @author zls
 *
 * @version 1.0
 *
 * @time 2015-12-27下午7:52:10
 */
public abstract class DelayTask
{
 protected Thread thread;
 private boolean isRun;

 /**
 * 延时器
 */
 public DelayTask(final long delay)
 {
 thread = new Thread()
 {
  @Override
  public void run()
  {
  try
  {
   sleep(delay);
   if(isRun)
   {
   mHandler.sendEmptyMessage(0);
   }
  } catch (Exception e)
  {
  }
  }
 };
 }

 protected Handler mHandler = new Handler()
 {
 @Override
 public void handleMessage(Message msg)
 {
  logic();
 }
 };

 /** 开始执行 */
 public void start()
 {
 isRun = true;
 thread.start();
 }

 /** 停止执行 */
 public void stop()
 {
 isRun = false;
 }

 /** 执行逻辑 */
 public abstract void logic();
}

有兴趣的朋友可以借鉴下,觉得这么设计不太好的也可以用你们自己设计的延时器来用。

现在上toast的布局代码:

<?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="wrap_content"
  android:orientation="vertical"
  android:paddingTop="5dp"
  android:paddingLeft="15dp"
  android:paddingRight="15dp">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/toast_shape"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <TextView
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="20dp"
      android:gravity="center"
      android:text="默认提示"
      android:textColor="#fff"
      android:textSize="15sp"/>
  </LinearLayout>

</LinearLayout>

测试Activity的代码:

public class MainActivity extends AppCompatActivity
{
  private AppToast toast;

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    toast = new AppToast(this);
  }

  public void ok(View v)
  {
    toast.show("这是Toast测试!" + Math.random());
  }
}

Demo下载

就此结束,希望能帮到需要此功能的朋友。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android获取应用程序名称(ApplicationName)示例

    MainActivity如下: 复制代码 代码如下: package cn.testapplicationname; import android.os.Bundle; import android.widget.TextView; import android.app.Activity; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; /** * Demo描述: * 获取应

  • 详解Android中Application设置全局变量以及传值

    Application设置全局变量以及传值 /** * 重写Application,主要重写里面的onCreate方法,就是创建的时候, * 我们让它初始化一些值,前段时间在javaeye里面看到过一个例子,与此相似, * 我做了些改进.听说外国开发者习惯用此初始化一些全局变量,好像在Activity * 一些类里面初始化全局变量的化,会遇到一些空指针的异常,当然,我没有遇到过. * 如果用此方法初始化的话,那么就可以避免那些有可能出现的错误. * * 启动Application,他就会创建一个

  • Android Application类的详细介绍

    Android Application类详解: Android中Application类的详细解释: 我们在平时的开发中,有时候可能会需要一些全局数据,来让应用中的所有Activity和View都能访问到,大家在遇到这种情况时,可能首先会想到自己定义一个类,然后创建很多静态成员. 但是这种方法不符合Android的框架架构,不过andorid已经为我们提供了这种情况的解决方案:在Android中,有一个名为Application的类,我们可以在Activity中使用getApplication(

  • Android Application级别自定义Toast

    在Android开发过程中,有时会需要一些消息提示,大多数情况可以用dialog来做,但有些消息不需要用户去点击取消并且不能对用户体验产生影响的提示,就需要toast来做了.但可惜的是,toast是系统级的,凡是涉及到系统的又会涉及到其他APP,有些定制系统可以对App的消息通知进行设置,一旦禁止了APP的通知toast则不会显示.而且在Android 7以后toast还需要申请权限麻烦死了有木有,劳资就想安安静静的提示一下有这么麻烦吗!所以,本人特地研究了下能在Application级别不受限

  • Android编程实现自定义toast示例

    本文实例讲述了Android编程实现自定义toast.分享给大家供大家参考,具体如下: 效果图: 代码: //自定义布局的toast customViewToast.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast toast = Toast.makeText(ToastTest.this, "top", Toast.LENGTH_SHORT); /

  • Android开发实现自定义Toast、LayoutInflater使用其他布局示例

    本文实例讲述了Android开发实现自定义Toast.LayoutInflater使用其他布局.分享给大家供大家参考,具体如下: 内容: 1.自定义样式toast 2.再活动中添加其他布局 实现效果: 步骤: 一.自定义View 引用zidingyixml文件 生成一个布局对象 二.采用Toast 的addView() 方法将该对象添加到Toast对象中 三.显示:Toast.show() 具体实现方法: public class MainActivity extends Activity {

  • Android 自定义 Toast 显示时间

    Android 自定义 Toast 显示时间 实现代码: package com.wm.realname.util; import android.content.Context; import android.os.Handler; import android.view.View; import android.widget.Toast; /** * Toast自定义显示时间 * 使用方法 * 1.先初始化类 MyToast myToast = new MyToast(this); * 2.

  • 超简单实现Android自定义Toast示例(附源码)

    Bamboy的自定义Toast,(以下称作"BToast") 特点在于使用简单, 并且自带两种样式: 1)普通的文字样式: 2)带图标样式. 其中图标有√和×两种图标. BToast还有另外一个特点就是: 系统自带Toast采用的是队列的方式,当前Toast消失后,下一个Toast才能显示出来: 而BToast会把当前Toast顶掉, 直接显示最新的Toast. 那么,简单三步,我们现在就开始自定义一下吧! (一).Layout: 要自定义Toast, 首先我们需要一个XML布局. 但

  • android之自定义Toast使用方法

    Android系统默认的Toast十分简洁,使用也非常的简单.但是有时我们的程序使用默认的Toast时会和程序的整体风格不搭配,这个时候我们就需要自定义Toast,使其与我们的程序更加融合. 使用自定义Toast,首先我们需要添加一个布局文件,该布局文件的结构和Activity使用的布局文件结构一致,在该布局文件中我们需设计我们Toast的布局,例如: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> &

  • android自定义Toast设定显示时间

    开发android的同学可能会抱怨Toast设定显示的时长无效,只能是Toast.LENGTH_LONG 或者Toast.LENGTH_SHORT 之一,为了解决这些办法,有多种实现方式: 1.使用定时器,定时调用show()方法. 2.使用CountDownTimer类,也是调用show()方法. 3.使用WindownManager类实现. 本文使用方法三进行实现,难度不大,直接看代码吧. package com.open.toast; import android.content.Cont

  • Android自定义Toast之WindowManager

    本文为大家分享了Android自定义Toast之WindowManager,供大家参考,具体内容如下 Toast:WindowManager 三个重要的API: public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); 相当于布局文件中的属性 public void removeView

  • Android百度地图自定义公交路线导航

    一.问题描述 基于百度地图实现检索指定城市指定公交的交通路线图,效果如图所示 二.通用组件Application类,主要创建并初始化BMapManager public class App extends Application { static App mDemoApp; //百度MapAPI的管理类 public BMapManager mBMapMan = null; // 授权Key // 申请地址:http://dev.baidu.com/wiki/static/imap/key/ p

  • Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题

    先给大家展示下效果图: 扫描内容是下面这张,二维码是用zxing库生成的 由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java package com.zxing.activity; import java.io.IOException; import java.util.Vector; import android.app.Activity; import android.content.Intent; import

随机推荐