์ค๋์ ์๋๋ก์ด๋์์ ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ๊ธฐ ์ํด์ ์ฌ์ฉํ๋ Glide ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด์ ์ ๋ฆฌ๋ฅผ ํด๋ณด๋ ค๊ณ ํฉ๋๋ค. ์ ๋ ํ์ ์์ ๊ฐ๋ฐ์ ํ ๋์๋ ์ด๋ฏธ์ง์ ๊ด๋ จํ ์ฒ๋ฆฌ๋ Glide๋ฅผ ํตํด์ ๊ฐ๋ฐ์ ํด์์์ต๋๋ค.
์ Glide๋ฅผ ์ฌ์ฉํ๋๋๊ณ ํ๋ค๋ฉด “… ๋นจ๋ผ์…”๋ผ๊ณ ๋ฐ์ ๋ต์ ํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ๋ณดํต ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ ๋์๋ app์์ฒด์ drawable ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํด์ค๊ธฐ๋ ํ์ง๋ง ์๋ฒ ํน์ ์ธ๋ถ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ค๋ ๊ฒฝ์ฐ๊ฐ ๋๋ค์์ ๋๋ค. ๋ฐ๋ผ์ ๋น ๋ฅด๊ฒ ์ด๋ฏธ์ง ๋ก๋ ๊ธฐ๋ฅ์ ์ฒ๋ฆฌํ๊ณ ํธ๋ฆฌํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ฃผ๋ ๋ชฉ์ ์ ๋๋ค. ์ด๋ Glide์์ ์ง์ํ๋ ๋ค์ํ ๋ฉ์๋ ๋ฐ ํด๋์ค๋ค์ ์ด์ฉํ๋ฉด ์ ๋ง ์ฝ๊ฒ ๋ค์ํ ์ด๋ฏธ์ง ๋ก๋๋ฅผ ๊ตฌํํด๋ผ ์ ์์ต๋๋ค.
Glide ์ ์ฉ ๋ฐฉ๋ฒ
Module ์ build.gradle์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ข ์์ฑ ์ถ๊ฐ
- ํ์ฌ bumptech์ ๋ฐฐํฌ ๋ฒ์ ์ 4.14.2 ๋ฒ์ ์ด ์ต์ ๋ฒ์ ์ ๋๋ค.
- Glide Github Link : https://github.com/bumptech/glide
// Glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'com.github.bumptech.glide:annotations:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
ImageView์ Glide ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด Url๋ก Image๋ฅผ ์ ์ฉ
Glide.with(albumThumbnail)
.load(items.contentUri)
.into(albumThumbnail)
id=”@+id/albumThumbnail”์ ๊ฐ์ง ImageView์ items.contentUri์ ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.
์ ๋ง ๊ฐ๋จํ์ง ์๋์? ์ด๋ค ๊ณณ์ ์ด๋ค ์ด๋ฏธ์ง๋ฅผ ๋ฑ๋กํ๋ค! ์ด๊ฒ ์ฌ์ค ๋์ ๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ๋ง ์ฌ์ฉํ๋ค๋ฉด ๊ตณ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์๊ฒ ์ฃ . ๋ ๋ง์ ๊ธฐ๋ฅ์ ํธํ๊ฒ ์ฌ์ฉํ ์ ์์ด์ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์๋ฏธ๊ฐ ์์ต๋๋ค.
Glide.with()
.load()
.transform()
/*
.centerCrop()
.centerInside()
.circleCrop()
.fitCenter()
.rotate()
.roundedCorners()
*/
.placeholder()
.error()
.fallback()
.thumbnail()
.into()
์์ ๋ฉ์๋๋ค๋ก ๊ธฐ๋ณธ์ ์ธ ์ด๋ฏธ์ง์ ๋ํ ์ฒ๋ฆฌ๋ ๋๋ถ๋ถ ํด์ค ์ ์์ต๋๋ค.
- with() : Activity, Fragment์ context๋ฅผ ๋ฑ๋ก
- load() : ์ด๋ฏธ์ง ๋ก๋ (๋ค์ํ ๋ฐฉ์์ ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ ์ ์์)
- into() : ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ View๋ฅผ ๋ฑ๋ก
- transform() : ์ด๋ฏธ์ง๋ฅผ ๋ณํํ์ฌ View์ ํ์ (๋ค์ํ ๋ณํ ๊ด๋ จ ๋ฉ์๋ ์ฌ์ฉ)
- placeholder() : ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ๊ธฐ ์ ์ ๋ณด์ฌ์ค ์์ ์ด๋ฏธ์ง ๋ฑ๋ก
- error() : ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ๋ ๊ณผ์ ์์ error๊ฐ ๋ฐ์ํ์ ๋, ๋ณด์ฌ์ค ์ด๋ฏธ์ง ๋ฑ๋ก
- fallback() : ๋ก๋ํ ์ด๋ฏธ์ง๊ฐ null์ผ๋, ๋ณด์ฌ์ค ์ด๋ฏธ์ง ๋ฑ๋ก
- thumbnail() : ์ด๋ฏธ์ง์ thumbnail์ ์์ฑ (ํด์๋๊ฐ ํฐ ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ ๋ก๋ ์๋ ๊ฐ์ ์ ์ํด thumbnail๋ก ์ผ์ ์ด๋ฏธ์ง์ ํด์๋๋ฅผ ๋ฎ์ถ์ด ๋ ธ์ถํ ์ ์๋๋ก ํจ.)
์์ ์ฝ๋๋ฅผ ํตํด์ ์ถ๊ฐ์ ์ผ๋ก ์ค๋ช ์ ๋ํด๋ณด์๋ฉด ์ ์ด๋ฏธ์ง๋ฅผ ์์ธํ ๋ณด์๋ฉด ์์ชฝ์ radius์ฒ๋ฆฌ๊ฐ ๋ ๊ฒ์ ํ์ธํ ์ ์๋๋ฐ ํด๋น ๋ด์ฉ์ ์ด๋ป๊ฒ ๊ตฌํํ์๋์ง ์ฝ๋๋ฅผ ํตํด์ ํจ๊ป ์ค๋ช ํด๋ณด๊ฒ ์ต๋๋ค.
- ๋๋ฐ์ด์ค์ ์ด๋ฏธ์ง, ๋์์์ ์ฝ์ด์ ์ ์ฅ ํด๋๋ณ ๋ฆฌ์คํธ๋ฅผ ๊ตฌํ.
- ํด๋ ๋ช , ํด๋ ๋ณ ์ด๋ฏธ์ง ๊ฐ์, ํด๋์ ์ฒซ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ์ธ๋ค์ผ์ ์์ดํ ์ผ๋ก ๊ตฌ์ฑํ์ฌ ๋ ธ์ถ.
์ถ๊ฐ์ ์ผ๋ก ์ธ๋ถ ์๋ฒ๋ฅผ ํตํ ์ด๋ฏธ์ง ๋ก๋ ๊ณผ์ ์ด ์๋๊ธฐ ๋๋ฌธ์ ๋ก๋ ์๊ฐ ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ๋ ๋ฐ๋ก ํด์ฃผ์ง ์๊ณ ๋ก๋ํ๋ ๊ณผ์ ๋ง ๊ตฌํํ์์ต๋๋ค.
์ด๋ฏธ์ง ๋ผ์ด๋ฉ ์ฒ๋ฆฌ๋ฅผ ์ํ ์์ ์ฝ๋
fragment_main.xml ์์ RecyclerView๋ฅผ ํํํ๊ธฐ ์ํด include ํ์ฌ ํด๋น xml์ ๋ก๋ํ์์ต๋๋ค.
<include
android:id="@+id/folder_content"
layout="@layout/folder_content_scrolling"/>
folder_content_scrolling.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
MainFragment ์ฝ๋์์ RecyclerView์ ๋ํ ์ค์ ์ ํ๋๋ก ํฉ๋๋ค.
val gridLayoutManager = GridLayoutManager(requireContext(), 2)
binding.folderContent.recyclerView.apply {
layoutManager = gridLayoutManager
adapter = mainAdapter
}
- GridLayoutManager๋ฅผ ์ด์ฉํ์ฌ 2์ด์ ๊ฐ์ง๋ RecylerView๋ฅผ ์ ์ฉํฉ๋๋ค. mvvm, databinding์ ์ ์ฉ์ผ๋ก folderContent(RecyclerView)์ ๋ํ ๊ธฐ๋ณธ ์ค์ ์ ์ ์ฉํฉ๋๋ค.
MainFragment์์ mainAdapter์ ๊ดํ ์ด๋ฒคํธ๋ค์ ๋ฐ์ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ ๊ตฌ์ฑํฉ๋๋ค.
private val mainAdapter by lazy {
MainAdapter { itemClick ->
val action = MainFragmentDirections.actionMainFragmentToDetailFragment()
findNavController().navigate(action)
viewModel.setSelectedFolder(itemClick)
}
}
- MainAdapter๋ฅผ mainAdapter์ ๊ตฌ์ฑํ๊ณ itemClick ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด RecyclerView์ ํด๋ฆญ ์ด๋ฒคํธ๋ฅผ ์ฐ๊ฒฐํ์ฌ ํด๋น ์์ดํ ์ ํด๋ฆญํ์ ๋ ์ด๋ค ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ง๋ฅผ MainFragment๋ด๋ถ์ ๊ตฌํํฉ๋๋ค.
- ์ ๋ Navigation์ฝ๋๋ฅผ ์ฐ๊ฒฐํ์ฌ ๋ค์ ํ์ด์ง๋ก ์ด๋ํ ์ ์๋๋ก ์ด๋ฒคํธ ์ฝ๋ฐฑ์ ๊ตฌํํ์์ต๋๋ค.
MainAdapter์ ๊ตฌ์ฑํ์ฌ RecyclerView์ ์์ดํ ๋ค์ ์ฐ๊ฒฐํด์ค๋๋ค.
package com.seonhan_dev.imagepicker.ui.main
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners
import com.seonhan_dev.imagepicker.data.model.MediaStoreFolder
import com.seonhan_dev.imagepicker.databinding.ItemAlbumThumbBinding
class MainAdapter(private var itemClick: (MediaStoreFolder) -> Unit) :
ListAdapter<MediaStoreFolder, MainAdapter.ViewHolder> (MediaStoreFolder.DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemAlbumThumbBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
getItem(position)?.let {
holder.bind(it, holder)
}
}
inner class ViewHolder(private val binding: ItemAlbumThumbBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(items: MediaStoreFolder, holder: ViewHolder) {
with(binding) {
albumName.text = items.item
albumCount.text = items.count.toString() + " Images"
Glide.with(albumThumbnail)
.load(items.contentUri)
.transform(
CenterCrop(),
GranularRoundedCorners(27f, 27f, 0f, 0f)
)
.into(albumThumbnail)
}
itemView.setOnClickListener {
itemClick(items)
}
}
}
}
item_album_thumb.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/mainFragment_content_margin"
android:elevation="@dimen/mainFragment_content_elevation">
<ImageView
android:id="@+id/album_thumbnail"
android:layout_width="match_parent"
android:layout_height="@dimen/mainFragment_content_image_height"
android:scaleType="centerCrop"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/mainFragment_content_title_height"
android:background="@drawable/bottom_corner_radius">
<TextView
android:id="@+id/album_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginStart="8dp"
android:textSize="@dimen/content_title_text_size"
android:textColor="@color/colorTextDark"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/album_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_count_margin_bottom"
android:layout_marginStart="8dp"
android:textSize="@dimen/content_count_text_size"
android:textColor="@color/colorTextDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/album_name"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</layout>
- RecyclerView์ ๊ตฌํ์ ๊ดํ์ฌ ์์ธํ ๋ค๋ฃจ์ง๋ ์๊ณ Glide ๊ตฌํ๋ถ๋ฅผ ๋ ์์ธํ ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
- ๋๋ฐ์ด์ค์ ์ด๋ฏธ์ง ์ ๋ณด๋ MediaStoreFolder ๋ชจ๋ธ์ ์ ์ฅ๋์ด์์ต๋๋ค. ํด๋น ๋ชจ๋ธ์ items๋ก ๋ฐ์ ํ๋ฉด์ ๋ ธ์ถํด์ผ ํ ์ ๋ณด๋ค์ ๋ฑ๋กํฉ๋๋ค.
- ์ ๋ ์ด๋ ์ด๋ฏธ์ง์ ์๋ถ๋ถ์ radius์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ transform() ํจ์๋ฅผ ์ด์ฉํ์ฌ CenterCrop(), GranularRoundedCorners(27f, 27f, 0f, 0f)์ ๋ด์ฉ์ ๋ฑ๋กํ์์ต๋๋ค.
- GranularRoundedCorners ๋ฉ์๋๋ Glide์ public final class GranularRoundedCorners extends BitmapTransformation๋ก ๊ตฌํ๋์ด์๋ ๋ด์ฉ์ ๋๋ค.
private final float topLeft;
private final float topRight;
private final float bottomRight;
private final float bottomLeft;
/** Provide the radii to round the corners of the bitmap. */
public GranularRoundedCorners(
float topLeft, float topRight, float bottomRight, float bottomLeft) {
this.topLeft = topLeft;
this.topRight = topRight;
this.bottomRight = bottomRight;
this.bottomLeft = bottomLeft;
}
์ด๋ฐ ๊ณผ์ ๋ค์ ํตํ์ฌ ๊ฐ๋จํ๊ฒ ํด๋น ์์ ์ด๋ฏธ์ง์ ๊ฐ์ ๋ด์ฉ์ ๊ตฌ์ฑํ ์ ์์์ต๋๋ค.
์์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ฝ๊ณ ๊ฐ๋จํ๊ฒ Glide ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ํ์ํ ๊ณณ์ ์ ์ฉํด๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.

'๐ป ๊ฐ๋ฐ์ ์ด์ผ๊ธฐ > ์๋๋ก์ด๋ ์ฝ์ง๊ธฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Kotlin์ Coroutine, ์ฝ๋ฃจํด #1 (0) | 2023.01.31 |
---|---|
Navigation, ์์ฃผ ๊ฐ๋จํ๊ฒ Fragment๊ฐ์ ์ ํ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ. (0) | 2022.10.20 |
[Android Build Issue] : [hilt] (2) | 2022.10.19 |
DI(์์กด์ฑ ์ฃผ์ )์ ๋ฌด์์ธ๊ฐ? ๊ทธ๋ฆฌ๊ณ Koin DI๋ฅผ ์ ์ฉํ๋ ๊ณผ์ (0) | 2022.09.14 |
MVVM์ ๋ํ์ฌ, ๊ทธ๋ฆฌ๊ณ ๊ฐ๋จํ ์ํ์ฝ๋๋ฅผ ๋ง๋ค์ด๋ณด๊ธฐ (0) | 2022.08.31 |