Search code examples
javaandroidxmlmobiledialog

Recycler view layout width is weird when used inside AlertDialog with constraints layout


I'm trying to use recycler view in an AlertDialog.
I want the recycler view to occupy 100% of AlertDialog width.

I use this xml code

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools">

    <TextView
        android:id="@+id/TV_DownloadablesDialogTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="@string/file_downloads"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RV_DownloadablesDialogRecycler"
        android:layout_width="0dp"
        android:layout_height="250dp"
        android:layout_marginTop="12dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/TV_DownloadablesDialogTitle"
        tools:listitem="@layout/downloadables_dialog_item_view" />

</androidx.constraintlayout.widget.ConstraintLayout>

in android studio preview it looks like this
enter image description here

but at runtime it actually looks like this.

enter image description here

Notice how the TextView is responsive to the constraint layout but the RecyclerView isn't.

here is how I show the AlertDialog.

    private void showDownloadablesDialog(LinkedList<Downloadable> downloadableList) {
        View downloadablesDialogView = getLayoutInflater().inflate(R.layout.downloadables_dialog, null, false);
        RecyclerView downloadablesRecycler = downloadablesDialogView.findViewById(R.id.RV_DownloadablesDialogRecycler);
        DownloadablesDialogAdapter adapter = new DownloadablesDialogAdapter(this, downloadableList);
        downloadablesRecycler.setAdapter(adapter);
        downloadablesRecycler.setLayoutManager(new LinearLayoutManager(this));

        new AlertDialog.Builder(this)
                .setView(downloadablesDialogView)
                .setPositiveButton(R.string.ok, (dialogView, which) -> {
                })
                .create()
                .show();


    }

This previous code is executed inside the Activity class.

I tried changing android:layout_width to match_parent but I got the same results.

but When I set it to a fixed width it work but I don't want to use fixed width as it will not make the app responsive on different screen sizes.



EDIT: I noticed when I clicked on the Remove Button it fixed itself somehow.

here is the logic of the remove button inside onBindViewHolder() in the recycler adapter

        holder.BFileRemove.setOnClickListener((button) -> {
            Intent intent = new Intent(context, NetworkService.class);
            intent.setAction(NetworkService.ACTION_MODIFY_DOWNLOADABLE);
            intent.putExtra(NetworkService.EXTRA_MODIFY_TYPE, NetworkService.VALUE_MODIFY_DELETE);
            intent.putExtra(NetworkService.EXTRA_MODIFY_DELETE_UUID, downloadables.get(holder.downloadableIndex).uuid);
            downloadables.remove(holder.downloadableIndex);
            notifyItemRemoved(holder.downloadableIndex);
            context.startService(intent);
        });

enter image description here


Solution

  • It seems that the problem might be in initial layout calculation. Even though the RecyclerView's width is set to 0dp with constraints, allowing it to expand within the AlertDialog, the layout pass might not be considering these constraints correctly.

    Use below code to auto adjust the width of recycler view:

    private void showDownloadablesDialog(LinkedList<Downloadable> downloadableList) {
    View downloadablesDialogView = getLayoutInflater().inflate(R.layout.downloadables_dialog, null, false);
    RecyclerView downloadablesRecycler = downloadablesDialogView.findViewById(R.id.RV_DownloadablesDialogRecycler);
    DownloadablesDialogAdapter adapter = new DownloadablesDialogAdapter(this, downloadableList);
    downloadablesRecycler.setAdapter(adapter);
    downloadablesRecycler.setLayoutManager(new LinearLayoutManager(this));
    
    AlertDialog alertDialog = new AlertDialog.Builder(this)
            .setView(downloadablesDialogView)
            .setPositiveButton(R.string.ok, (dialogView, which) -> {})
            .create();
    
    alertDialog.setOnShowListener(dialogInterface -> {
        Window window = alertDialog.getWindow();
        if (window != null) {
            View decorView = window.getDecorView();
            decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    ViewGroup.LayoutParams layoutParams = downloadablesRecycler.getLayoutParams();
                    layoutParams.width = decorView.getWidth();
                    downloadablesRecycler.setLayoutParams(layoutParams);
                }
            });
        }
    });
    
    alertDialog.show();
    

    }