自定义可拖动的Toast

package com.loaderman.toastdemo;

import android.content.Context;
import android.graphics.PixelFormat;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;


/**
 * 
 * 自定义归属地吐司
 * <p/>
 * 让窗口布局响应触摸事件:
 * 1. 去掉FLAG_NOT_TOUCHABLE的标记
 * 2. 调整显示级别为TYPE_PHONE, 可以支持触摸
 * 3. 加权限: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 */
public class AddressToast {

    private       WindowManager              mWM;
    private       View                       mView;
    private final WindowManager.LayoutParams mParams;
    private final TextView                   tvAddress;
    private       int                        startX;
    private       int                        startY;

    private Context mContext;
    private int[] mIcons = new int[]{R.drawable.shape_address_normal, R.drawable
            .shape_address_orange, R.drawable.shape_address_blue, R.drawable.shape_address_gray,
            R.drawable.shape_address_green};
    public AddressToast(Context ctx) {
        mContext = ctx;

        //窗口管理器
        //窗口: android系统中最顶级的布局, 任何的界面和组件都显示在窗口中, Activity, 状态栏, dialog
        //当需要在第三方app中显示布局时, 由于没有activity可以依托,此时可以直接使用WindowManager在窗口上添加布局
        mWM = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);

        //初始化布局参数, 定义当前布局的宽高,位置,显示方式等信息
        mParams = new WindowManager.LayoutParams();
        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;//高度包裹内容
        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//宽度包裹内容
        mParams.format = PixelFormat.TRANSLUCENT;//显示格式,默认就行
        //params.windowAnimations = com.android.internal.R.style.Animation_Toast;//窗口动画
        mParams.type = WindowManager.LayoutParams.TYPE_PHONE;//类型, 吐司类型(不支持触摸)
        //params.setTitle("Toast");//标题
        //标记, 保持屏幕常亮, 没有焦点, 不可触摸
        mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        // | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        //        mParams.x;
        //        mParams.y;

        //初始化布局
        //        mView = new TextView(ctx);
        //        mView.setText(text);
        //        mView.setTextColor(Color.RED);
        //        mView.setTextSize(25);
        mView = View.inflate(ctx, R.layout.toast_address, null);
        tvAddress = (TextView) mView.findViewById(R.id.tv_address);
        //设置窗口布局的触摸事件
        mView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        System.out.println("按下...");
                        //1.记录起点坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        System.out.println("移动...");
                        //2. 记录移动后的坐标
                        int moveX = (int) event.getRawX();
                        int moveY = (int) event.getRawY();
                        //3. 计算偏移量
                        int dx = moveX - startX;
                        int dy = moveY - startY;
                        //4. 根据偏移量更新布局位置
                        mParams.x += dx;
                        mParams.y += dy;
                        mWM.updateViewLayout(mView, mParams);//更新控件位置

                        //5. 重新初始化起点坐标
                        startX = moveX;
                        startY = moveY;
                        break;
                    case MotionEvent.ACTION_UP:
                        System.out.println("抬起...");
                        break;
                    default:
                        break;
                }
                return true;//消费掉此事件
            }
        });
    }

    //显示布局
    public void show(String text) {
        //mView.setText(text);
        tvAddress.setText(text);
        //获取当前选中的样式
        tvAddress.setBackgroundResource(mIcons[0]);//重新设置背景
        //给窗口添加布局对象
        mWM.addView(mView, mParams);
    }

    //隐藏布局
    public void hide() {
        if (mWM != null && mView != null) {
            //移除窗口布局
            //布局没有添加给窗口时, 从窗口移除布局就会出异常
            try {
                mWM.removeView(mView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
package com.loaderman.toastdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private AddressToast mToast;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToast = new AddressToast(this);
    }
    public void display(View view){
        mToast.show("自定义的哦");
    }
    public void hide(View view){
        mToast.hide();
    }
}

 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.loaderman.toastdemo.MainActivity">

    <Button
        android:id="@+id/btn_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="display"
        android:text="显示"/>
    <Button
        android:id="@+id/btn_hide"
        android:onClick="hide"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="隐藏"/>
</LinearLayout>

 toast_address.xml

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

    <TextView
        android:id="@+id/tv_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_address_normal"
        android:drawableLeft="@drawable/location"
        android:text="未知号码"
        android:padding="8dp"
        android:textColor="@color/white"
        android:textSize="18sp"/>
</LinearLayout>

在res/drawable下

shape_address_blue.xml shape_address_gray.xml shape_address_green.xml shape_normal_blue.xml shape_address_orange.xml只需要把下面代码需要以下color即可

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <!--颜色-->
    <solid android:color="@color/global_blue"/>
    <!--给矩形加圆角-->
    <corners android:radius="6dp"/>
</shape>

 在res/values/colors.xml添加需求颜色值即可如

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="red">#F00</color>
    <color name="black">#000</color>
    <color name="gray">#a000</color>
    <color name="global_blue">#459FD7</color>
    <color name="white">#fff</color>
    <color name="light_gray">#cccccc</color>
    <color name="light_green">#00ffa1</color>
</resources>

 添加权限:

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

 效果图:

原文地址:https://www.cnblogs.com/loaderman/p/6481179.html