Dependency
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
Activity Layout
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carousel_recycler_view"
app:layoutManager="com.google.android.material.carousel.CarouselLayoutManager"
android:layout_width="match_parent"
tools:listitem="@layout/carousel_layout"
android:background="@drawable/rounded_corners"
android:layout_height="140dp"
android:layout_gravity="center"
android:clipChildren="false"
android:clipToPadding="false" />
carousel_layout.xml
<com.google.android.material.carousel.MaskableFrameLayout 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:id="@+id/carousel_item_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/_5sdp"
android:layout_marginTop="@dimen/_5sdp"
android:layout_marginEnd="@dimen/_5sdp"
android:layout_marginBottom="@dimen/_5sdp"
android:foreground="?attr/selectableItemBackground"
app:shapeAppearance="?attr/shapeAppearanceCornerExtraLarge">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/carousel_image_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="TODO"
android:scaleType="centerCrop"
android:src="@drawable/new_bannerr"
android:clipToOutline="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/close_btn"
android:layout_width="@dimen/_30sdp"
android:layout_height="@dimen/_30sdp"
android:layout_marginEnd="10dp"
android:contentDescription="TODO"
android:padding="8dp"
android:src="@drawable/close_for_edit_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/carousel_image_view"
app:tint="@color/color_red" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.carousel.MaskableFrameLayout>
CarouselAdapter
class CarouselAdapter(
private val imageList: ArrayList<Uri>,
val context: Context,
private val onListEmptyCallback: () -> Unit
) :
RecyclerView.Adapter<CarouselAdapter.ItemViewHolder>() {
inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: PhotoView = itemView.findViewById(R.id.carousel_image_view)
val carouselItemCounter: MaskableFrameLayout =
itemView.findViewById(R.id.carousel_item_container)
val deleteButton: ImageView = itemView.findViewById(R.id.close_btn)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): CarouselAdapter.ItemViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.carousel_layout, parent, false)
return ItemViewHolder(view)
}
@SuppressLint("RestrictedApi")
override fun onBindViewHolder(holder: CarouselAdapter.ItemViewHolder, position: Int) {
holder.imageView.load(imageList[position])
holder.carouselItemCounter.setOnMaskChangedListener { maskRect ->
// Any custom motion to run when mask size changes
holder.deleteButton.translationX = maskRect.left
holder.deleteButton.setAlpha(lerp(1F, 0F, 0F, 80F, maskRect.left))
}
// Handle delete button click
holder.deleteButton.setOnClickListener {
removeImage(position)
}
// Initialize the adapter with the image click callback
holder.imageView.setOnClickListener {
showImagePopup(imageList[position])
}
}
// Function to remove the image from the list
private fun removeImage(position: Int) {
imageList.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, imageList.size) // Update adapter to refresh the layout
// Check if list is empty and trigger the callback
if (imageList.isEmpty()) {
onListEmptyCallback.invoke()
}
}
// Function to show the image in a popup dialog
private fun showImagePopup(imageUri: Uri) {
// Create an ImageView dynamically
val imageView = PhotoView(context)
imageView.setImageURI(imageUri)
imageView.adjustViewBounds = true // Allow scaling of the image
// Create an AlertDialog to show the image
val dialog = AlertDialog.Builder(context)
.setView(imageView)
.setPositiveButton("Close") { dialog, _ ->
dialog.dismiss()
}
.create()
// Show the dialog
dialog.show()
dialog.window?.setDimAmount(0.5f)
}
override fun getItemCount() = imageList.size
}
Activity
private val imageList = ArrayList<Uri>()
private val carouselAdapter = CarouselAdapter(imageList, this) {
updateAdapter()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_medical_record)
setupRecyclerView()
updateAdapter()
}
private fun setupRecyclerView() {
carouselRecyclerView = findViewById(R.id.carousel_recycler_view)
carouselRecyclerView.setLayoutManager(CarouselLayoutManager())
carouselRecyclerView.adapter = carouselAdapter
// Initially show the empty view if the list is empty
if (imageList.isEmpty()) {
carouselRecyclerView.visibility = View.GONE
} else {
carouselRecyclerView.visibility = View.VISIBLE
}
}
private fun updateAdapter() {
carouselRecyclerView.visibility = View.VISIBLE
carouselAdapter.notifyDataSetChanged()
// the empty view if the list is empty
if (imageList.isEmpty()) {
carouselRecyclerView.visibility = View.GONE
} else {
carouselRecyclerView.visibility = View.VISIBLE
}
}
Top comments (0)