023 Android 自定义Toast控件

1.Toast自定义控件工具类

package com.example.administrator.test62360safeguard.Utils;

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

import com.example.administrator.test62360safeguard.R;

public class ToastUtil {

    /**
     * 显示吐司
     * @param context 应用的上下文
     * @param windowManager 窗口管理器
     * @param textshow 需要在textview 中需要显示的文本内容
     * @return 吐司toast控件
     */
    public static View showToast(final Context context, final WindowManager windowManager, String textshow){
        final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
        final WindowManager.LayoutParams params = mParams;

        //设置toast的高度、宽度
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;

        params.format = PixelFormat.TRANSLUCENT;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.setTitle("Toast");
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                //| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; //默认可以被触摸
        params.gravity=Gravity.LEFT+Gravity.TOP; //设置toast的位置()左上角
        //toast显示效果,xml--->view ,将toast挂到windowManager窗体
        final View myToastView = View.inflate(context, R.layout.toast_view, null);

        //给自定义的toast控件添加拖拽事件
        myToastView.setOnTouchListener(new View.OnTouchListener() {
            int startX;
            int startY;
            int window_width;
            int window_height;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getRawX(); //获取点击位置(移动前)相对于整个屏幕原点(左上)的x距离
                        startY = (int) event.getRawY(); //获取点击位置(移动前)相对于整个屏幕原点(左上)的y距离
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int moveX = (int) event.getRawX(); //获取点击位置(移动后)相对于整个屏幕原点(左上)的x距离
                        int moveY = (int) event.getRawY();//获取点击位置(移动后)相对于整个屏幕原点(左上)的y距离
                        int disX=moveX-startX;  //x方向的移动距离
                        int disY=moveY-startY;  //y方向的移动距离

                        params.x=params.x+disX;  //设置toast控件的放置位置
                        params.y=params.y+disY;

                        //容错处理
                        //获取屏幕的宽和高
                        window_width = windowManager.getDefaultDisplay().getWidth();
                        window_height=windowManager.getDefaultDisplay().getHeight();
                        //以下4个if语句:判断控件是否在屏幕的有效区域内
                        if(params.x<0){
                            params.x=0;
                        }

                        if(params.y<0){
                            params.y=0;
                        }

                        if(params.x>window_width-myToastView.getWidth()){
                            params.x=window_width-myToastView.getWidth();
                        }

                        if(params.y>window_height-myToastView.getHeight()){
                            params.y=window_height-myToastView.getHeight();
                        }


                        //告知窗体,toast控件需要按照手势的移动,去做位置的更新
                        windowManager.updateViewLayout(myToastView,params);


                        startX = (int) event.getRawX(); //获取点击位置(移动后)相对于整个屏幕原点(左上)的x距离
                        startY = (int) event.getRawY(); //获取点击位置(移动后)相对于整个屏幕原点(左上)的y距离
                        break;
                    case MotionEvent.ACTION_UP:
                        SharePreferenceUtil.putInt(context, ConstantValue.LOCATION_X, params.x);
                        SharePreferenceUtil.putInt(context, ConstantValue.LOCATION_Y, params.y);
                        break;
                }
                //(1)若只需要响应拖拽事件,应该返回true
                //(2)既要响应点击事件,又要响应拖拽过程,则此返回值结果需要修改为false
                return true;
            }
        });

        params.x=SharePreferenceUtil.getInt(context,ConstantValue.LOCATION_X,0);
        params.y=SharePreferenceUtil.getInt(context,ConstantValue.LOCATION_Y,0);

        int[] picArray=new int[]{R.drawable.call_locate_white,R.drawable.call_locate_orange,R.drawable.call_locate_blue,
        R.drawable.call_locate_gray,R.drawable.call_locate_green};
        int toast_style_index = SharePreferenceUtil.getInt(context, ConstantValue.TOAST_STYLE, 0);
        //设置toast中显示的文字内容
        TextView tv_toast = myToastView.findViewById(R.id.tv_toast);
        tv_toast.setText(textshow);
        tv_toast.setBackgroundResource(picArray[toast_style_index]);
        //在窗体上挂载一个view(需要添加权限)
        windowManager.addView(myToastView,mParams);
        return myToastView;
    }

    /**
     * 移除吐司
     * @param windowManager 窗口管理器
     * @param toastView   所要关闭的toast组件
     */
    public static void closeToast( WindowManager windowManager, View toastView) {
        windowManager.removeView(toastView);
    }
}

 2.调用类

(1)设置中心页面的后台处理类:SettingActivity.java

package com.example.administrator.test62360safeguard;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;

