zoukankan      html  css  js  c++  java
  • 17、Android--悬浮控件

    Toas

    Android中的Toast是一种简易的消息提示框。

    基本吐司

    基本Toast的使用如下所示:

    Toast.makeText(MainActivity.this, "按钮被单击", Toast.LENGTH_SHORT).show();  
    

    Toast默认的位置在于屏幕的下方居中的位置,如果想改变Toast的位置则可以设置Gravity:

    Toast toast = Toast.makeText(this, "当前已是最新版本", Toast.LENGTH_SHORT);
    toast.setGravity(Gravity.CENTER, 0, 0);
    toast.show();  
    

    自定义吐司

    在Android中还可以自定义吐司,来改变吐司的显示位置和存在的时间等。

    private void showMyToast(String address) {
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        View view = View.inflate(this, R.layout.total_address, null);
        TextView tv_address = (TextView) view.findViewById(R.id.tv_address);
        tv_address.setText(address);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        params.format = PixelFormat.TRANSLUCENT;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        wm.addView(view, params);
    } 
    

    注意:在自定义Tost使用完后必须调用WindowManager的removeView(view)来释放资源。

    Toast工具类

    Toast一般要求在主线程执行,所以我们可以编写工具类对Toast所在线程进行判断,然后执行相应的操作。

    public class ToastUtils {
        private static final String TAG = "ToastUtil";
        public static void showToast(final Activity context, final String messages) {
            if ("main".equals(Thread.currentThread().getName())) {
                Toast.makeText(context, messages, Toast.LENGTH_LONG).show();
            } else {
                context.runOnUiThread(() -> Toast.makeText(context, messages, Toast.LENGTH_LONG).show());
            }
        }
    }
    

    PopupWindow

    PopupWindow,顾名思义弹窗。PopupWindow是与AlertDialog在形式上类似的弹窗功能,都是为了在activity最上层显示一个弹窗.但是区别是PopupWindow可以自定义出现的位置,并且可以添加入自己需要的View或者导入自己写好的xml布局。

    TextView textView = new TextView(MainActivity.this);
    textView.setText("测试文本");
    PopupWindow popupWindow = new PopupWindow(textView, 200, 300);//参数为1.View 2.宽度 3.高度
        popupWindow.setOutsideTouchable(true); //设置点击外部区域可以取消popupWindow
    mTestButton = (Button)findViewById(R.id.test_btn);
        mTestButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //设置popupWindow显示,并且告诉它显示在那个View下面
            popupWindow.showAsDropDown(mTestButton);
        }
    });
    

    使用详解

    常用函数

    PopupWindow常用的构造函数如下所示:

    public PopupWindow (Context context)
    public PopupWindow(View contentView, int width, int height)
    public PopupWindow(View contentView)
    public PopupWindow(View contentView, int width, int height, boolean focusable)
    

    PopupWindow常用的方法如下所示:

    setContentView(View contentView):设置PopupWindow显示的View
    getContentView():获得PopupWindow显示的View
    setTouchable(true):设置PopupWindow可触摸
    setOutsideTouchable(boolean touchable):设置外部点击退出
    showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
    showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
    showAtLocation(View parent, int gravity, int x, int y): 相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移 PS:parent这个参数只要是activity中的view就可以了!
    setWidth/setHeight:设置宽高,也可以在构造方法那里指定好宽高, 除了可以写具体的值,还可以用WRAP_CONTENT或MATCH_PARENT, popupWindow的width和height属性直接和第一层View相对应。
    setFocusable(true):设置焦点,设置焦点后,如果返回按下返回键,不会直接退出当前activity而是先退出当前的PopupWindow。
    setAnimationStyle(int):设置动画效果
    

    其中设置PopupWindow的显示方法有两种方式,分别是:showAsDropDown()和showAtLocation()

    位置显示

    showAtLocation()显示View的内部在指定位置(),它有两个方法的重载:

    public void showAtLocation(View parent, int gravity, int x, int y)
    public void showAtLocation(IBinder token, int gravity, int x, int y)
    

    showAsDropDown()显示在一个参照物View的外部周围,有三个方法重载,这里参照物View的周围,使用这个方法是无法在View的内部找到锚点,它的锚点都是围绕者View的外部四周

    public void showAsDropDown(View anchor)
    public void showAsDropDown(View anchor, int xoff, int yoff)
    public void showAsDropDown(View anchor, int xoff, int yoff, int gravity)
    

    带Gravity参数的方法是API 19新引入的。这里的xoff与yoff是对应view的坐标偏移量,对应的初始坐标位置是view的左下角。

    适配问题

    解决Android7.0调用showAsDropDown方法失效问题:
    原理是重写showAsDropDown,将PopupWindow对话框的高度设置成整个屏幕这么大,然后在减去这View指定的底部坐标值。

    @Override
    public void showAsDropDown(View anchor) {
        if(Build.VERSION.SDK_INT >= 24) {
            Rect rect = new Rect();
            anchor.getGlobalVisibleRect(rect);
            DisplayMetrics outMetrics = new DisplayMetrics();
            Context context = anchor.getContext();
            ((Activity) context).getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics);
            int h = outMetrics.heightPixels - rect.bottom;
            setHeight(h);
        }
        super.showAsDropDown(anchor);
    }
    

    对话框

    Android中提供了种类丰富的对话框:

    名称 描述
    AlertDialog 功能最丰富、实际使用最广的对话框
    ProgressDialog 进度对话框,这个对话框支持简单进度条的封装
    DatePickDialog 日期选择对话框,该对话框只是对DatePicker的包装
    TimePickDialog 时间选择对话框,该对话框只是对TimePick的包装

    除上表列出的对话框外,我们还可以进行自定义对话框。

    常用对话框

    1、确定取消对话框

    AlertDialog.Builder builder = new Builder(this);
    builder.setTitle("友情提醒");
    builder.setMessage("若练此功,必先自宫,是否继续?");
    builder.setPositiveButton("好的,想好了", new OnClickListener() {
    	@Override
    	public void onClick(DialogInterface dialog, int which) {
    		Toast.makeText(MainActivity.this, "啊。。。", 0).show();
    		Toast.makeText(MainActivity.this, "即使自宫,也不一定成功", 0).show();
    	}
    });
    builder.setNegativeButton("想想再说", new OnClickListener() {
    	@Override
    	public void onClick(DialogInterface dialog, int which) {
    		Toast.makeText(MainActivity.this, "若不自宫,一定不成功", 0).show();
    	}
    });
    builder.create().show();
    

    2、单选对话框

    AlertDialog.Builder builder = new Builder(this);
    builder.setTitle("请选择性别:");
    final String[] items = { "男", "女", "未知" };
    builder.setSingleChoiceItems(items, 2, new OnClickListener() {
    	@Override
    	public void onClick(DialogInterface dialog, int which) {
    		dialog.dismiss();
    		Toast.makeText(MainActivity.this, "您的性别:" + items[which], 0).show();
    	}
    });
    builder.show();
    

    3、多选对话框

    AlertDialog.Builder builder = new Builder(this);
    builder.setTitle("请选择您喜欢的水果:");
    final String[] items = { "苹果", "香蕉", "葡萄", "橘子" };
    final boolean[] result = new boolean[] { true, true, false, false };
    builder.setMultiChoiceItems(items, result,
    		new OnMultiChoiceClickListener() {
    			@Override
    			public void onClick(DialogInterface dialog, int which, boolean isChecked) {
    				result[which] = isChecked;
    				Toast.makeText(MainActivity.this,items[which] + isChecked, 0).show();
    			}
    		});
    builder.setPositiveButton("提交", new OnClickListener() {
    	@Override
    	public void onClick(DialogInterface dialog, int which) {
    		StringBuffer sb = new StringBuffer();
    		for (int i = 0; i < result.length; i++) {
    			if (result[i]) 
    				sb.append(items[i] + ",");
    		}
    		Toast.makeText(MainActivity.this, "您喜欢:" + sb.toString(), 0).show();
    	}
    });
    builder.show();
    

    4、进度对话框

    final ProgressDialog pd = new ProgressDialog(this);
    pd.setTitle("提醒");
    pd.setMessage("正在处理中。。。请稍后");
    pd.show();
    new Thread() {
    	public void run() {
    		try {
    			Thread.sleep(5000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		pd.dismiss();
    	};
    }.start(); 
    

    5、进度条对话框

    final ProgressDialog pd = new ProgressDialog(this);
    // 设置进度的样式
    pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    pd.setTitle("提醒");
    pd.setMessage("正在处理中。。。请稍后");
    pd.show();
    new Thread() {
    	public void run() {
    		pd.setMax(100);
    		try {
    			for (int i = 0; i <= 100; i++) {
    				pd.setProgress(i);
    				Thread.sleep(500);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		pd.dismiss();
    	};
    }.start();
    

    样式对话框

    基本对话框

    在Android中可以对对话框进行简单的定制,代码如下:

    Builder builder = new Builder(this);
    View view = View.inflate(this, R.layout.item_dialog, null);
    final AlertDialog dialog = builder.create();
    dialog.setView(view, 0, 0, 0, 0);
    dialog.show();
    Button btn_ok = (Button) view.findViewById(R.id.btn_item_ok);
    Button btn_cancel = (Button) view.findViewById(R.id.btn_item_cancel);
    btn_ok.setOnClickListener(new OnClickListener() {
    	@Override
    	public void onClick(View v) {
    		Toast.makeText(MainActivity.this, "确认对话框被按下", 0).show();
    		dialog.dismiss();
    	}
    });
    btn_cancel.setOnClickListener(new OnClickListener() {   
    	@Override
    	public void onClick(View v) {
    		Toast.makeText(MainActivity.this, "取消对话框被按下", 0).show();
    		dialog.dismiss();
    	}
    });
    

    底部弹出对话框

    除了自定义布局文件外,还可以对弹出位置进行修改

    View view = getLayoutInflater().inflate(R.layout.photo_choose_dialog, null);
    dialog = new Dialog(this, R.style.transparentFrameWindowStyle);
    dialog.setContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    Window window = dialog.getWindow();
    window.setWindowAnimations(R.style.main_menu_animstyle);
    WindowManager.LayoutParams wl = window.getAttributes();
    wl.x = 0;
    wl.y = getWindowManager().getDefaultDisplay().getHeight();
    wl.width = ViewGroup.LayoutParams.MATCH_PARENT;
    wl.height = ViewGroup.LayoutParams.WRAP_CONTENT;
    
    dialog.onWindowAttributesChanged(wl);
    dialog.setCanceledOnTouchOutside(false);
    dialog.show();
    // 初始化
    Button btnCamera = (Button) view.findViewById(R.id.btn_phonedialog_camera);
    Button btnPhoto = (Button) view.findViewById(R.id.btn_phonedialog_photo);
    Button btnCancel = (Button) view.findViewById(R.id.btn_phonedialog_cancel);
    
    btnCamera.setOnClickListener(new OnClickListener() {
    	@Override
    	public void onClick(View v) {           
    	}
    });
    
    btnPhoto.setOnClickListener(new OnClickListener() {
    	@Override
    	public void onClick(View v) {
    	}
    });
    
    btnCancel.setOnClickListener(new OnClickListener() {
    	@Override
    	public void onClick(View v) {
    	}
    });
    

    其中使用到的样式

    <style name="transparentFrameWindowStyle" parent="android:style/Theme.Dialog">
        <item name="android:windowBackground">@drawable/photo_choose_bg</item>
    </style>
    <style name="main_menu_animstyle">
        <item name="android:windowEnterAnimation">@anim/photo_dialog_in_anim</item>
        <item name="android:windowExitAnimation">@anim/photo_dialog_out_anim</item>
    </style>  
    

    使用到的布局文件如下:

    <?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="match_parent"
        android:background="#00000000"
        android:gravity="bottom"
        android:orientation="vertical"
        android:padding="5dip" >
        <Button
            android:id="@+id/btn_phonedialog_camera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/photo_gallery_selector"
            android:paddingBottom="10dip"
            android:paddingTop="10dip"
            android:text="拍照"
            android:textSize="16sp" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="0.5dip"
            android:background="#DAD9DB" />
        <Button
            android:id="@+id/btn_phonedialog_photo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/photo_camera_selector"
            android:paddingBottom="10dip"
            android:paddingTop="10dip"
            android:text="从手机相册选择"
            android:textSize="16sp" />
        <Button
            android:id="@+id/btn_phonedialog_cancel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dip"
            android:background="@drawable/photo_cancel_selector"
            android:paddingBottom="10dip"
            android:paddingTop="10dip"
            android:text="取消"
            android:textSize="16sp" />
    </LinearLayout>  
    

    全局对话框

    写好Alert功能块后,在altet.show()语句前加入:

    alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    

    使用到的权限:

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

    如果只在Service中写入常在Activity中使用的创建Alert的代码,运行时是会发生错误的,因为Alter的显示需要依附于一个确定的 Activity类。而以上做法就是声明我们要弹出的这个提示框是一个系统的提示框,即全局性质的提示框,所以只要手机处于开机状态,无论它现在处于何种 界面之下,只要调用alter.show(),就会弹出提示框来。

    AlertDialog.Builder builder = new AlertDialog.Builder(this); 
    builder.setMessage("Are you sure you want to exit?") 
           .setCancelable(false) 
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() { 
               public void onClick(DialogInterface dialog, int id) { 
                    MyActivity.this.finish(); 
               } 
           }) 
           .setNegativeButton("No", new DialogInterface.OnClickListener() { 
               public void onClick(DialogInterface dialog, int id) { 
                    dialog.cancel(); 
               } 
           }); 
           
    AlertDialog alert = builder.create(); 
      alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
      alert.show();
    

    自定义对话框

    1、 在theme.xml或style.xml中定义对话框的样式:

    <style name="CustomDialog">
        <!-- alertDialog窗口背景色 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!--dialog是否有边框-->
        <item name="android:windowFrame">@null</item>
        <!--dialog是否有标题-->
        <item name="android:windowNoTitle">true</item>
        <!--是否浮现在activity之上-->
        <item name="android:windowIsFloating">true</item>
        <!--是否半透明-->
        <item name="android:windowIsTranslucent">true</item>
        <!--是否有遮盖(eg.Activity的闪屏页)-->
        <item name="android:windowContentOverlay">@null</item>
        <!--进出动画-->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <!--背景是否模糊显示-->
        <item name="android:backgroundDimEnabled">true</item>
    </style>
    

    2、创建自定义的对话框继承自Dialog,并在构造函数中配置相关参数:

    public class GeneralDialog extends Dialog {
        private Context mContext;
        @BindView(R.id.title)
        TextView mTvTitle;
        @BindView(R.id.confirm)
        Button mBtnConfirm;
        @BindView(R.id.cancel)
        Button mBtnCancel;
        private OnGeneralClickListener mListener;
        public GeneralDialog(Context context) {
            super(context, R.style.CustomDialog);
            this.mContext = context;
            View view = View.inflate(mContext, R.layout.dialog_genera_layout, null);
            ButterKnife.bind(this, view);
            setContentView(view);
            // Init Dialog
            setCanceledOnTouchOutside(true);
            setCancelable(true);
            WindowManager.LayoutParams params = this.getWindow().getAttributes();
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.gravity = Gravity.CENTER;
            this.getWindow().setAttributes(params);
            // Init Event
            mBtnConfirm.setOnClickListener(v -> {
                if (mListener != null)
                    mListener.onConfirmClick(v);
            });
            mBtnCancel.setOnClickListener(v -> {
                if (mListener != null)
                    mListener.onCancelClick(v);
            });
        }
        public void setCustomTitle(int titleStr){
            mTvTitle.setText(titleStr);
        }
        public void setOnGeneralClickListener(OnGeneralClickListener listener){
            this.mListener = listener;
        }
        public interface OnGeneralClickListener{
            void onConfirmClick(View view);
            void onCancelClick(View view);
        }
    }
    

    3、如果想让对话框的宽度能铺满全屏,可以做如下设置

    setCanceledOnTouchOutside(true);
    setCancelable(true);
    WindowManager.LayoutParams params = this.getWindow().getAttributes();
    params.width = WindowManager.LayoutParams.MATCH_PARENT;
    params.height = WindowManager.LayoutParams.WRAP_CONTENT;
    params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
    params.y = DensityUtils.dip2px(context, 145);
    this.getWindow().setAttributes(params);
    this.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
    

    4、使用自定义对话框代码如下:

    GeneralDialog generalDialog = new GeneralDialog(SplashActivity.this);
    generalDialog.setCustomTitle(R.string.text_splash_network_desc);
    generalDialog.setOnGeneralClickListener(new GeneralDialog.OnGeneralClickListener() {
        @Override
        public void onConfirmClick(View view) {
            startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
            generalDialog.dismiss();
        }
        @Override
        public void onCancelClick(View view) {
            requestPermission();
            generalDialog.dismiss();
        }
    });
    generalDialog.show();
    
  • 相关阅读:
    【年度总结】——踏雪留痕
    ios提交程序后出现的各种问题
    c++动态库中使用命名空间的问题
    第八章 网络的时代—网络开发(4)
    USB otg 学习笔记
    servlet_3
    Windows server 2012清除并重建SID
    实时监听输入框值变化:oninput & onpropertychange
    JQuery 自动触发事件
    jquery input change事件
  • 原文地址:https://www.cnblogs.com/pengjingya/p/5509055.html
Copyright © 2011-2022 走看看