web-dev-qa-db-ja.com

AndroidでのDialogFragmentの位置

ポップアップ画面のようなDialogFragmentを表示するViewがあります。ウィンドウは常に画面の中央に表示されます。 DialogFragmentウィンドウの位置を設定する方法はありますか? ソースコード を調べましたが、まだ何も見つかりませんでした。

58
alfacan

次のようなものを試してください:

_@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    getDialog().getWindow().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
    WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
    p.width = ViewGroup.LayoutParams.MATCH_PARENT;
    p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
    p.x = 200;
    ...
    getDialog().getWindow().setAttributes(p);
    ...
_

またはgetDialog().getWindow()のその他のメソッド。

set-contentを呼び出した後、必ず位置を設定してください。

93
Steelight

右、これで1〜2時間、壁に頭をぶつけて、最終的にDialogFragmentを思いどおりに配置しました。

私は Steelightの答え に基づいています。これは、私が見つけた最も単純で最も信頼できるアプローチです。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) {
    Window window = getDialog().getWindow();

    // set "Origin" to top left corner, so to speak
    window.setGravity(Gravity.TOP|Gravity.LEFT);

    // after that, setting values for x and y works "naturally"
    WindowManager.LayoutParams params = window.getAttributes();
    params.x = 300;
    params.y = 100;
    window.setAttributes(params);

    Log.d(TAG, String.format("Positioning DialogFragment to: x %d; y %d", params.x, params.y));
} 

ご了承ください params.widthおよびparams.softInputMode(Steelightの回答で使用されます)は、これには無関係です。


以下は、より完全な例です。私が本当に必要としていたのは、「ソース」または「親」ビュー(この場合はImageButton)の隣に「確認ボックス」DialogFragmentを配置することでした。

カスタムフラグメントの代わりにDialogFragmentを使用することを選択しました。これは、「ダイアログ」機能を無料で提供するためです(ユーザーが外側をクリックするとダイアログを閉じるなど)。

Example ConfirmBox
「ソース」ImageButtonの上にあるConfirmBoxの例(ゴミ箱)

/**
 * A custom DialogFragment that is positioned above given "source" component.
 *
 * @author Jonik, https://stackoverflow.com/a/20419231/56285
 */
public class ConfirmBox extends DialogFragment {
    private View source;

    public ConfirmBox() {
    }

    public ConfirmBox(View source) {
        this.source = source;            
    }

    public static ConfirmBox newInstance(View source) {
        return new ConfirmBox(source);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setStyle(STYLE_NO_FRAME, R.style.Dialog);
    }


    @Override
    public void onStart() {
        super.onStart();

        // Less dimmed background; see https://stackoverflow.com/q/13822842/56285
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.dimAmount = 0.2f; // dim only a little bit
        window.setAttributes(params);

        // Transparent background; see https://stackoverflow.com/q/15007272/56285
        // (Needed to make dialog's alpha shadow look good)
        window.setBackgroundDrawableResource(Android.R.color.transparent);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Put your dialog layout in R.layout.view_confirm_box
        View view = inflater.inflate(R.layout.view_confirm_box, container, false);

        // Initialise what you need; set e.g. button texts and listeners, etc.

        // ...

        setDialogPosition();

        return view;
    }

    /**
     * Try to position this dialog next to "source" view
     */
    private void setDialogPosition() {
        if (source == null) {
            return; // Leave the dialog in default position
        }

        // Find out location of source component on screen
        // see https://stackoverflow.com/a/6798093/56285
        int[] location = new int[2];
        source.getLocationOnScreen(location);
        int sourceX = location[0];
        int sourceY = location[1];

        Window window = getDialog().getWindow();

        // set "Origin" to top left corner
        window.setGravity(Gravity.TOP|Gravity.LEFT);

        WindowManager.LayoutParams params = window.getAttributes();

        // Just an example; edit to suit your needs.
        params.x = sourceX - dpToPx(110); // about half of confirm button size left of source view
        params.y = sourceY - dpToPx(80); // above source view

        window.setAttributes(params);
    }

    public int dpToPx(float valueInDp) {
        DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
    }
}

必要に応じてコンストラクターのパラメーターまたはセッターを追加することにより、上記をより一般的に使用するのは非常に簡単です。 (私の最後のConfirmBoxには、テキストとView.OnClickListenerはコードでカスタマイズできます。)

79
Jonik

次のように、DialogFragmentのonResume()メソッドをオーバーライドする必要があります。

@Override
public void onResume() {
    final Window dialogWindow = getDialog().getWindow();
    WindowManager.LayoutParams lp = dialogWindow.getAttributes();
    lp.x = 100;        // set your X position here
    lp.y = 200;        // set your Y position here
    dialogWindow.setAttributes(lp);

    super.onResume();
}

getDialog().getWindow()DialogFragmentに対して機能しません。これは、getWindow()がホスティングアクティビティが表示されない場合はnullを返すためです。ベースのアプリ。 getAttributes()を試みると、NullPointerExceptionを取得します。

Mobistryの答えをお勧めします。 DialogFragmentクラスが既にある場合、切り替えるのはそれほど難しくありません。 onCreateDialogメソッドを、PopupWindowを構築して返すメソッドに置き換えてください。その後、AlertDialog.builder.setView()に提供するビューを再利用し、(PopupWindow object).showAtLocation()

4
Austin B

ビューの場所とサイズを指定できるため、この目的でPopupWindowクラスを使用しています。

3
Sileria

Android.support.v7.app.AppCompatDialogFragmentからAppCompatDialogFragmentを使用していますが、ダイアログのフラグメントを画面の下部に揃えて、すべての境界線も削除します。特に、コンテンツの幅を親に合わせて設定する必要があります。

だから、私はこれから欲しかった(黄色の背景はダイアログフラグメントのrootLayoutから来る):

src_img_1

これを取れ:

src_img_2

上記のソリューションはいずれも機能しませんでした。だから、私はこれをどうにかして:

fun AppCompatDialogFragment.alignToBottom() {
    dialog.window.apply {
        setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
        decorView.apply {

            // Get screen width
            val displayMetrics = DisplayMetrics().apply {
                windowManager.defaultDisplay.getMetrics(this)
            }

            setBackgroundColor(Color.WHITE) // I don't know why it is required, without it background of rootView is ignored (is transparent even if set in xml/runtime)
            minimumWidth = displayMetrics.widthPixels
            setPadding(0, 0, 0, 0)
            layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
            invalidate()
        }
    }
}
1
Cililing
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(mActivity, R.style.BottomDialog);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // 
    dialog.setContentView(R.layout.layout_video_live);
    dialog.setCanceledOnTouchOutside(true);

    Window window = dialog.getWindow();
    assert window != null;
    WindowManager.LayoutParams lp = window.getAttributes();
    lp.gravity = Gravity.BOTTOM; //psotion
    lp.width = WindowManager.LayoutParams.MATCH_PARENT; // fuill screen
    lp.height = 280;
    window.setAttributes(lp);
    return dialog;
}
1
Ven Ren