[Kotlin_Android] Fragment recyclerView이용해서 랭킹 화면 만들기

Jamwon·2021년 5월 12일
0

Kotlin_Android

목록 보기
5/30

이번에는 사용자 본인의 운동 point와 소속이 같은 유저들의 운동 point들의 랭킹 페이지를 구현해본다!

원래는 소속을 전국 대학교 list로 한정할려했는데 아직은 그냥 String으로 같은 이름들끼리로 구현했다.

1. fragment_ranking_main.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="@color/gray"
    tools:context=".fragment.MyPageFragment"

   >

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"

        app:layout_constraintGuide_percent="0.9" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="15dp"
        android:layout_marginStart="5dp"
        android:layout_marginEnd="5dp"
        android:layout_weight="8"
        android:background="@drawable/shape_rectanglegray"
        android:orientation="vertical"
        android:weightSum="8"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="10dp"
            android:layout_weight="1">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="38dp"
                android:layout_gravity="center"
                android:src="@drawable/group_ranking_blue" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="금주의 랭킹"
                android:textColor="@color/white"
                android:textSize="20dp"
                android:textStyle="bold" />

        </FrameLayout>


        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="2dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:layout_weight="1.3"
            android:background="@drawable/shape_ranking_mine">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <ImageView
                    android:layout_width="80dp"
                    android:layout_height="70dp"
                    android:layout_marginLeft="15dp"
                    android:layout_marginTop="10dp"
                    android:scaleType="centerCrop"
                    android:src="@drawable/penguin" />

                <LinearLayout
                    android:layout_width="130dp"
                    android:layout_height="match_parent"
                    android:layout_marginLeft="10dp"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/txt_ranking_my_id"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="top|center"
                        android:layout_marginTop="10dp"
                        android:text="본인아이디"
                        android:textSize="25dp" />

                    <TextView
                        android:id="@+id/txt_ranking_my_points"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="top|center"
                        android:layout_marginTop="5dp"
                        android:text="2000pt"
                        android:textSize="20dp" />


                </LinearLayout>

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="50dp"
                    android:layout_gravity="center"
                    android:layout_marginLeft="5dp"
                    android:text="운동하기"
                    android:textStyle="bold" />


            </LinearLayout>
        </FrameLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="87dp"
            android:layout_weight="4.7">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rankingRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginStart="8dp"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="8dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="8dp"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
        </FrameLayout>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

같이 프로젝트 진행하는 친구가 만들어준 ranking xml에 recycler view을 적용해서 만들었다.

랭킹, 포인트 정보 받아오기.

화면들이 바뀌는 PageActivity.kt 에서 volley통신을 이용해서 사용자의 운동 point랑 소속이 같은 사용자의 ranking과 point를 받아오기로 했다.ㅣ

사용자 운동 point는 sharedPereference 를 이용해서 저장하려고 User()에 point 정보를 추가해주고 나중에 운동을 하고나면 포인트를 다시 갱신해주는 함수를 만들어 주었다.

SharedManager.kt

fun setUserPoint(user:User,points:Int){
        prefs["points"]=points.toString()
    }
fun saveCurrentUser(user: User){
        prefs["name"]=user.name
        prefs["id"] =user.id
        prefs["password"]=user.password
        prefs["belong"] =user.belong
        prefs["age"]=user.age
        prefs["gender"]=user.gender
        prefs["points"]="0"
    }

이런식으로 수정해주고 User data class에도 point를 추가해줬다.

