Android透明背景Dialog、Dialog实现悬浮窗口 可与输入法交互,不被输入法覆盖

直接干货上代码!

直接干货上代码!

PersonSetRemarkDialog 核心代码

package com.ctri.ui.personal.widget;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.TextView;

import com.ctri.ui.R;


/********************
 * 设置备注dialog
 ********************/
public class PersonSetRemarkDialog extends AlertDialog {

    private OnCertainButtonClickListener mOnCertainButtonClickListener;
    private Context context;


    public interface OnCertainButtonClickListener {
        void onCertainButtonClick(String remark);
    }

    public PersonSetRemarkDialog(Context context) {
        super(context);
        this.context = context;
    }

    public void setOnCertainButtonClickListener(OnCertainButtonClickListener listener) {
        mOnCertainButtonClickListener = listener;
    }


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

        TextView mSure = (TextView) findViewById(R.id.dialog_person_setremark_ensure);
        final EditText et = (EditText) findViewById(R.id.dialog_person_setremark_edit);
        et.setFocusable(true);

        mSure.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnCertainButtonClickListener != null) {
                    String remark = et.getText().toString();
                    mOnCertainButtonClickListener.onCertainButtonClick(remark);
                }
                PersonSetRemarkDialog.this.dismiss();
            }

        });
        findViewById(R.id.dialog_person_setremark_cancle).setOnClickListener(new View
                .OnClickListener() {
            @Override
            public void onClick(View view) {
                PersonSetRemarkDialog.this.dismiss();
            }
        });
        findViewById(R.id.dialog_person_setremark_cancle_x).setOnClickListener(new View
                .OnClickListener() {
            @Override
            public void onClick(View view) {
                PersonSetRemarkDialog.this.dismiss();
            }
        });

        setCancelable(false);
        getWindow().setBackgroundDrawableResource(android.R.color.transparent);//只有这样才能去掉黑色背景

    }

    @Override
    public void show() {
        super.show();
        //这样后边的view怎么获取焦点呢? 谁调用 谁就可以获取焦点 如下
        // mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //mWm.updateViewLayout(view, mParams);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager
                .LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    }
}

dialog_person_setremark.xml  布局


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/transparent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/dialog_person_setremark_border"
        android:layout_width="1dp"
        android:layout_height="20dp"
        android:layout_below="@+id/dialog_person_setremark_layout"
        android:layout_centerHorizontal="true"
        android:background="@color/white"/>
    <ImageView
        android:id="@+id/dialog_person_setremark_cancle_x"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_below="@+id/dialog_person_setremark_border"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:scaleType="fitXY"
        android:src="@drawable/clearedittext"/>

    <RelativeLayout
        android:id="@+id/dialog_person_setremark_layout"
        android:layout_width="270dp"
        android:layout_height="185dp"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:background="@color/white"
    >
        <TextView
            android:id="@+id/dialog_person_setremark_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="12dp"
            android:text="设置备注"
            android:textColor="@color/home_title_color"
            android:textSize="@dimen/font_size_18"/>

        <EditText
            android:id="@+id/dialog_person_setremark_edit"
            android:layout_width="240dp"
            android:layout_height="36dp"
            android:layout_below="@+id/dialog_person_setremark_title"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="@dimen/margin_size_20"
            android:background="@drawable/bg_buy_gray"
            android:gravity="center"
            android:hint="1~8个汉字"
            android:inputType="number"
            android:padding="5dp"
            android:singleLine="true"
            android:textColor="@color/black"
            android:textSize="16sp"/>


        <TextView
            android:id="@+id/dialog_person_setremark_cancle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignEnd="@+id/dialog_person_setremark_edit"
            android:layout_below="@+id/dialog_person_setremark_edit"
            android:layout_marginEnd="6dp"
            android:layout_marginLeft="@dimen/margin_size_25"
            android:layout_marginTop="28dp"
            android:background="@drawable/detail_community_add_bg"
            android:ems="6"
            android:gravity="center"
            android:paddingBottom="@dimen/margin_size_5"
            android:paddingLeft="@dimen/margin_size_20"
            android:paddingRight="@dimen/margin_size_20"
            android:paddingTop="@dimen/margin_size_5"
            android:text="取消"
            android:textColor="@color/bg_red"
            android:textSize="@dimen/font_size_15"/>

        <TextView
            android:id="@+id/dialog_person_setremark_ensure"
            android:layout_width="112.5dp"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/dialog_person_setremark_cancle"
            android:layout_alignBottom="@+id/dialog_person_setremark_cancle"
            android:layout_alignStart="@+id/dialog_person_setremark_edit"
            android:background="@drawable/detail_sub_bg"
            android:ems="6"
            android:gravity="center"
            android:paddingBottom="@dimen/margin_size_5"
            android:paddingLeft="@dimen/margin_size_20"
            android:paddingRight="@dimen/margin_size_20"
            android:layout_marginBottom="20dp"
            android:paddingTop="@dimen/margin_size_5"
            android:text="确定"
            android:textColor="@color/white"
            android:textSize="@dimen/font_size_15"/>
    </RelativeLayout>
