Kotlin, FireBase 채팅어플 만들기 -1- [Splash] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -2- [Login] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -3- [Sign Up] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -4- [Bottom Navigation] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -5- [친구창_fragment] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -6- [채팅 리스트_fragment] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -7- [프로필 변경_fragment] (tistory.com)
Kotlin, FireBase 채팅어플 만들기 -8- [채팅창_activity] (tistory.com)
[전체 코드 깃허브 주소]
LasBe-code/LasbeTalk (github.com)
[참고]
[XML]
<fragment_profile.xml>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/profile_imageview"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/profile_textview_email"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/profile_textview_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="TextView"
android:textColor="#505050"
app:layout_constraintBottom_toTopOf="@+id/profile_textview_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/profile_imageview" />
<EditText
android:id="@+id/profile_textview_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:gravity="center"
android:inputType="textPersonName"
android:text="Name"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/profile_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/profile_textview_email" />
<Button
android:id="@+id/profile_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Change"
android:textColor="#FFFFFF"
app:backgroundTint="#FFFF9800"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/profile_textview_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
비율을 위해 레이아웃으로 한번 묶어준 후 heigth를 wrap_content로 설정해주었다
ImageView는 변경 가능한 프로필사진
TextView는 변경 불가능한 이메일
EditText는 변경 가능한 이름
[액티비티 or 프래그먼트]
class ProfileFragment : Fragment() {
companion object{
private var imageUri : Uri? = null
private val fireStorage = FirebaseStorage.getInstance().reference
private val fireDatabase = FirebaseDatabase.getInstance().reference
private val user = Firebase.auth.currentUser
private val uid = user?.uid.toString()
fun newInstance() : ProfileFragment {
return ProfileFragment()
}
}
//메모리에 올라갔을 때
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
//프레그먼트를 포함하고 있는 액티비티에 붙었을 때
override fun onAttach(context: Context) {
super.onAttach(context)
}
private val getContent =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if(result.resultCode == AppCompatActivity.RESULT_OK) {
imageUri = result.data?.data //이미지 경로 원본
profile_imageview.setImageURI(imageUri) //이미지 뷰를 바꿈
//기존 사진을 삭제 후 새로운 사진을 등록
fireStorage.child("userImages/$uid/photo").delete().addOnSuccessListener {
fireStorage.child("userImages/$uid/photo").putFile(imageUri!!).addOnSuccessListener {
fireStorage.child("userImages/$uid/photo").downloadUrl.addOnSuccessListener {
val photoUri : Uri = it
println("$photoUri")
fireDatabase.child("users/$uid/profileImageUrl").setValue(photoUri.toString())
Toast.makeText(requireContext(), "프로필사진이 변경되었습니다.", Toast.LENGTH_SHORT).show()
}
}
}
Log.d("이미지", "성공")
}
else{
Log.d("이미지", "실패")
}
}
//뷰가 생성되었을 때
//프레그먼트와 레이아웃을 연결시켜주는 부분
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//view 선언을 안하고 return에 바로 적용시키면 glide가 작동을 안함
val view = inflater.inflate(R.layout.fragment_profile, container, false)
val photo = view?.findViewById<ImageView>(R.id.profile_imageview)
val email = view?.findViewById<TextView>(R.id.profile_textview_email)
val name = view?.findViewById<TextView>(R.id.profile_textview_name)
val button = view?.findViewById<Button>(R.id.profile_button)
//프로필 구현
fireDatabase.child("users").child(uid).addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
}
override fun onDataChange(snapshot: DataSnapshot) {
val userProfile = snapshot.getValue<Friend>()
println(userProfile)
Glide.with(requireContext()).load(userProfile?.profileImageUrl)
.apply(RequestOptions().circleCrop())
.into(photo!!)
email?.text = userProfile?.email
name?.text = userProfile?.name
}
})
//프로필사진 바꾸기
photo?.setOnClickListener{
val intentImage = Intent(Intent.ACTION_PICK)
intentImage.type = MediaStore.Images.Media.CONTENT_TYPE
getContent.launch(intentImage)
}
button?.setOnClickListener{
if(name?.text!!.isNotEmpty()) {
fireDatabase.child("users/$uid/name").setValue(name.text.toString())
name.clearFocus()
Toast.makeText(requireContext(), "이름이 변경되었습니다.", Toast.LENGTH_SHORT).show()
}
}
return view
}
}
우선 프로필사진은 갤러리에서 선택하면 바로 변경되도록 적용했다.
이름은 버튼을 누르면 변경이 적용된다.
회원가입 액티비티와 같이 getContent를 사용하여 이미지 뷰를 클릭했을 때
MediaStore를 이용하여 갤러리를 띄우고
선택한 사진의 ImageUri를 registerForAvtivityResult로 받아온다.
회원가입과 다른 점은 getContent 내에서
delete()를 통해 기존에 있던 프로필 사진을 삭제 후 콜백을 받아
선택한 사진을 storage에 올리고 또 콜백을 받아
database에 이미지 url을 변경해준다.
private val getContent =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if(result.resultCode == AppCompatActivity.RESULT_OK) {
imageUri = result.data?.data //이미지 경로 원본
profile_imageview.setImageURI(imageUri) //이미지 뷰를 바꿈
//기존 사진을 삭제 후 새로운 사진을 등록
fireStorage.child("userImages/$uid/photo").delete().addOnSuccessListener {
fireStorage.child("userImages/$uid/photo").putFile(imageUri!!).addOnSuccessListener {
fireStorage.child("userImages/$uid/photo").downloadUrl.addOnSuccessListener {
val photoUri : Uri = it
println("$photoUri")
fireDatabase.child("users/$uid/profileImageUrl").setValue(photoUri.toString())
Toast.makeText(requireContext(), "프로필사진이 변경되었습니다.", Toast.LENGTH_SHORT).show()
}
}
}
Log.d("이미지", "성공")
}
else{
Log.d("이미지", "실패")
}
}
.
.
///onCreateView///
photo?.setOnClickListener{
val intentImage = Intent(Intent.ACTION_PICK)
intentImage.type = MediaStore.Images.Media.CONTENT_TYPE
getContent.launch(intentImage)
}
이름 변경하는 부분은 쉬워서 패스
가장 애먹었던 부분은 프래그먼트 내에서 glide로 이미지를 불러오는 것이었다.
어댑터에서는 holder.itemView.context에서
액티비티에서는 this로
프래그먼트에서는 requireContext()로 context를 불러올 수 있었다.
그리고 view를 직접 선언하지 않고 return문에 inflater를 넣어주면 프로필 프래그먼트를 열 때
glide에서 오류가 나와서 팅기는 문제가 있었다.
view를 선언해서 문제는 해결했지만 이유는 잘 모르겠다.
//// 리사이클러뷰 어댑터 ////
Glide.with(holder.itemView.context).load(friend?.profileImageUrl)
.apply(RequestOptions().circleCrop())
.into(holder.imageView)
//// 프래그먼트 ////
Glide.with(requireContext()).load(userProfile?.profileImageUrl)
.apply(RequestOptions().circleCrop())
.into(photo!!)
//// return문에 inflater == glide 오류 ////
return inflater.inflate(R.layout.fragment_profile, container, false)
//// view 선언 == glide 성공 ////
val view = inflater.inflate(R.layout.fragment_profile, container, false)
[작동]
[아쉬운 점]
버튼을 눌렀을 때 프로필사진과 이름이 같이 바뀌도록 수정해야겠다.
'Android' 카테고리의 다른 글
Kotlin, FireBase 채팅어플 만들기 -8- [채팅창_activity] (0) | 2021.09.09 |
---|---|
Kotlin, FireBase 채팅어플 만들기 -6- [채팅 리스트_fragment] (0) | 2021.09.09 |
Kotlin, FireBase 채팅어플 만들기 -5- [친구창_fragment] (0) | 2021.09.07 |
Kotlin, FireBase 채팅어플 만들기 -4- [Bottom Navigation] (0) | 2021.09.04 |
Kotlin, FireBase 채팅어플 만들기 -3- [Sign Up] (0) | 2021.09.02 |
댓글