PageActivity.kt

    private fun setUserRank(){
        val queue = Volley.newRequestQueue(this)
        var currentUser = sharedManager.getCurrentUser()

        val url_getUserRank = JSP.getUserRank(currentUser.id.toString())

        val StringRequest2 = StringRequest(
                Request.Method.GET, url_getUserRank, { response ->
            response.trim { it <= ' ' }

            val details2 = (response.trim().split(",")).toTypedArray()
            val userPoint :Int
//            Toast.makeText(this, "유저의 운동 points:${details2[2]}", Toast.LENGTH_SHORT).show()
            if (details2[2]==null){


                sharedManager.setUserPoint(currentUser,0)
            }
            else{
                sharedManager.setUserPoint(currentUser,details2[2].toInt())
            }
                                                     }, {
            Toast.makeText(this, "server error", Toast.LENGTH_SHORT).show()
        })
        queue.add(StringRequest2)

    }
    private fun setRankData(){
        val queue = Volley.newRequestQueue(this)
        var currentUser = sharedManager.getCurrentUser()
        val url_getEveryRank = JSP.getEveryRank(currentUser.belong.toString())

        val StringRequest3 = StringRequest(
                Request.Method.GET, url_getEveryRank, { response ->
            response.trim { it <= ' ' }

            val details3 = (response.trim().split(",")).toTypedArray()
            datas.clear()
            for (i in 0 until (details3.size)-3 step 3){
//                Log.d("ranklist",details3.size.toString())
//                Log.d("ranklist",details3[i])
                datas.apply{
                    add(User(img = R.drawable.penguin, id = details3[i+1],points = details3[i+2]))

                }
                Log.d("ranklist","${details3[i+1]} ${details3[i+2]}")
            }
            initRecycler()

        }, {
            Toast.makeText(this, "server error", Toast.LENGTH_SHORT).show()
        })
        queue.add(StringRequest3)
    }
    

setUserRank() 함수는 sharedManager를 이용해서 현재 사용자의 정보를 받아와서 운동 point를 지정해주는 함수이다.

jsp로 구현된 기능은 userid를 GET하면 순위,id,point 이런식으로 response가 온다.. 흐음.....

어플리케이션 자체에서 운동을 기록하고 유저 point를 갱신해주는 기능은 자세 교정 기능을 다 이식시키고 적용할 계획이다.

setRankData() 함수는 mutablelist에다가 유저의 정보를 하나씩 더해준다음에 initRecycler 함수를 실행한다.(fragment에 ranking정보를 보내줄 adapter의 갱신)

jsp구 구현된 기능은 유저의 소속을 보내면 그 소속의 모든 유저의 랭킹,id,point가 넘어오는데... response가 랭킹,id,point,랭킹,id,point ----,id,point,랭킹 이런식으로 줄줄이 소세지 와서..일일이 잘라서 넣어주었다... 이런식이 아닐텐데...

   fun initRecycler(){
        userRankAdapter = UserRkAdapter(this)
        rankingRecyclerView?.adapter = userRankAdapter
        userRankAdapter.datas =datas
        userRankAdapter.notifyDataSetChanged()

    }

initRecycler() 함수는 recylerview에 넘어갈 adapter를 지정해주는 함수이다.

함수들은 만들었고 bottom nav bar에서 랭킹을 누르면 setRankData 가 실행되게 setUserRank는 PageActivity가 실행될때 한번 실행되게 하였다.

RankingMainFragment.kt

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity as PageActivity).initRecycler()
        Log.d("viewCreated","initRecyclerView")
    }

Fragment가 실행되고 PageActivity에서 만든 initRecycler() 함수를 실행시키면되는데 !!! 중요할점은 onCreate나 onCreateView에서 initRecycler() 함수를 실행하면 참조할 View가 생성되어있지기 때문에 꼭 onViewCreated에서 함수를 써야된다.

여기서 문제점!!!!!!

기존에 앞의 문서에서 썻듯이 fragment를 replace하는식으로 bottom nav bar의 버튼을 통해서 fragment를 바꿨는데 replace를 하고 나서 다시 그 fragment로 replace 하면 adapter가 다시 연결이 되지않는다...!!

replace는 해당 컨테이너에 있는 모든 fragment를 지우고 새 fragment를 추가하는건데 이때 생명주기가 새로 시작되어서 그런거 같다..!

해결책

fragment를 replace하지 않고 show() hide()를 이용해서 화면 전환을 만들어주었다. 이 함수는 fragment를 화면에서 잠시 숨겼다가 보여주는 그런방식이다.

