Met4licのあけくれ帖

日常とか、勉強したこととかいろいろ書いていくつもりのブログです

Androidのつまづき「DialogFragmentの横幅が反映されない」

発端

今回はDialogFragmentの横幅がlayout.xmlで指定しても変わらないので、なんでだろ~と思って調べてみました。
参考サイト↓
Y.A.M の 雑記帳: Android DialogFragment では Dialog のサイズ指定は onActivityCreated でやれ
画面の解像度やdensity(ピクセル密度)の取得方法 | Android Techfirm Lab
今回は上の二つのサイトを参考にさせていただきました。

問題のコード

layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:orientation="vertical">

    <!-- ここにその他のViewを配置 -->

</LinearLayout>

というような感じで、rootViewにwidthを指定しているものの表示されるのが300dpよりも全然小さい。。。
なぜかなぁと思って調べていたら出てきたのがこちらの記事。
Y.A.M の 雑記帳: Android DialogFragment では Dialog のサイズ指定は onActivityCreated でやれ
こちらによると、どうやらsetContentView内でLayoutParamsにWRAP_CONTENTを内部的に設定しているらしい。
そして丁寧にその対処法も書いてくれていて大助かり。対処としては、

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

    Dialog dialog = getDialog();

    /* LayoutParamsを取得する */
    WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();

    /* DisplayMetrics を用いてDisplay上の大きさ(?)を取得し、layoutParamsに設定する処理(省略) */

    /* LayoutParamsをセット */
    dialog.getWindow().setAttributes(layoutParams)

}

というような感じのようです。

んでもって、ここだけの情報だとPixelでの指定方法が書かれているだけだったので、併せてdpでの指定に関する記事を探したところ
画面の解像度やdensity(ピクセル密度)の取得方法 | Android Techfirm Lab
こちらの記事を見つけました。
どうやらAndroidの中での「dp」の倍率は以下のコードで取得できるようです。

    DisplayMetrics metrics = new DisplayMetrics();
    context.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    /* metrics.scaledDensity でとれるのがdpの倍率*/

取得できるのは倍率なので、これをきちんと大きさに変換してやる必要があります。
(具体的には、「設定したい大きさ * metrics.scaledDensity」で変換する。注意点としては型はfloatであること。)

これらを踏まえて修正したコードがこちら

修正後のコード

↓ layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:gravity="center"
        android:text="posting"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/editText"
        android:layout_margin="10dp"
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:hint="describe contents"/>

    <Button
        android:id="@+id/postBtn"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="send"
        android:textSize="20sp"/>
</LinearLayout>

↓ myDialogFragment

import android.app.Dialog;
import android.content.Context;
import android.media.Image;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import my.com.myAppName.R;

public class myDialogFragment extends DialogFragment {

    public myDialogFragment() {
        // Required empty public constructor
    }

    private EditText editText;


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

    /**
     * LayoutParamsを操作し、横幅を適用
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        Dialog dialog = getDialog();

        //AttributeからLayoutParamsを求める
        WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();

        //display metricsでdpのもと(?)を作る
        DisplayMetrics metrics = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);

        //LayoutParamsにdpを計算して適用(今回は横幅300dp)(※metrics.scaledDensityの返り値はfloat)
        float dialogWidth = 300 * metrics.scaledDensity;
        layoutParams.width = (int)dialogWidth;

        //LayoutParamsをセットする
        dialog.getWindow().setAttributes(layoutParams);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.layout, container, false);
        postText = (EditText)view.findViewById(R.id.editText);
        Button postBtn = (Button)view.findViewById(R.id.postBtn);
        postBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(),editText.getText(),Toast.LENGTH_SHORT).show();
                dismiss();
            }
        });
        return view;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState){
        Dialog dialog = new Dialog(getActivity());
        //TITLE部分のないdialogの生成
        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);

        return dialog;
    }

}

今回はこんなもんで、終わります。