<

调用方法

PersonSetRemarkDialog personSetRemarkDialog = new PersonSetRemarkDialog
                        (getContext());
                personSetRemarkDialog.setOnCertainButtonClickListener(new PersonSetRemarkDialog
                        .OnCertainButtonClickListener() {
                    @Override
                    public void onCertainButtonClick(String remark) {
                        ToastHelper.getInstance()._toast("success");
                        if (!remark.isEmpty()) {
                            tv_personal_name.setText(remark);
                        }
                    }
                });
                personSetRemarkDialog.show();


简单吧,使用的图片我就不传了,可以自己弄一个。



在说点额外的知识,调用的view(activity、fragment)是怎么获取焦点的呢?

WindowManager mWm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);   
Button view = new Button(this);   
view.setText("window manager test!");   
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();    
mWm.addView(view, mParams);

我们这个button的显示和当前的运行环境基本上是无关的,当前是什么activity或者是桌面,使用这个底层的结果给你的编程带来很大的灵活性,但是要注意,显示出来就要销毁掉,这个是必须的,销毁其实就是一个remove。

但是仅仅这么写会有个问题,就是view显示在最上层,但是后面的view无法获得焦点,当你touch的坐标超出上次view的范围时

mParams = new WindowManager.LayoutParams();   
mWm.updateViewLayout(view, mParams);

需要后面的view获得焦点时:

mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;    
mWm.updateViewLayout(view, mParams);
别忘了在AndroidManifest.xml中添加权限:

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

public int flags;
行为选项/旗标,默认为 none .
下面定义了 flags 的取值:


不许获得焦点。
不能获得按键输入焦点,所以不能向它发送按键或按钮事件。那些时间将发送给它后面的可以获得焦点的窗口。此选项还会设置FLAG_NOT_TOUCH_MODAL选项。设置此选项,意味着窗口不能与软输入法进行交互,所以它的Z序独立于任何活动的输入法(换句话说,它可以全屏显示,如果需要的话,可覆盖输入法窗口)。要修改这一行为,可参考FLAG_ALT_FOCUSALBE_IM选项。
public static final int FLAG_NOT_FOCUSABLE = 0x00000008;

不接受触摸屏事件。
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;