PageActivity.kt

화면 Tag를 전역변수로 정해주었다.

 companion object {
        private const val TAG_HOME_FRAGMENT = "home"
        private const val TAG_RANK_FRAGMENT = "rank"
        private const val TAG_ROUTINE_FRAGMENT="routine"
        private const val TAG_GUIDE_FRAGMENT="guide"
        private const val TAG_MYPAGE_FRAGMENT="mypage"
    }
private fun setFragment(fragment:Fragment, tag:String){
        val transaction = supportFragmentManager.beginTransaction()
        val manager = supportFragmentManager
        if (manager.findFragmentByTag(tag)==null){
            transaction.add(R.id.frameLayout,fragment,tag)
        }
        val home = manager.findFragmentByTag(TAG_HOME_FRAGMENT)
        val rank = manager.findFragmentByTag(TAG_RANK_FRAGMENT)
        val routine = manager.findFragmentByTag(TAG_ROUTINE_FRAGMENT)
        val guide = manager.findFragmentByTag(TAG_GUIDE_FRAGMENT)
        val mypage = manager.findFragmentByTag(Companion.TAG_MYPAGE_FRAGMENT)

        if (home!= null){
            transaction.hide(home)
        }
        if (rank!= null){
            transaction.hide(rank)
        }
        if (routine!= null){
            transaction.hide(routine)
        }
        if (guide!= null){
            transaction.hide(guide)
        }
        if (mypage!= null){
            transaction.hide(mypage)
        }

        when (tag){
            TAG_HOME_FRAGMENT->{
                if(home!=null){
                    transaction.show(home)
                }
            }
            TAG_RANK_FRAGMENT->{
                if(rank!=null){
                    transaction.show(rank)
                }
            }
            TAG_ROUTINE_FRAGMENT->{
                if(routine!=null){
                    transaction.show(routine)
                }
            }
            TAG_GUIDE_FRAGMENT->{
                if(guide!=null){
                    transaction.show(guide)
                }
            }
            Companion.TAG_MYPAGE_FRAGMENT ->{
                if(mypage!=null){
                    transaction.show(mypage)
                }
            }
        }

        transaction.addToBackStack(tag)
        transaction.commitAllowingStateLoss()
    }

만약 fragment가 생성되어있지 않으면 함수가 실행될때 fragment를 add해준다. 그리고 상황에 따라 fragment를 hide하고 show 해주는 식으로 만들었다.

override fun onClick(v: View) {
//        val datas = mutableListOf<User>()
        val currentUser = sharedManager.getCurrentUser()

        val transaction = supportFragmentManager.beginTransaction()
        when (v.id) {
            R.id.btn_home -> {
                setDataAtFragment(HomeFragment(), TAG_HOME_FRAGMENT)
            }
            R.id.btn_guide -> {
                setDataAtFragment(GuideMainFragment(), TAG_GUIDE_FRAGMENT)
            }
            R.id.btn_mypage -> {
                setDataAtFragment(MyPageFragment(), TAG_MYPAGE_FRAGMENT)
            }
            R.id.btn_ranking -> {
                setRankData()
                setDataAtFragment(RankingMainFragment(), TAG_RANK_FRAGMENT)
            }
            R.id.btn_routine -> {
                setDataAtFragment(MyRoutineFragment(), TAG_ROUTINE_FRAGMENT)
            }
            R.id.btn_drawer -> {
                info_user_id.setText("${currentUser.id}")
                info_user_belong.setText("${currentUser.belong}")
                main_drawer_layout.openDrawer(GravityCompat.START)
            }
            R.id.btn_logout -> {
                logOut()
            }
        }
    }

그래서 해당 버튼들이 눌렸을때 Tag를 참조해서 화면을 전환해주는 걸 완성하였다.

기능우선적으로 만들고있어서 좀 사이즈가 맞지 않는다...

profile
한걸음씩 위로 자유롭게

0개의 댓글