이번에는 게시글을 작성하고 작성한 게시글이 recyclerView를 통해 나타나게 하려고 한다.
생각한 게시글은 image 한 장과 게시글.
메인 화면에 floatingActionButton을 만들어주고 누르면 게시글을 작성하는 페이지로 넘어가는 것을 만들면
1) 메인 Fragment에 RecyclerView와 FloatingActionButton 추가
원하는 Fragment에 생성하면 된다.
코드
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/homeRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/writeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="30dp"
android:backgroundTint="@color/grey"
android:src="@drawable/icon_add"/>
2) 버튼을 눌렀을 때 나타날 Fragment 생성
원하는 이름의 Fragment와 layout 생성하시고 연결하면 된다.ㅇㅇ..
간단해서 생략
3) 지지난번에 만든 navigation을 활용해서 페이지 연결
모르겠으면 저어번에 올린 게시글 참고
4) Fragment 화면 이동
binding.writeButton.setOnClickListener {
val action = HomeFragmentDirections.actionHomeFragmentToWriteFragment()
findNavController().navigate(action)
}
저번에 설명을 작성했나 모르겠지만 다시 작성(?)하자면
2번 줄의 코드를 설명하자면
HomeFragmentDirections : navigation의 HomeFragment(내가 메인으로 둔 Fragment)
actionHomeFragmentToWriteFragment : action / HomeFragment / To / WriteFragment 이렇게 띄어서 읽어보면 편하다.
3번처럼 이어줬다면 navigation에 <action ...> 이런것이 생겼는데 그 action의 id를 가져온 것이다!
설명을 너무 못해서 제가 이해한거 이해하려하지말고 참고한 자료 보시길..
그냥 게시글을 작성하게 만드는 것은 안된다.
저번 글에서 인증된 사용자만 게시글에 권한이 있게 만들어 주었다.
그러면 조건문으로 auth에 인증된 사용자만 접근 가능하게 하려면
binding.writeButton.setOnClickListener {
if(Firebase.auth.currentUser != null){
val action = HomeFragmentDirections.actionHomeFragmentToWriteArticleFragment()
findNavController().navigate(action)
}
Snackbar.make(view,"로그인 후 사용해주세요.",Snackbar.LENGTH_SHORT).show()
}
if 조건문으로 Firebase.auth.currentUser가 null이 아니면 접근 가능하게 한다.
5) 갤러리에서 사진 가져오기
페이지 이동까지 마쳤으면 갤러리에 접근 허용과 사진을 선택했을 때 사진을 가져올 수 있어야한다.
밑에 공식문서를 읽고 가면 좋다.
5_0) UI 수정
사진을 눌렀을 때 가져올 수 있게 writeFragment layout 추가
사진 받을 부분은 ImageView로 받았다.
+ 버튼으로 이미지를 받고 x 버튼은 사진을 다시 지우는 버튼
개인 id 사항
선택된 이미지 띄우는 ImageView = selectedImageView
이미지 넣는 + 버튼 : plusImageButton
이미지 지우는 x 버튼 : clearImageButton
밑에 코드에서 찾으실까봐 필요한 부분 id만 올렸다.
나머지는 개인 취향껏
5_1) 갤러리 접근 허용
추가적으로 API 33이전의 API를 사용하면 위에 사진 맨 밑줄처럼 EXTERNAL_STORAGE도 함께 허용해야 한다.
밑에 사진 설명
위에 블로그 내용을 참고했습니다.
5_2) 사진 가져오기
위에 공식문서 밑에 좋은 도구가 있다.
위에처럼 나오게 사용할 것이다.
>>그냥 복붙
import해주니 빨간 부분은 사라졌다. ActivityResultContracts에서 가져오나보다.
import androidx.activity.result.contract.ActivityResultContracts
pickMedia 가져온 부분 밑에보면 '단일 미디어 항목 선택'과 '여러 미디어 항목 선택'이 있는데 사진 한장만 올릴 생각이라서 단일 미디어의 ImageOnly를 사용했다.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentWriteBinding.bind(view)
//추가
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
}
전체코드
package com.example.kotlin_sai.ui.article
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import com.example.kotlin_sai.R
import com.example.kotlin_sai.databinding.FragmentWriteBinding
class WriteFragment:Fragment(R.layout.fragment_write) {
private lateinit var binding:FragmentWriteBinding
val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
// Callback is invoked after the user selects a media item or closes the
// photo picker.
if (uri != null) {
Log.d("PhotoPicker", "Selected URI: $uri")
} else {
Log.d("PhotoPicker", "No media selected")
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentWriteBinding.bind(view)
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
}
이제 실행하면 끝
avd에 사진이 없어서 초록이 사진 찍어서 사진 추가했다.
앗 두장은 눈감았네
사진을 누르면
Logcat에 로그가 잘 찍힌다.
갤러리의 이미지를 눌렀을 때 uri가 잘 나온다는 뜻은 그 이미지uri 주소만 잘 연결시켜주면 쉽게 이미지를 가져올 수 있다는 뜻?!
먼저, uri를 저장할 변수를 생성한다.
import android.net.Uri
class WriteFragment
...생략
private val seletedUri: Uri? = null
위에서 생성한 pickMedia uri를 seletedUri로 변경
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) { //이미지가 선택되면 이미지uri가 null이 아님
//selectedImageView에 이미지 띄우기
selectedUri = uri //추가
binding.selectedImageView.setImageURI(uri)
}
이제 게시물을 올렸을 때가 필요하다.
binding.uploadTextView.setOnClickListener { //submitButton +버튼 눌렀을 때
if (selectedUri != null) {
val fileName = "${UUID.randomUUID()}.png"
Firebase.storage.reference.child("articles/photo").child(fileName)
.putFile(selectedUri ?: return@setOnClickListener)
.addOnCompleteListener{
if(it.isSuccessful){
Log.e("aa","success")
}else{
it.exception?.printStackTrace()
}
}
} else {
Snackbar.make(view, "이미지를 선택해주세요.", Snackbar.LENGTH_SHORT).show()
}
}
한 줄씩 분해
val fileName = "${UUID.randomUUID()}.png"
firebase의 storage에 생기는 id를 혹시라도 겹칠까봐 랜덤하게 생성해서 .png를 붙인채 저장한다.
Firebase.storage.reference.child("articles/photo").child(fileName)
이제 Firebase의 storage에 articles파일 아래 photo파일안에 위에 생성한 fileName을 올려준다.
.putFile(selectedUri ?: return@setOnClickListener)
null값의 예외처리
.addOnCompleteListener{
if(it.isSuccessful){
Log.e("upload","success!!!!")
}
}
올리는 것에 성공하게된다면 로그를 찍어보기위해 만듬
else {
Snackbar.make(view, "이미지를 선택해주세요.", Snackbar.LENGTH_SHORT).show()
}
이미지 값이 null 선택되지 않았다면 Snackbar 띄우기
Firebase의 Storage에 가보면 규칙에 체크한 부분이 false로 되어있다. 권한설정을 저번에 말했는데 로그인한 유저(인증한 유저)로 바꾸면 좋지만 일단 확인하기 위해 true로 바꾼다.
사진을 선택한 뒤 게시물 등록 버튼을 누르면
Storage에 잘 올라온다.
하지만 이제 시작이다..
올린 사진의 저장소 위치 상태가 ??
이렇게 되면 Android에서 주소를 받아오기 힘들다
binding.uploadTextView.setOnClickListener { //submitButton +버튼 눌렀을 때
if (selectedUri != null) {
val fileName = "${UUID.randomUUID()}.png"
Firebase.storage.reference.child("articles/photo").child(fileName)
.putFile(selectedUri ?: return@setOnClickListener)
.addOnCompleteListener{
if(it.isSuccessful){
Firebase.storage.reference.child("articles/photo").child(fileName)
.downloadUrl
.addOnSuccessListener {
Log.e("imageUri",it.toString())
}.addOnFailureListener {
}
}else{
it.exception?.printStackTrace()
}
}
} else {
Snackbar.make(view, "이미지를 선택해주세요.", Snackbar.LENGTH_SHORT).show()
}
}
로그에 uri주소가 잘 나오고
uri를 눌러보면 내가 넣은 눈뜬 내 셀카가 잘 나온다.
기능 정리를 어떻게 할까하다가 layout에 버튼들을 가지고 setOnclickListener을 전부 추가할 것이라서 표로 나타냈다.
setOnClickListener | 구현 |
간략히 설명하자면 지난번 글의 navigation에 다시 homeFragment로 돌아가는 action 추가/이어주기 |
|
아까 등록한 action으로 페이지 이동 / 위에서 설명한 게시물 등록 | |
|
선택된 이미지, uri를 지워야한다. |
|
처음 들어왔을 때 선택하지 않거나 선택한 이미지를 지웠을 경우에 볼 수 있는 버튼이기 때문에 if문으로 이미지가 없다는 조건하에 다시 이미지를 선택할 수 있게 해준다. 밑에 메서드로 선언한 이유는 시작했을 때도 나와야하고 +버튼을 눌렀을 경우에도 뜨기 때문에 코드를 중복할 필요없이 메서드 호출로 코드 중복을 최소화하기 위함이다. |
게시물은 다음 포스팅 |
+) navigation 기능인 Animations 활용하기
- enterAnim : action으로 이동해서 새로운 화면이 띄어질 때
- exitAnim : action으로 이동해서 원래있던 화면이 exit할 때
- popEnterAnim : 원래 화면으로 돌아갈 때의 원래 화면의 animation
- popExitAnim : 새로운 화면이 exit할 때의 animation
ref
'Android Studio' 카테고리의 다른 글
Android - TabLayout 사용해서 Fragment 전환 (0) | 2024.03.26 |
---|---|
Android - SharedPreferences (0) | 2024.03.25 |
Android - FireStore 규칙 설정 / 데이터 가져오기 (1) | 2024.03.12 |
Kotlin - Firebase Auth로 간단한 로그인 구현 (1) | 2024.03.08 |
Android - FragmentContainerView와 BottomNavigation item으로 fragment넘기기 (2) | 2024.03.05 |