4

I've made a construction in Android to easy build & show a DialogFragment on the screen. The dialog contains a TextView, ListView and a Button. It's build to easily inflate different views in the ListView so I can make custom Dialogs.

Example: enter image description here

The left image is correct. On the right I inflated an extra view. A view I use to display text in the DialogFragment. But when I add that view it doesn't wrap content anymore. The ListView makes itself scrollable.

I can add more of the bluebuttons you see on the image and the ListView will still wrap_content correct. But when I add one or more of the other views it the ListView makes itself scrollable.

The problem is I just can't get the ListView to wrap_content correct.

This is the xml of the "blue button" view: (the correct inflated view)

 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/overlay_item_label"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_weight="1"
     android:orientation="vertical"
     android:weightSum="1">

     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@drawable/tile_button_categorytile"
         android:orientation="horizontal">

         <ImageView
             android:id="@+id/popUpImage"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_margin="6dp"
             android:scaleType="fitCenter"
             android:src="@drawable/ic_speaker" />

        <com.joanzapata.iconify.widget.IconTextView
             android:id="@+id/popUpButton"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="center"
             android:layout_margin="4dp"
             android:layout_marginRight="15dp"
             android:layout_weight="1"
             android:padding="4dp"
             android:text="Bewerken {fa-android}"
             android:textColor="@color/white"
             android:textSize="14sp"
             android:textStyle="bold" />
    </LinearLayout>
</LinearLayout>

The view used as text in the DialogFragment: (which causes the ListView to make itself scrollable)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/overlay_item_label"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"

    android:background="@color/white"
    android:layout_weight="1"
    android:weightSum="1">

        <TextView
            android:id="@+id/LabelOverlay"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:gravity="center"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:text="@string/placeholder"
            android:textColor="@color/purple"
            android:textSize="12sp" />
</LinearLayout>

When I add extra paddingTop and paddingBottom to the view that is used to show text, the ListView doesn't make itself scrollable (on only a few devices). The padding is set to around 20dp and then it on some devices it doesn't make itself scrollable, but then on other devices its too much padding so it shows whitespace...

This is the code of the fragment that shows the DialogFragment:

public class PopUpFragmentPhone extends DialogFragment {
    PopUp popUpData;
    ListView listView;

    public static PopUpFragmentPhone newInstance(PopUp data) {
        PopUpFragmentPhone popUpFragment = new PopUpFragmentPhone();

        Bundle args = new Bundle();
        args.putParcelable("PopUpData", data);
        popUpFragment.setArguments(args);
        return popUpFragment;
    }

    @Override
    public void onStart(){
        super.onStart();
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams windowParams = window.getAttributes();
        windowParams.dimAmount = 0.70f;

        windowParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
        window.setAttributes(windowParams);

        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        getDialog().getWindow().setLayout(MainApplication.width / 2, ViewGroup.LayoutParams.WRAP_CONTENT);
        getDialog().setCanceledOnTouchOutside(true);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme);
        popUpData = getArguments().getParcelable("PopUpData"); //get the PopUp class.
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.pop_up_phone, container, false);

        //Set the title of the popUp
        TextView popUpTitle = (TextView)v.findViewById(R.id.overlayTitle);
        popUpTitle.setText(popUpData.getHeader());

        listView = (ListView) v.findViewById(R.id.listViewItemsOverlay);
        listView.setAdapter(new PopUpAdapterPhone(MainApplication.getContext(), 1, popUpData.getItems(), this));

        boolean showCancel = popUpData.isCancel();
        Button cancelButton = (Button) v.findViewById(R.id.cancel_button);
        Drawable cancelIcon = new IconDrawable(getActivity(), FontAwesomeIcons.fa_times).colorRes(R.color.red).sizeDp(20);
        cancelButton.setCompoundDrawablesWithIntrinsicBounds(cancelIcon, null, null, null);
        if(showCancel) {
            // Cancel button click
            cancelButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    getDialog().dismiss();
                }
            });
        } else {
            cancelButton.setVisibility(View.GONE);
        }

        getDialog().getWindow().setLayout(MainApplication.width / 2, ViewGroup.LayoutParams.WRAP_CONTENT);//set the size of the fragment, so the rest is a touch to cancel the popUP

        return v;
    }
}