当窗口可以获得焦点(没有设置 FLAG_NOT_FOCUSALBE 选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围内。
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;

另外一种情况

当请求布局时,你的窗口可能出现在状态栏的上面或下面,从而造成遮挡。当设置这一选项后,窗口管理器将确保窗口内容不会被装饰条(状态栏)盖住。
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;

反转FLAG_NOT_FOCUSABLE选项。
如果同时设置了FLAG_NOT_FOCUSABLE选项和本选项,窗口将能够与输入法交互,允许输入法窗口覆盖;
如果FLAG_NOT_FOCUSABLE没有设置而设置了本选项,窗口不能与输入法交互,可以覆盖输入法窗口。
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;

如果你设置了FLAG_NOT_TOUCH_MODAL,那么当触屏事件发生在窗口之外事,可以通过设置此标志接收到一个MotionEvent.ACTION_OUTSIDE事件。注意,你不会收到完整的down/move/up事件,只有第一次down事件时可以收到ACTION_OUTSIDE。
public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;

跟输入法的关系

7. public int softInputMode;
软输入法模式选项:
以下选项与 softInputMode 有关:
软输入区域是否可见。
public static final int SOFT_INPUT_MASK_STATE = 0x0f;

未指定状态。
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;

不要修改软输入法区域的状态。
public static final int SOFT_INPUT_STATE_UNCHANGED = 1;

隐藏输入法区域(当用户进入窗口时)。
public static final int SOFT_INPUT_STATE_HIDDEN = 2;

当窗口获得焦点时,隐藏输入法区域。
public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;

显示输入法区域(当用户进入窗口时)。
public static final int SOFT_INPUT_STATE_VISIBLE = 4;

当窗口获得焦点时,显示输入法区域。
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;

窗口应当主动调整,以适应软输入窗口。
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;

未指定状态,系统将根据窗口内容尝试选择一个输入法样式。
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;

当输入法显示时,允许窗口重新计算尺寸,使内容不被输入法所覆盖。
不可与SOFT_INPUT_ADJUSP_PAN混合使用,如果两个都没有设置,系统将根据窗口内容自动设置一个选项。
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;

输入法显示时平移窗口。它不需要处理尺寸变化,框架能够移动窗口以确保输入焦点可见。
不可与SOFT_INPUT_ADJUST_RESIZE混合使用;如果两个都没设置,系统将根据窗口内容自动设置一个选项。
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;

当用户转至此窗口时,由系统自动设置,所以你不要设置它。
当窗口显示之后该标志自动清除。
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;


摘自网上的另一种实现,也贴出来。Android输入法弹出,设置控件在软键盘之上显示

描述:当输入法弹出时,布局会被压缩,某些控件被遮挡住,但是需求可能并不想让该控件遮挡住。如何让某些控件也浮在软件盘上,比如“登录”按钮。
解决:给最外层的布局设置一个OnGlobalLayoutListener的监听事件,当布局发生改变时改变控件位置的方式来实现,代码如下:

 /**
    * @param root 最外层布局,需要调整的布局
    * @param scrollToView  被键盘遮挡的scrollToView,滚动root,使scrollToView在root可视区域的底部
    */
    private void controlKeyboardLayout(final View root, final View scrollToView) {
        // 注册一个回调函数,当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时调用这个回调函数。
        root.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    Rect rect = new Rect();
                    // 获取root在窗体的可视区域
                    root.getWindowVisibleDisplayFrame(rect);
                    // 当前视图最外层的高度减去现在所看到的视图的最底部的y坐标
                    int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
                    // 若rootInvisibleHeight高度大于100,则说明当前视图上移了,说明软键盘弹出了
                    if (rootInvisibleHeight > 100) {
                        //软键盘弹出来的时候
                        int[] location = new int[2];
                        // 获取scrollToView在窗体的坐标
                        scrollToView.getLocationInWindow(location);
                        // 计算root滚动高度,使scrollToView在可见区域的底部
                        int srollHeight = (location[1] + scrollToView.getHeight() + PixelUtil.dp2px(20, getContext())) - rect.bottom;
                        if (srollHeight != 0){
                            root.scrollTo(0, srollHeight);
                        }
                    } else {
                        // 软键盘没有弹出来的时候
                        root.scrollTo(0, 0);
                    }
                }
            });
    }


实例:在一开始的时候已经给出,这样就可以在调用输入发的时候,把view顶上去,而不是覆盖view

@Override
    public void show() {
        super.show();
        //这样后边的view怎么获取焦点呢? 谁调用 谁就可以获取焦点 如下
        // mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //mWm.updateViewLayout(view, mParams);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager
                .LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    }

看了这篇文章收货很大,也引用了一部分,贴出来大家一起看。谢谢~

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1105/509.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值