Challenge: Detail Display : Solution and Question

Hi guys,
After hours and hours of headache i find a solution to this Challenge, but unfortunatelly i still have a problem that i will present at the end, so lets begin:

1- Create a Layout file : “zoom_layout” containig two elements, an ImageView inside of a Linear Layout:

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android
android:layout_width=“wrap_content”
android:layout_height=“wrap_content” >

<ImageView
    android:id="@+id/zoom_image_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

</LinearLayout>

2- Create a DialogFragment where we will put the crime image: i called it ZoomDialogFragment.
i follow the same convention of using a companion object newInstance() function, and in this function i pass a photoFileName variable that contain the crime.photoFileName

class ZoomDialogFragment : DialogFragment() {

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val view = inflater.inflate(R.layout.zoom_layout, container, false)
         val imageView = view.findViewById(R.id.zoom_image_view) as ImageView 

    return view
}

companion object {
    fun newInstance(photoFileName: String): ZoomDialogFragment {
        val frag = ZoomDialogFragment()
        val args = Bundle()
        args.putSerializable("PHOTO_URI", photoFileName)
        frag.arguments = args
        return frag
    }
}

}

3- In CrimeFragment an ImageView Object, instanciate it in onCreate View, and in onStart() i setOnclickListener to it. in this listener i create a ZoomDialogFragment instance with the crime.photoFileName and i call i FragmentDialog.show(…) function

    photoView.setOnClickListener {

        val zoomDialog= ZoomDialogFragment.newInstance(crime.photoFileName)

        zoomDialog.show(fragmentManager,null)

    }

4- we did not finish with ZoomDialogFragment, because we need to display the photo there:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    val view = inflater.inflate(R.layout.zoom_layout, container, false)
    val imageView = view.findViewById(R.id.zoom_image_view) as ImageView

val photoFileName = arguments?.getSerializable(“PHOTO_URI”) as String

imageView.setImageBitmap(BitmapFactory.decodeFile(requireContext().filesDir.path + “/” + photoFileName))

    return view


}

The final result is shown in this picture:

But as you can see, there is two white bars above and bellow the image, i wonder if there is a way to display just the image!!
Let me know if you find a solution to this

2 Likes

Two things potentially:

  1. Your layouts are set to wrap_content instead of match_parent.

  2. It may be based on the aspect ratio/sizing of your image. Was the picture taken landscape and now you’re trying to display portrait? You’ll need to either stretch the image or zoom & crop. There was code that was scaling the image by taking the smaller of the two dimensions, that may still be in place.

Thank you Jeff for your reply, but infortunatelly i tried your sollutions but nothing happened
1- i set the layout and the ImageView to match_parent but in vain
2- i took another picture in landscape to see if there is any difference but nothing important, just the image height was reduced a little bit (because of the landscape mode)

Here is my solution using AlertDialog as it allow you to set buttons, themes … etc.

1- Create a Layout that contains imageView:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/crimePicture"
        android:layout_width="394dp"
        android:layout_height="510dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:scaleType="fitStart"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>

2- Create a PictureDialogFragment that implement DialogFragment

private const val ARG_IMAGE = "image"

class PictureDialogFragment: DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {


            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)

            //get the layout inflater
            val inflater = requireActivity().layoutInflater

            //get a dialog picture view reference
            // Pass null as the parent view because its going in the dialog layout
            val view = inflater.inflate(R.layout.dialog_picture, null)

            // Inflate and set the layout for the dialog
            builder.setView(view)

            //get reference to crimePicture image view
            val crimePicture = view.findViewById(R.id.crimePicture) as ImageView

            //get the image file path argument
            val photoFile = arguments?.getSerializable(ARG_IMAGE) as File

            //get the scaled image
            val bitmap = getScaledBitmap(photoFile.path, requireActivity())

            //set the picture in the crimePicture view
            crimePicture.setImageBitmap(bitmap)


            //set the dialog characteristics
            builder.setTitle(R.string.crime_photo)
                .setNegativeButton(R.string.Dismiss, DialogInterface.OnClickListener{ _, _ -> dialog?.cancel() } )


            // Create the AlertDialog object and return it
            builder.create()

        } ?: throw IllegalStateException("Acitivity cannot be null")

    }


    companion object {
        fun newInstance(photoFile: File): PictureDialogFragment {
            val args = Bundle().apply { putSerializable(ARG_IMAGE, photoFile) }

            return PictureDialogFragment().apply { arguments = args }

        }
    }
}

3- in CrimeFragment, implement setOnClickListener of the photoView

private const val DIALOG_PICTURE = "DialogePicture"

class CrimeFragment: Fragment(), DatePickerFragment.Callbacks, TimePickerFragment.Callbacks {

................


 override fun onStart() {
        super.onStart()
.......................

photoView.setOnClickListener{
            if (photoFile.exists())
            {
                PictureDialogFragment.newInstance(photoFile).apply { show(this@CrimeFragment.parentFragmentManager, DIALOG_PICTURE ) }
            }

        }

......................

This is the result:

1 Like

You need to add android:adjustViewBounds=“true” to ImageView inside your XML file

<?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"
                                                   xmlns:tools="http://schemas.android.com/tools"
                                                   android:layout_width="wrap_content"
                                                   android:layout_height="wrap_content"
                                                   android:layout_gravity="center">
    <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            tools:srcCompat="@tools:sample/avatars"
            android:id="@+id/crime_image"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:adjustViewBounds="true"
    />
</androidx.constraintlayout.widget.ConstraintLayout>
1 Like

Hi,
I don’t have reference to parentFragmentManager, how you did ?

Thanks

Put this xml, it should be nice :

<?xml version="1.0" encoding="utf-8"?>

<ImageView
android:id="@+id/zoom_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

That worked. Thanks!

Hello everyone,

I tried both ConstraintLayout and LinearLayout for my view object, but this is the result I am getting.

Does anyone know why is the image rotated and smaller than the actual size?

Thanks in advance.

I ended up fixing this after some trial and error.

Here is how it looks now:

Here is what my xml file for the image view looks like.

...
 <ImageView
        android:id="@+id/dialog_photo"
        android:layout_width="550dp"
        android:layout_height="550dp"
        android:adjustViewBounds="true"

        android:rotation="90"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="-1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0"
        tools:srcCompat="@tools:sample/avatars" />
...

I have set android:rotation=“90” because for some reason the images show up rotated.
I had tried both “match_parent” and “wrap_content” for the layout_height/layout_width, but that was the primary cause of the problem for some reason, making the images look shrunk. I didn’t want to hard code an exact number for the layout height and width, but it seems that there is no way around it.

Lastly, I set the bias to be -1 for the layout_constraintHorizonal_bias, because a value of 0 moves the image to the right.

If I remember correctly, I think you need to put this dependency in build.gradle
implementation ‘androidx.fragment:fragment-ktx:1.3.0’