The view of the pop up fragment:

<?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:orientation="vertical"
      android:gravity="center"
      android:padding="5dp"
      android:weightSum="3"
      android:background="@drawable/tile_button_wordtile"
      android:id="@+id/overlay_master_view">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/menu"
            android:id="@+id/overlayTitle"
            android:textStyle="bold"
            android:textSize="15sp"
            android:padding="4dp"
            android:textColor="@color/purple"
            android:layout_weight="1"
            android:background="@color/white"
            android:layout_margin="4dp"
            android:layout_gravity="center_horizontal" />

       <ListView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none"
            android:layout_weight="1"
            android:divider="@android:color/transparent"
            android:dividerHeight="5.0sp"
            android:id="@+id/listViewItemsOverlay">

        </ListView>

        <com.joanzapata.iconify.widget.IconButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="start"
            android:padding="5dp"
            android:layout_weight="1"
            android:textStyle="bold"
            android:textSize="15sp"
            android:drawablePadding="5dp"
            android:id="@+id/cancel_button"
            android:layout_marginTop="5dp"
            android:textColor="@color/red"
            android:background="@drawable/tile_button_functiontile"
            android:text="@string/cancel"/>
 </LinearLayout>

I tried lots of things, inflate it in a LinearLayout or RelativeLayout. Wrap_content, match_parent, weightSum and all that kinds of stuff. Tried changing the layouts in a lot of ways but it all didn't work out.

I hope someone can help me.

476rick
  • 2,764
  • 4
  • 29
  • 49
  • Possible duplicate of [Android: wrap\_content is not working with ListView](https://stackoverflow.com/questions/11295080/android-wrap-content-is-not-working-with-listview) – Ben P. Nov 02 '17 at 22:44

1 Answers1

1

Note: In the code below, I've removed the backgrounds as I didn't have them.

But basically you shouldn't have to change it too much to match what you want.

Your dialog

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.WindowManager;
import android.widget.ListView;

import java.util.ArrayList;

public class CustomDialogFragment extends DialogFragment {

    private static final String DIALOG_DATA = "my.app.package.DIALOG_DATA";

    public static CustomDialogFragment newInstance(ArrayList<ListElement> data) {
        CustomDialogFragment f = new CustomDialogFragment();
        Bundle args = new Bundle();
        args.putParcelableArrayList(DIALOG_DATA, data);
        f.setArguments(args);

        return f;
    }

    @Override
    public void onResume() {
        super.onResume();
        // Calculate the height/width you want
        // See: https://stackoverflow.com/a/12923805/1827254 for more info
        // In this example, the width is not changed as retrieved from the LayoutParams of the dialog.

        WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
        int width = params.width; //getResources().getDimensionPixelSize(R.dimen.popup_width);
        int height = getResources().getDimensionPixelSize(R.dimen.popup_height);

        getDialog().getWindow().setLayout(width, height);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        ArrayList<ListElement> data = getArguments().getParcelableArrayList(DIALOG_DATA);

        // Inflate the dialog layout
        View view = View.inflate(getContext(), R.layout.custom_dialog, null);

        ListView listView = view.findViewById(R.id.dialog_list);
        listView.setAdapter(new CustomAdapter(getContext(), data));

        View btn = view.findViewById(R.id.dialog_cancel_button);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dismiss(); // Dismiss the dialog.
            }
        });

        return new AlertDialog.Builder(getActivity())
                .setView(view)
                .create();
    }
}

The dialog layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/overlay_master_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <!-- Title of the view -->

    <!-- Note: instead of using 'android:text="@string/placehoder"' use
         'tools:text="My preview text"'. Otherwise the system has to set your
         placeholder value and then replace it with the actual value you want in the code -->
    <TextView
        android:id="@+id/dialog_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:background="@color/white"
        android:padding="4dp"
        android:text="@string/menu"
        android:textColor="@color/purple"
        android:textSize="15sp"
        android:textStyle="bold"
        tools:text="Preview text" />

    <!-- The ListView needs to have a height of 0 in order to let
    the button to be displayed below it-->
    <ListView
        android:id="@+id/dialog_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:divider="@android:color/transparent"
        android:dividerHeight="5.0sp"
        android:scrollbars="none" />

    <!-- Button 'cancel'-->
    <com.joanzapata.iconify.widget.IconButton
        android:id="@+id/dialog_cancel_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:drawablePadding="5dp"
        android:gravity="start"
        android:padding="5dp"
        android:text="@string/cancel"
        android:textColor="@color/red"
        android:textSize="15sp"
        android:textStyle="bold" />
