이번에는 게시글을 작성하고 작성한 게시글이 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를 가져온 것이다!
설명을 너무 못해서 제가 이해한거 이해하려하지말고 참고한 자료 보시길..
[Kotlin] Fragment Navigation 화면 전환 방법
Fragment Navigation 이란? Android Jetpack의 Navigation Component를 사용하여 페이지 이동을 쉽게 구현하게 해주는 방법이다. * 공식 문서 * https://developer.android.com/guide/navigation/navigation-getting-started 1. Navigation
cocococo.tistory.com
그냥 게시글을 작성하게 만드는 것은 안된다.
저번 글에서 인증된 사용자만 게시글에 권한이 있게 만들어 주었다.
그러면 조건문으로 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) 갤러리에서 사진 가져오기
페이지 이동까지 마쳤으면 갤러리에 접근 허용과 사진을 선택했을 때 사진을 가져올 수 있어야한다.
밑에 공식문서를 읽고 가면 좋다.
저장소 액세스 프레임워크를 사용하여 파일 열기 | Android 개발자 | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 저장소 액세스 프레임워크를 사용하여 파일 열기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Androi
developer.android.com
5_0) UI 수정
사진을 눌렀을 때 가져올 수 있게 writeFragment layout 추가
사진 받을 부분은 ImageView로 받았다.
+ 버튼으로 이미지를 받고 x 버튼은 사진을 다시 지우는 버튼
개인 id 사항
선택된 이미지 띄우는 ImageView = selectedImageView
이미지 넣는 + 버튼 : plusImageButton
이미지 지우는 x 버튼 : clearImageButton
밑에 코드에서 찾으실까봐 필요한 부분 id만 올렸다.
나머지는 개인 취향껏
5_1) 갤러리 접근 허용
공유 저장소 미디어 파일에 액세스 | Android Developers
DataStore offers a more modern way of storing local data. You should use DataStore instead of SharedPreferences. Read the DataStore guide for more information. 이 페이지는 Cloud Translation API를 통해 번역되었습니다. 공유 저장소 미디
developer.android.com
추가적으로 API 33이전의 API를 사용하면 위에 사진 맨 밑줄처럼 EXTERNAL_STORAGE도 함께 허용해야 한다.
밑에 사진 설명
[Android/Kotlin] 갤러리 접근 권한(Premission) 설정하기 - 커스텀 갤러리(1)
안드로이드 앱을 개발하다 보면 특정 권한을 얻어야지만 사용이 가능한 기능들이 있습니다. Android6.0 (API 수준 23) 마쉬멜로우 이전 버전은 메니페스트에 권한을 넣어주면 사용이 가능했지만, 마
tg-world.tistory.com
위에 블로그 내용을 참고했습니다.
5_2) 사진 가져오기
위에 공식문서 밑에 좋은 도구가 있다.
사진 선택 도구 | Android Developers
DataStore offers a more modern way of storing local data. You should use DataStore instead of SharedPreferences. Read the DataStore guide for more information. 이 페이지는 Cloud Translation API를 통해 번역되었습니다. 사진 선택 도구 컬
developer.android.com
위에처럼 나오게 사용할 것이다.
>>그냥 복붙
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
[Kotlin] Fragment Navigation 화면 전환 방법
Fragment Navigation 이란? Android Jetpack의 Navigation Component를 사용하여 페이지 이동을 쉽게 구현하게 해주는 방법이다. * 공식 문서 * https://developer.android.com/guide/navigation/navigation-getting-started 1. Navigation
cocococo.tistory.com
[Android/Kotlin] 갤러리 접근 권한(Premission) 설정하기 - 커스텀 갤러리(1)
안드로이드 앱을 개발하다 보면 특정 권한을 얻어야지만 사용이 가능한 기능들이 있습니다. Android6.0 (API 수준 23) 마쉬멜로우 이전 버전은 메니페스트에 권한을 넣어주면 사용이 가능했지만, 마
tg-world.tistory.com
'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 |