Skip to content

改变DialogFragment的显示属性

例如改变Dialog的显示位置,将背景设置为透明,去掉默认阴影等等。

改变背景颜色

Dialog一般都有它自己的背景。我们可以查看SDK中的资源文件,找到Base.V7.ThemeOverlay.AppCompat.Dialog主题。 看到android:windowBackground指定为@drawable/abc_dialog_material_background

我们可以拿到dialog的window,再来设置window的背景。

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Window dialogWindow = getDialog().getWindow();
        if (dialogWindow != null) {
            dialogWindow.setBackgroundDrawableResource(android.R.color.transparent); // dialog背景设置为透明
            // ....
        }
    }

我们可以看改变背景颜色的前后对比图。可以看到默认的背景是白色的。右图的背景变成了透明的。

改变背景颜色并不是去掉阴影。

去掉背景阴影

默认情况下dialog会有一层阴影,把后面的内容遮盖。我们也可以让dialogWindow去掉这个阴影。

dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

DialogFragment自定义位置

例如让Dialog显示在点击的位置上。

调整显示位置,需要改变Dialog window的WindowManager.LayoutParams

如果要同时调整x和y位置,需要先设置gravity dialogWindow.setGravity(Gravity.TOP | Gravity.START)

获取到LayoutParams后,修改它的x和y值。

public class AdjustLocationDialog extends DialogFragment {
    private static final String TAG = "rustAppDialog";
    private static final String K_X = "k_x";
    private static final String K_Y = "k_y";

    public AdjustLocationDialog() {
    }

    public static AdjustLocationDialog newDialog(int x, int y) {
        AdjustLocationDialog dialog = new AdjustLocationDialog();
        Bundle bundle = new Bundle();
        bundle.putInt(K_X, x);
        bundle.putInt(K_Y, y);
        dialog.setArguments(bundle);
        return dialog;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate: " + getArguments());
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        Window dialogWindow = getDialog().getWindow();
        if (dialogWindow != null) {
            WindowManager.LayoutParams lp = dialogWindow.getAttributes();
            dialogWindow.setGravity(Gravity.TOP | Gravity.START);
            dialogWindow.setBackgroundDrawableResource(android.R.color.transparent); // dialog背景设置为透明
            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;

            Bundle bundle = getArguments();
            if (bundle != null) {
                lp.x = bundle.getInt(K_X);
                lp.y = bundle.getInt(K_Y);
                Log.d(TAG, "onCreateView: y == " + lp.y);
            } else {
                Log.w(TAG, "onCreateView: input bundle is null.");
            }

            dialogWindow.setAttributes(lp);
        }
        return inflater.inflate(R.layout.dialog_input_text, container, false);
    }
}

layout文件dialog_input_text.xml。里面放置TextView与EditText。

<?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:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    android:background="#00000000"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/adjust_dialog_et_height"
        android:background="@drawable/shape_input_text_popup_bg"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingStart="4dp"
        android:paddingEnd="4dp">

        <TextView
            android:id="@+id/note_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="请输入:"
            android:textSize="12sp" />

        <EditText
            android:id="@+id/et"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="4dp"
            android:background="@null"
            android:focusable="true"
            android:gravity="center_vertical"
            android:inputType="text"
            android:minWidth="100dp"
            android:textSize="14sp" />
    </LinearLayout>

</LinearLayout>

尺寸定义

<dimen name="adjust_dialog_et_height">36dp</dimen>

如何获取点击位置

手指触摸到屏幕上,系统会告诉app点击位置。我们用OnTouchListener来获取点击位置。

下面是Adapter中监听触摸事件的监听器。以及点击事件的监听器。

holder.tv.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        downX = event.getX();
        downY = event.getY();
        rawX = event.getRawX();
        rawY = event.getRawY();
        Log.d(TAG, String.format(Locale.CHINA, "x,y {%.2f, %.2f}; raw-x,y {%.2f,%.2f}",
                downX, downY, rawX, rawY));
        return false;
    }
});
holder.tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (onItemClick != null) {
            onItemClick.onClick((int) rawX, (int) rawY);
        }
    }
});

在触摸监听器中返回false,表示我们不处理这个触摸事件。点击事件可以正常监听到。 在onTouch中把触摸坐标记录下来。等到onClick时,再利用坐标数据。

event.getX()event.getY()获取到的是当前View的触摸坐标。 event.getRawX()event.getRawY()获取到的是屏幕的触摸坐标。即触摸点在屏幕上的位置。

EditText不被软键盘遮挡

上面的例子中,Dialog可在任意地方弹出。 若dialog在屏幕下方弹出,此时我们要输入文字到弹窗的EditText,弹出的软键盘(soft keyboard)会把dialog挡住。

我们希望EditText不被软键盘遮挡,提高用户体验。可以对dialogWindow进行一些调整。

可设置 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)

dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

弹出dialog后,dialog移动到软键盘的正上方。

代码在这 https://github.com/AnRFDev/Tutorial2020