와챠의 우당탕탕 코딩 일기장
[Android/Kotlin]사진 최대 선택 개수 제한하기/limit the number of selected photo 본문
코딩 일기장/Android(Kotlin)
[Android/Kotlin]사진 최대 선택 개수 제한하기/limit the number of selected photo
minWachya 2022. 2. 27. 16:30반응형
아래 화면은 "동네 고영희" 앱 UI입니다^____^
결과 화면
구현한 기능
- 갤러리에서 사진 선택(사진 선택 시 최대 선택 개수 지정)
- 사진 재선택 시 이전에 선택한 사진 보이기
- 갤러리에서 사진 선택 시 확대된 사진 보이기
- 선택된 사진 개수 실시간으로 보이기
1. 라이브러리 gradle에 추가
사진 개수 제한을 위한 fishbun과
이미지 로드를 위한 gilde 라이브러리를 다운받아준다.
최신 버전 확인: https://github.com/sangcomz/FishBun
dependencies {
implementation 'io.github.sangcomz:fishbun:1.0.0-beta01' // limit photo count
implementation 'com.github.bumptech.glide:glide:4.12.0' // glide
}
2. Manifest에 권한 추가
갤러리에 들어가야하니까... 관련 권한이 필요하다.
<!--사용자 갤러리에서 사진 가져오기-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
그리고 아래 코드도 application 태그 밖에 써준다.
<!--사용자 갤러리에서 사진 가져오기-->
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
3. 코드 작성
3-1. fragment_cat_add3.xml: 사진이 보일 xml
<!--사진 선택 레이아웃-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layoutSelectPhoto"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginTop="16dp"
android:layout_marginStart="20dp"
android:background="@drawable/layout_border_round"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textPic">
<ImageView
android:id="@+id/imageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvSlash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:text="@string/cat_add_picture_slash"
android:textColor="@color/beige_E3DECF"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<TextView
android:id="@+id/tvSelectCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:text="@string/cat_add_picture_select_count"
android:textColor="@color/yellow_F1BC35"
android:textSize="10sp"
app:layout_constraintEnd_toStartOf="@+id/tvSlash"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:text="@string/cat_add_picture_max_count"
android:textColor="@color/beige_E3DECF"
android:textSize="10sp"
app:layout_constraintStart_toEndOf="@+id/tvSlash"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcPhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="@+id/layoutSelectPhoto"
app:layout_constraintStart_toEndOf="@+id/layoutSelectPhoto"
app:layout_constraintTop_toTopOf="@+id/layoutSelectPhoto" />
3-2. list_item_cat_add_photo.xml: 리사이클러뷰 아이템 xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="72dp"
android:layout_height="72dp"
app:cardCornerRadius="4dp"
android:layout_marginEnd="4dp">
<ImageView
android:id="@+id/imgCatAddPhoto"
android:layout_width="72dp"
android:layout_height="72dp"
/>
<ImageView
android:id="@+id/imgCatAddClose"
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/btn_close_round"
android:src="@drawable/ic_btn_close"
android:layout_margin="8dp"
android:layout_gravity="right"/>
</androidx.cardview.widget.CardView>
4. Adapter 생성
앱 UI를 보니 사진 선택된 갯수를 보여주고/삭제될 때도 그 갯수가 바로 반영되어야 할 거 같았다.
그래서 CatAddFragment3.kt(fragment_cat_add3.xml)의 뷰를 CatAddPhotoAdapter(list_item_cat_add_photo.xml)에서 수정해야하는 상황이 발생했다.
해결 방법으로는
1, CatAddFragment3.kt 안에 CatAddPhotoAdapter를 코드를 작성하는 방법도 있고
2, CatAddPhotoAdapter에 CatAddFragment3의 뷰바인딩을 넘겨주는 방법도 있었다.
나는 클래스 너무 길어지는 게 싫어서 2번을 택했다!
CatAddPhotoAdapter.kt
설명은 주석에 ㅎ.ㅎ
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.example.dongnaegoyang.R
import com.example.dongnaegoyang.databinding.FragmentCatAdd3Binding
// 고양이 추가 페이지-3단계: 사진 어댑터
class CatAddPhotoAdapter(val binding: FragmentCatAdd3Binding) : RecyclerView.Adapter<CatAddPhotoAdapter.ViewHolder>() {
var imgUris = ArrayList<Uri>() // Uri 배열
// 뷰홀더 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CatAddPhotoAdapter.ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item_cat_add_photo, parent, false)
return ViewHolder(itemView)
}
// position 번째 아이템 설정하기
override fun onBindViewHolder(holder: CatAddPhotoAdapter.ViewHolder, position: Int) {
val uri = imgUris[position]
holder.setItem(uri)
}
// 아이템 갯수 리턴
override fun getItemCount() = imgUris.size
// 아이템 삭제
fun removeData(position: Int) {
// 아이템 삭제
imgUris.removeAt(position)
notifyItemRemoved(position)
// 현재 선택된 사진 개수 변경
binding.tvSelectCount.text = itemCount.toString()
}
// 사진 로드하기
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setItem(url: Uri) {
// 이미지 로드
Glide.with(itemView)
.load(url)
.error(R.drawable.ic_launcher_background) // 오류 시 이미지
.apply(RequestOptions().centerCrop())
.into(itemView.findViewById(R.id.imgCatAddPhoto))
// 삭제 버튼
itemView.findViewById<ImageView>(R.id.imgCatAddClose).setOnClickListener {
removeData(this.layoutPosition)
}
}
}
}
5. 실행 코드 작성
CatAddFragment3.kt
private const val TAG = "mmmCatAddFragment3"
private var _binding: FragmentCatAdd3Binding? = null
private val binding get() = _binding!!
// 고양이 추가: 3단계 프레그먼드
class CatAddFragment3 : Fragment() {
private lateinit var photoAdapter: CatAddPhotoAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentCatAdd3Binding.inflate(inflater, container, false)
val view = binding.root
// 사진 어댑터 설정
photoAdapter = CatAddPhotoAdapter(binding)
binding.rcPhoto.adapter = photoAdapter
setSelectPhoto() // 사진 선택 설정
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
// 사진 선택 설정
private fun setSelectPhoto() {
// 사진 설정 부분
val photoResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
if (data != null) {
// 이전 데이터 삭제
photoAdapter.imgUris.clear()
// 새 데이터 저장
val photoUriArr = data.getParcelableArrayListExtra<Uri>(INTENT_PATH)!!
for (uri in photoUriArr) photoAdapter.imgUris.add(uri)
photoAdapter.notifyDataSetChanged()
}
// 사진 갯수
binding.tvSelectCount.text = photoAdapter.itemCount.toString()
}
}
binding.layoutSelectPhoto.setOnClickListener {
FishBun.with(this@CatAddFragment3)
.setImageAdapter(GlideAdapter())
.setIsUseDetailView(true) // 상세 사진 보기 true
.setMaxCount(6) // 최대 사진 개수
.setSelectedImages(photoAdapter.imgUris) // 이전에 선택했던 사진 uri 배열
.setActionBarColor(Color.parseColor("#473A22"), Color.parseColor("#5D4037"), false)
.setActionBarTitleColor(Color.parseColor("#ffffff"))
.startAlbumWithActivityResultCallback(photoResultLauncher)
}
}
}
다행히 라이브러리가 있었다~~ 다행~~ 생각보다 너무 편하게 기능 구현이 가능해서 놀랐다.
짱...!!!!!!
반응형
'코딩 일기장 > Android(Kotlin)' 카테고리의 다른 글
[Android/Kotlin] TabLayout: unselected tab indicator/미선택된 탭의 이터레이터 색 설정/탭 밑줄/tab underline (0) | 2022.03.19 |
---|---|
[Android/Kotlin] FragmentContainerView 연습 Code with Joyce (0) | 2022.03.05 |
[Android/Kotlin]Custom Dialog (0) | 2022.02.26 |
[Android/Kotlin]BottomSheetDialog/round corner/아래에 뜨는 다이얼로그로 선택하는 스피너 (0) | 2022.02.19 |
[Android/Kotlin]Spinner hint/Spinner underline (0) | 2022.02.18 |
Comments