</LinearLayout>

The list adapter

 class CustomAdapter extends ArrayAdapter<ListElement> {
    private final LayoutInflater mInflater;

    public CustomAdapter(Context context, ArrayList<ListElement> data) {
        super(context, 0, data);
        mInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, @NonNull ViewGroup parent) {
        // Get the data item for this position
        ListElement element = getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        if (convertView == null) {
            // Use your custom layout
            convertView = mInflater.inflate(R.layout.list_element, parent, false);
        }

        // Get the views and set the data

        TextView tv = (TextView) convertView.findViewById(R.id.elt_text);
        tv.setText(element.getText());

        ImageView imageView = (ImageView) convertView.findViewById(R.id.elt_image);
        imageView.setImageResource(element.getIconRes());

        return convertView;
    }
}

List element layout

I think setting the weight to every component was one of your issues

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/overlay_item_label"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/blue"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/elt_image"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_margin="6dp"
        android:scaleType="fitCenter"
        tools:src="@mipmap/ic_launcher" />

    <com.joanzapata.iconify.widget.IconTextView
        android:id="@+id/elt_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="4dp"
        android:layout_marginRight="15dp"
        android:padding="4dp"
        android:textColor="@color/white"
        android:textSize="14sp"
        android:textStyle="bold"
        tools:text="Bewerken {fa-android}" />
</LinearLayout>

An element of the list

import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.DrawableRes;

/**
 * Every element of the list has an icon and a text.
 * You can add other parameters
 */

public class ListElement implements Parcelable {
    private String mText;
    @DrawableRes
    private Integer mIconRes;

    public ListElement() {
        // Default constructor
    }

    public ListElement(String text, @DrawableRes int resId) {
        this.mText = text;
        this.mIconRes = resId;
    }

    protected ListElement(Parcel in) {
        mText = in.readString();
        if (in.readByte() == 0) {
            mIconRes = null;
        } else {
            mIconRes = in.readInt();
        }
    }

    public static final Creator<ListElement> CREATOR = new Creator<ListElement>() {
        @Override
        public ListElement createFromParcel(Parcel in) {
            return new ListElement(in);
        }

        @Override
        public ListElement[] newArray(int size) {
            return new ListElement[size];
        }
    };

    public String getText() {
        return mText;
    }

    public Integer getIconRes() {
        return mIconRes;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(mText);
        if (mIconRes == null) {
            parcel.writeByte((byte) 0);
        } else {
            parcel.writeByte((byte) 1);
            parcel.writeInt(mIconRes);
        }
    }
}

Use case example (in MainActivity)

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();


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

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

        ArrayList<ListElement> data = generateData();

        // Create and show the dialog.
        DialogFragment newFragment = CustomDialogFragment.newInstance(data);
        newFragment.show(ft, "dialog");
    }

    private ArrayList<ListElement> generateData() {
        ArrayList<ListElement> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            list.add(new ListElement("elt " + i, R.mipmap.ic_launcher));
        }

        return list;
    }
}
Eselfar
  • 3,759
  • 3
  • 23
  • 43
  • To manage the title and the visibility of the cancel button, you can add extra parameters to the `newInstance` method of the DialogFragment and add them into the bundle. It'd probably be easier than having a big `PopUpData` object that needs to be parcelable – Eselfar Nov 02 '17 at 23:34
  • Thank you very much for your answer, I will try to implement this as soon as possible, but I think it will be Monday before I have enough time because it is a lot to change. – 476rick Nov 03 '17 at 19:12
  • 1
    It worked, I really want to thank you! I really couldn't figure the problem out. Thanks @Eselfar – 476rick Nov 08 '17 at 07:17