import com.example.administrator.test62360safeguard.Utils.ConstantValue;
import com.example.administrator.test62360safeguard.Utils.SetttingClickView;
import com.example.administrator.test62360safeguard.Utils.SetttingItemView;
import com.example.administrator.test62360safeguard.Utils.SharePreferenceUtil;
import com.example.administrator.test62360safeguard.Utils.ToastUtil;

public class SettingActivity extends AppCompatActivity {
    View toastView=null;
    private String[] toastStyleArray;
    private int toast_style_value;
    private SetttingClickView scv_toast_style;
    private SetttingClickView scv_toast_location;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);
        initUpdate();
        initPhoneAddress();
        initToastStyle();
        initToastLocation();
    }

    /**
     * 设置中心列表中第4个条目:设置归属地提示框位置
     */
    private void initToastLocation() {
        scv_toast_location = findViewById(R.id.scv_toast_location);
        scv_toast_location.setTitle("归属地提示框位置");
        scv_toast_location.setDes("设置归属地提示框位置");
        scv_toast_location.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(getApplicationContext(),ToastLocationActivity.class);
                startActivity(intent);
            }
        });
    }

    /**
     * 设置中心列表中第3个条目:设置归属地显示风格
     */
    private void initToastStyle() {
        scv_toast_style = findViewById(R.id.scv_toast_style);
        scv_toast_style.setTitle("设置归属地显示风格");
        //1.创建描述文字所在的string类型的数组
        toastStyleArray = new String[]{"透明","橙色","蓝色","灰色","绿色"};
        //2.通过sp中存储的显示样式对应的索引值,用于获取描述文字
        toast_style_value = SharePreferenceUtil.getInt(getApplicationContext(),ConstantValue.TOAST_STYLE,0);
        //3.通过索引,获取字符串数组中的文字,让控件显示
        scv_toast_style.setDes(toastStyleArray[toast_style_value]);
        //4.给自定义控件绑定点击事件
        scv_toast_style.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showToastStyleDialog();
            }
        });
    }

    /**
     * 创建选择toast显示样式对话框
     */
    private void showToastStyleDialog() {
        AlertDialog.Builder builder=new AlertDialog.Builder(this);
        builder.setIcon(R.mipmap.ic_launcher); //设置对话框图标
        builder.setTitle("请选择归属地样式"); //设置标题

        /*
          选择单个条目事件监听
          参数1:string类型的数组描述颜色
          参数2:弹出对话框选中条目的索引值
          参数3:点击某一个条目后触发的点击事件(1.记录选择的索引值 2.关闭对话框 3.显示选中颜色的文字)
         */
        builder.setSingleChoiceItems(toastStyleArray, toast_style_value, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //(1.记录选择的索引值 2.关闭对话框 3.显示选中颜色的文字)
                SharePreferenceUtil.putInt(getApplicationContext(),ConstantValue.TOAST_STYLE,which);
                dialog.dismiss(); //关闭对话框
                scv_toast_style.setDes(toastStyleArray[which]);
            }
        });

        //消极按钮
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.show(); //显示对话框

    }

    /**
     * 设置中心列表中第2个条目:是否显示电话号码归属地的方法
     */
    private void initPhoneAddress() {
        final SetttingItemView siv_phone_address=findViewById(R.id.siv_phone_address);
        //获取已有的开关状态,用来显示
        boolean open_phone=SharePreferenceUtil.getBoolean(this,ConstantValue.OPEN_PHONE,false);
        siv_phone_address.setChecked(open_phone);
        //点击过程中,状态切换过程
        siv_phone_address.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取之前的选中状态
                boolean isCheck=siv_phone_address.isChecked();
                //将原有状态取反,设置为当前状态
                siv_phone_address.setChecked(!isCheck);
                //将当前状态保存到SharePreference中(进行更新)
                SharePreferenceUtil.putBoolean(getApplicationContext(),ConstantValue.OPEN_PHONE,!isCheck);

                WindowManager windowManager= (WindowManager) getSystemService(WINDOW_SERVICE);
                if(!isCheck){
                    //调用自定义toast
                    toastView=ToastUtil.showToast(getApplicationContext(),windowManager,"hello linda");
                }else {
                    if(toastView!=null){
                        ToastUtil.closeToast(windowManager,toastView);
                    }
                }

            }
        });
    }

    /**
     * 设置中心列表中第1个条目:自动更新模块
     */
    private void initUpdate() {
        final SetttingItemView siv_update=findViewById(R.id.siv_update);
        //获取已有的开关状态,用来显示
        boolean open_update=SharePreferenceUtil.getBoolean(this,ConstantValue.OPEN_UPDATE,false);
        siv_update.setChecked(open_update);

        siv_update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取之前的选中状态
                boolean isCheck=siv_update.isChecked();
                //将原有状态取反,设置为当前状态
                siv_update.setChecked(!isCheck);
                //将当前状态保存到SharePreference中(进行更新)
                SharePreferenceUtil.putBoolean(getApplicationContext(),ConstantValue.OPEN_UPDATE,!isCheck);
            }
        });
    }
}

(2)设置Toast控件显示位置的页面后台代码:ToastLocationActivity.java

package com.example.administrator.test62360safeguard;

import android.annotation.SuppressLint;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.example.administrator.test62360safeguard.Utils.ConstantValue;
import com.example.administrator.test62360safeguard.Utils.SharePreferenceUtil;

public class ToastLocationActivity extends AppCompatActivity {

    ImageView iv_drag;
    Button bt_drag_visible;
    Button bt_drag_invisible;
    private int startX;
    private int startY;
    private WindowManager windowManager;
    private int window_width;
    private int window_height;
    private long[] mHits = new long[2];

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

        initUI();
    }

    @SuppressLint("ClickableViewAccessibility")
    private void initUI() {
        iv_drag = findViewById(R.id.ivTL_drag_pic);
        bt_drag_visible = findViewById(R.id.bt_drag_visible);
        bt_drag_invisible = findViewById(R.id.bt_drag_invisible);
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        window_width = windowManager.getDefaultDisplay().getWidth();
        window_height=windowManager.getDefaultDisplay().getHeight();


        int location_x=SharePreferenceUtil.getInt(getApplicationContext(),ConstantValue.LOCATION_X,0);
        int location_y=SharePreferenceUtil.getInt(getApplicationContext(),ConstantValue.LOCATION_Y,0);
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.leftMargin=location_x;
        layoutParams.topMargin=location_y;
        iv_drag.setLayoutParams(layoutParams);

        //给控件绑定双击事件
        iv_drag.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
                mHits[mHits.length-1] = SystemClock.uptimeMillis();
                if(mHits[mHits.length-1]-mHits[0]<500){
                    //满足双击事件后,调用代码
                    int left = window_width/2 - iv_drag.getWidth()/2;  //left表示控件左边缘距屏幕左侧的距离
                    int top = window_height/2 - iv_drag.getHeight()/2;
                    int right = window_width/2+iv_drag.getWidth()/2;
                    int bottom = window_height/2+iv_drag.getHeight()/2;

                    //控件按以上规则显示
                    iv_drag.layout(left, top, right, bottom);

                    //存储最终位置
                    SharePreferenceUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X, iv_drag.getLeft());
                    SharePreferenceUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y, iv_drag.getTop());
                }
            }
        });

        //监听某一个控件的拖拽事件(按下、移动、放下)
        iv_drag.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getRawX(); //获取点击位置(移动前)相对于整个屏幕原点(左上)的x距离
                        startY = (int) event.getRawY(); //获取点击位置(移动前)相对于整个屏幕原点(左上)的y距离
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int moveX = (int) event.getRawX(); //获取点击位置(移动后)相对于整个屏幕原点(左上)的x距离
                        int moveY = (int) event.getRawY();//获取点击位置(移动后)相对于整个屏幕原点(左上)的y距离
                        int disX=moveX-startX;  //x方向的移动距离
                        int disY=moveY-startY;  //y方向的移动距离

                        //1.当前控件所在屏幕的左上角的位置
                        //getLeft()获取该控件与父控件的相对位置
                        int left=iv_drag.getLeft()+disX; //控件(移动后)左侧坐标=控件(移动前)左侧坐标+移动距离
                        int top=iv_drag.getTop()+disY; //顶端坐标
                        int right=iv_drag.getRight()+disX;
                        int bottom=iv_drag.getBottom()+disY;

                        //容错处理:控件不能拖拽出手机屏幕
                        //左边缘不能超出屏幕
                        if(left<0){
                            return true;
                        }

                        if (right>window_width){
                            return true;
                        }

                        if (top<0){
                            return true;
                        }
                        if(bottom>window_height-30){
                            return true;
                        }
                        //2.告知移动的控件,按照计算出来的坐标去展示
                        iv_drag.layout(left,top,right,bottom);

                        //3.重置起始位置的坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        //4.存储移动后的位置坐标
                        SharePreferenceUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_X,iv_drag.getLeft());
                        SharePreferenceUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_Y,iv_drag.getTop());
                        break;
                }
                //(1)若只需要响应拖拽事件,应该返回true
                //(2)既要响应点击事件,又要响应拖拽过程,则此返回值结果需要修改为false
                return false;
            }
        });
    }
}

3.效果图

posted @ 2019-05-09 17:07  雨后观山色  阅读(644)  评论(0编辑  收藏  举报