Skip to content

29th-WE-SOPT-Android-Part/Android-Hyebin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 

Repository files navigation

Android-Hyebin

github_이혜빈_ver1-25




1주차

1️⃣ First Week

SignIn Login Home SignUp
ezgif com-gif-maker ezgif com-gif-maker (1) ezgif com-gif-maker (2) ezgif com-gif-maker (3)




1. SignUp

  • 아이디, 비밀번호 입력이 모두 되었을 때만 로그인 버튼 눌렀을 때 HomeActivity로 이동 (토스트메시지 출력)
val intentHome = Intent(this, HomeActivity::class.java)

binding.apply {
     btnLogin.setOnClickListener {
         val userId : String = etId.text.toString()
         val userPw : String = etPassword.text.toString()
         if (userId.isNotEmpty() && userPw.isNotEmpty()) {
             startActivity(intentHome)
             Toast.makeText(this@SignInActivity, "$userId 님 환영합니다", Toast.LENGTH_SHORT).show()
         } else {
              Toast.makeText(this@SignInActivity, "로그인 실패", Toast.LENGTH_SHORT).show()
         }
     }
 }



  • 회원가입 버튼 눌렀을 때 화면 이동
val intentSingUp = Intent(this, SignUpActivity::class.java)
        
btnSignup.setOnClickListener {
    startActivity(intentSingUp)
    finish()
}



  • 회원가입에 성공한 뒤, 아이디&패스워드 자동 입력
if (intent.hasExtra("id") && intent.hasExtra("pw")) {
    val id = intent.getStringExtra("id")
    val pw = intent.getStringExtra("pw")

    etId.setText(id)
    etPassword.setText(pw)
}



  • EditText의 hint 속성 및 비밀번호의 inputType 속성
<EditText
    android:id="@+id/et_password"
    android:layout_width="0dp"
    android:layout_height="50dp"
    android:layout_marginStart="40dp"
    android:layout_marginTop="10dp"
    android:layout_marginEnd="40dp"
    android:background="@drawable/et_border_pink"
    android:ems="10"
    android:hint="비밀번호를 입력해주세요"
    android:textSize="15dp"
    android:paddingStart="20dp"
    android:inputType="textPassword"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/tv_password" />




2. Home

  • Home 버튼 누르면 나의 git 페이지로 이동 (암시적 인텐트)
binding.btnGit.setOnClickListener{
    var intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/lhb8106"))
    startActivity(intent)
}

✅명시적 인텐트와 암시적 인텐트의 차이점✅

명시적 인텐트는 실행하고자하는 컴포넌트가 명확할 때 사용하는 방식입니다. 즉, 패키지 내부의 액티비티를 실행할 때 사용됩니다.
암시적 인텐트는 어떠한 인텐트를 담아서 보내면, 시스템이 적절한 컴포넌트를 찾아서 실행해주는 방식입니다.



  • 사진 비율 맞추기
 <ImageView
     android:id="@+id/iv_profile"
     android:layout_width="180dp"
     android:layout_height="0dp"
     android:layout_marginTop="20dp"
     android:src="@drawable/selca"
     app:layout_constraintDimensionRatio="1:1"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toTopOf="parent" />



  • 스크롤뷰 적용
<ScrollView
    android:id="@+id/scroll"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginTop="20dp"
    android:layout_marginBottom="20dp"
    android:fillViewport="true"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/tv_title">
</ScrollView>




3. SignIn

  • 회원가입 완료 버튼 눌렀을 때, 빈칸 확인 및 아이디, 비밀번호 값 넘겨주기
val intent = Intent(this, SignInActivity::class.java)

binding.apply {
    btnSingup.setOnClickListener {
        val userName : String = etName.text.toString()
        val userId : String = etId.text.toString()
        val userPw : String = etPassword.text.toString()

         if (userName.isNotEmpty() && userId.isNotEmpty() && userPw.trim().isNotEmpty()) {
                    intent.putExtra("id", userId)
                    intent.putExtra("pw", userPw)
                    startActivity(intent)
                    finish()

         } else {
             Toast.makeText(this@SignUpActivity, "입력되지 않은 정보가 있습니다", Toast.LENGTH_SHORT).show()
         }
     }
  }



  • hint 속성 및 inputType 속성은 위의 SignUp과 같습니다.







🤍이번 과제를 통해 배운 내용 & 성장한 내용🤍


**☝constraintlayout을 정확히 이해했습니다!**
지금까지 안드로이드 스튜디오에서 LinearLayout을 주로 사용하고, ConstraintLayout을 제대로 활용해본 경험이 없었는데, 이번 과제와 세미나를 통해 ConstraintLayout을 제대로 이해하고 활용할 수 있는 방법을 알게 되었습니다.
그 외에도 layout 내에서 쓸 수 있는 다양한 속성을 익힐 수 있었습니다. (inputType 속성 & constraintDimensionRatio 속성)

✌intent를 이해할 수 있는 기회가 되었습니다!
처음에는 잘 이해가 되지 않았지만, 여러번 화면을 이동하는 연습을 하다보니, intent를 사용하는 방법과 활용 방안에 대해서 잘 익힐 수 있는 기회가 되었습니다.
하지만 hasExtra는 아직은..잘 모르겠네요.. 얼렁뚱당 의도대로 움직이긴 하지만 더 정확한 코드를 작성하고 싶습니다.

👌git과 notion
git을 다루는 방법을 하나도 모르는 사람이었는데, 이번에 과제를 제출하기 위해 유튜브도 찾아보고 많은 사람들에게 물어보며 공부를 했습니다..
아직 배워야할 점이 산더미이지만 차근차근 올라가서 나중에는 꼭 깃 마스터가 되겠습니다..❗
그리고 notion을 솝트 들어와서 처음 알게 되었다보니, 자료 하나 찾는데에도 꽤 많은 시간을 소모했습니다.
하지만 자주 들어가서 정보를 확인하다보니 notion이 점점 어렵지 않게 느껴집니다!
노션과 깃.. 차차 친해지겠습니다💗







2주차

2️⃣ Second Week

Home
ezgif com-gif-maker (5)



🙏FollowerRecyclerView와 RepositoryRecyclerView의 코드가 유사하므로 FollowerRecyclerView 구현코드만 작성하겠습니다.🙏


LEVEL1



1. FollowerRecyclerView

+) LinearLayoutManager 사용 ( GridLayoutManage관련 코드는 하단에 첨부하겠습니다. )

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_follower"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        tools:itemCount="4"
        tools:listitem="@layout/item_follower_list" />



2. FolloweData

data class FollowerData(
    val name: String,
    val introduction: String
)



3. FollowrAdapter

class FollowerAdapter : RecyclerView.Adapter<FollowerAdapter.FollowerViewHolder>() {
    val userList = mutableListOf<FollowerData>()

    class FollowerViewHolder(private val binding : ItemFollowerListBinding) : RecyclerView.ViewHolder(binding.root){
        fun onBind(data: FollowerData) {
            binding.tvName.text = data.name
            binding.tvIntroduction.text = data.introduction
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FollowerViewHolder {
        val binding = ItemFollowerListBinding.inflate(LayoutInflater.from(parent.context),parent,false)

        return FollowerViewHolder(binding)
    }

    override fun onBindViewHolder(holder: FollowerViewHolder, position: Int) {
        holder.onBind(userList[position])
    }

    override fun getItemCount(): Int = userList.size
}



FollowerFragment

class FollowerFragment : Fragment() {
    private lateinit var follwerAdapter: FollowerAdapter
    private var _binding: FollowerFragmentBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FollowerFragmentBinding.inflate(layoutInflater, container,false)

        follwerAdapter = FollowerAdapter()
        binding.rvFollower.adapter = follwerAdapter

        follwerAdapter.userList.addAll(
            listOf(
                FollowerData("이혜빈1", "안녕하세요"),
                FollowerData("이혜빈2", "안녕하세요"),
                FollowerData("이혜빈3", "안녕하세요"),
                FollowerData("이혜빈4", "안녕하세요")
            )
        )
        follwerAdapter.notifyDataSetChanged()
        return binding.root

    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}



HomeActivity

class HomeActivity : AppCompatActivity() {
    private var postion = FIRST_POSITION
    private lateinit var binding : ActivityHomeBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityHomeBinding.inflate(layoutInflater)

        setContentView(binding.root)

        initTransactionEvent()
    }

    fun initTransactionEvent() {
        val followerFragment = FollowerFragment()
        val repositstoryFragment = RepositoryFragment()

        supportFragmentManager.beginTransaction().add(R.id.container_rv, followerFragment).commit()

        binding.btnFollower.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.container_rv, followerFragment) .commit()
        }

        binding.btnRepository.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.container_rv, repositstoryFragment) .commit()
        }
    }


    companion object {
        const val FIRST_POSITION = 1
    }

}



xml ellipsize 속성

<TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textColor="@color/black"
        android:textSize="12sp"
        android:ellipsize="end"
        android:maxLines="1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_title"
        tools:text="내용" />



RepositoryRecyclerView 속성
+)GridlayoutManager 사용

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_repository"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:spanCount="2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:itemCount="4"
        android:layout_marginLeft="55dp"
        android:layout_marginRight="30dp"
        android:layout_marginTop="10dp"
        tools:listitem="@layout/item_repository_list" />

LEVEL2-2


시험기간이라.. 2-2만 구현했습니다.. 다른 부분은 차차 해보겠습니다...



Decoration

   class Decoration(val colorString: String, val left: Int, val right: Int, val height: Int, val bottom:Int) : RecyclerView.ItemDecoration() {
    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDraw(c, parent, state)

        val paint = Paint().apply {
            color = Color.parseColor(colorString)
        }

        for (i in 0 until parent.childCount) {
            val child = parent.getChildAt(i)
            if (i != parent.childCount - 1) {
                c.drawRect(child.left.toFloat(), child.bottom.toFloat(), child.right.toFloat(), child.bottom.toFloat() + height, paint)
            }
        }
    }
    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.right = right
        outRect.left = left
        outRect.top = height
        outRect.bottom = height
    }
}



FollowerFragment

binding.rvFollower.addItemDecoration(Decoration("#F658A6", 50,50,25,25))







🤍이번 과제를 통해 배운 내용 & 성장한 내용🤍


☝Fragment에 대해 이해했습니다.
실습 예제만 따라하고 직접 원하는 요소를 살려서 구현은 해본 적이 없었는데, 이번 기회를 통해 직접 코드를 작성하면서 제대로 이해할 수 있는 시간을 가졌습니다.
그리고 fragment에서 binding을 사용하는 법 또한 익힐 수 있었습니다. 생명주기를 제대로 이해하지 못했는데 이번 기회를 통해 제대로 이해할 수 있게 되었습니다.

✌ItemDecoration을 알게 되었습니다.
원래 xml에서 margin값을 모두 줬는데, 이번 과제를 통해 ItemDecoration을 처음 알게되었습니다.
그래서 제가봐도 아직 부족하고.. 이상한.. 코드지만 더 열심히 공부해서.. 다음주에 더 나은 코드로 바꿔오겠습니다









3주차

3️⃣ Third Week

SignUp SignIn Profile Home ViewPager
ezgif com-gif-maker (6) ezgif com-gif-maker (7) ezgif com-gif-maker (8) ezgif com-gif-maker (9) ezgif com-gif-maker (10)



LEVEL1



1-1. EditText에 selector 활용하기

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/et_border_pink" android:state_focused="true"/>
    <item android:drawable="@drawable/et_fill_gray" android:state_focused="false"/>
</selector>



1-2. 버튼 등등 Drawable로 직접 만들기

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/pink"/>
    <corners
        android:bottomRightRadius="5dp"
        android:bottomLeftRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp"/>



✍Button에 selector 활용하기는 위의 EditText에 selector 활용하기와 같은 방식으로 코드를 작성했습니다!


2-1. 이미지 Glide의 CircleCrop 기능을 활용해서 넣어주기

 Glide.with(this)
            .load("https://mblogthumb-phinf.pstatic.net/MjAxOTA0MjNfMjcy/MDAxNTU2MDIwNjg0ODMw.KwUiIDMhdpKzsuNX83GpdFljS1HjgNhCBNcXv2QXfxkg.ksHQVjDUTn8AMV4XVSfETLX-tZ1LTz9-bOmO0o7AtI8g.JPEG.ndh7782/%EC%B9%98%EC%A6%8801.JPG?type=w800")
            .apply(RequestOptions.circleCropTransform())
            .into(binding.ivProfile)



2-2. 아이콘 이미지 export해서 사용

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_profile"
        android:icon="@drawable/ic_person_gray"
        android:title="프로필" />

    <item
        android:id="@+id/menu_home"
        android:icon="@drawable/ic_home_gray"
        android:title="" />

    <item
        android:id="@+id/menu_camera"
        android:icon="@drawable/ic_camera_gray"
        android:title="카메라" />
</menu>



2-3. 하단에 BottomNavigation 넣어주기

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:menu="@menu/menu_bottom"
        app:itemIconTint="@drawable/selector_icon"
        app:itemTextColor="@drawable/selector_icon"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />



xml ellipsize 속성

<TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textColor="@color/black"
        android:textSize="12sp"
        android:ellipsize="end"
        android:maxLines="1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_title"
        tools:text="내용" />



3-1 TabLayout + ViewPager2

 <com.google.android.material.tabs.TabLayout
        android:id="@+id/tl_follow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:fontFamily="@font/noto_sans_kr_regular"
        android:textFontWeight="500"
        android:textSize="16sp"
        app:tabIndicatorColor="@color/pink"
        app:tabIndicatorHeight="3dp"
        app:tabSelectedTextColor="@color/pink"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </com.google.android.material.tabs.TabLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp_follow"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="13dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tl_follow" />

LEVEL2-2



FollowerAdapter

 Glide.with(itemView.context).load(data.photo)
                .apply(RequestOptions.circleCropTransform())
                .into(binding.ivProfile)



FollowerData

data class FollowerData(
    val name: String,
    val introduction: String,
    val photo : String
)



FollowerFragment

 follwerAdapter.userList.addAll(
            listOf(
                FollowerData("스폰지밥", "안녕하세요", "https://ww.namu.la/s/bd52223e4d1f11fcc4c7f6506bf3321b26579bf118db6c1ca20492b9af4228a414edd25f1006baace220e4ca771288e0f38d6cbf253ae4e9d39aaf4b881600b0d65e518e7d94891837ee9a0c6a723aac0f4d2b7bf4a65b36bd1fe636aa49c632"),
                FollowerData("뚱이", "안녕하세요", "https://img.insight.co.kr/static/2020/08/12/700/fyzvinle3b068ce501hq.jpg"),
                FollowerData("집게사장", "안녕하세요", "https://pbs.twimg.com/media/D8RITHlV4AAb1iG.jpg")
            )
        )







🤍이번 과제를 통해 배운 내용 & 성장한 내용🤍


☝디자인을 적용하는 방법을 익혔습니다
초기에 직접 레이아웃을 짰을 때와 디자이너분께서 디자인해주는 것을 보며 수정을 해나가면서 나오는 결과물의 차이를 보고 디자이너의 중요성과 협업의 중요성을 깨달을 수 있는 계가기 되었습니다.
또한, 피그마를 제대로 다뤄본 적이 한번도 없었는데, 협업에 있어서 피그마를 쓰는 법을 익힐 수 있었습니다.

✌ViewPager2를 이해했습니다
어플을 사용하면서 가장 많이 봤던 기능 중 하나였는데, 이번 세미나를 통해 ViewPager2를 알 수 있었습니다.
또한, TabLayout등등도 함께 배울 수 있어서 뜻깊었습니다.




4주차 # 4️⃣ Fourth Week
LogIn
ezgif com-gif-maker (11)



LEVEL1



PostMan 테스트 이미지 첨부

POST GET
POST 조회



RequestData

data class RequestLoginData(
    @SerializedName("email")
    val email: String,
    val password: String
)

data class RequestSignUpData(
    @SerializedName("email")
    val email: String,
    val name: String,
    val password: String
)



ResponseData

data class ResponseLoginData(
    val status: Int,
    val success: Boolean,
    val message: String,
    val data: Data
) {
    data class Data(
        val id: Int,
        val name: String,
        val email: String
    )
}


data class ResponseSignUpData(
    val status: Int,
    val success: Boolean,
    val message: String,
    val data: Data
) {
    data class Data(
        val id: Int,
        val name: String,
        val email: String
    )
}



SampleService

interface SampleService {
    @Headers("Content-Type: application/json")
    @POST("user/login")
    fun postLogin(
        @Body requestLoginData: RequestLoginData
    ) : Call<ResponseLoginData>
}

interface SignUpService {
    @Headers("Content-Type: application/json")
    @POST("user/signup")
    fun postSignUp(
        @Body requestSignUpData: RequestSignUpData
    ) : Call<ResponseSignUpData>
}



ServiceCreator

<menu xmlns:android="http://schemas.android.com/apk/res/android">
object ServiceCreator {
    private const val BASE_URL = "https://asia-northeast3-we-sopt-29.cloudfunctions.net/api/"

    private val retrofit: Retrofit = Retrofit
        .Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val sampleService : SampleService = retrofit.create(SampleService::class.java)
}


object SignUpCreator {
    private const val BASE_URL = "https://asia-northeast3-we-sopt-29.cloudfunctions.net/api/"

    private val retrofit: Retrofit = Retrofit
        .Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val signUpService : SignUpService = retrofit.create(SignUpService::class.java)
}



SignInActivity

 private fun initNetwork() {
        val requestLoginData = RequestLoginData(
            binding.etId.text.toString(),
            binding.etPassword.text.toString()
        )

        val call : Call<ResponseLoginData> = ServiceCreator.sampleService.postLogin(requestLoginData)
        call.enqueue(object : Callback<ResponseLoginData> {
            override fun onResponse(
                call: Call<ResponseLoginData>,
                response: Response<ResponseLoginData>
            ) {
                if(response.isSuccessful) {
                    Toast.makeText(this@SignInActivity, "${response.body()?.data?.name}님 반갑습니다", Toast.LENGTH_SHORT).show()
                    startActivity(Intent(this@SignInActivity,HomeActivity::class.java))
                } else {
                    Toast.makeText(this@SignInActivity, "로그인에 실패했습니다", Toast.LENGTH_SHORT).show()
                }

            }

            override fun onFailure(call: Call<ResponseLoginData>, t: Throwable) {
                Log.e("NetworkTest", "error: $t")
            }

        })
    }



SignUpActivity

 private fun initNetwork() {
        val requestSignUpData = RequestSignUpData(
            binding.etName.text.toString(),
            binding.etId.text.toString(),
            binding.etPassword.text.toString()
        )

        val call : Call<ResponseSignUpData> = SignUpCreator.signUpService.postSignUp(requestSignUpData)
        call.enqueue(object : Callback<ResponseSignUpData> {
            override fun onResponse(
                call: Call<ResponseSignUpData>,
                response: Response<ResponseSignUpData>
            ) {
                if (response.isSuccessful) {
                    Toast.makeText(this@SignUpActivity, response.body()?.message, Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(this@SignUpActivity, "회원가입 실패", Toast.LENGTH_SHORT).show()
                }
            }

            override fun onFailure(call: Call<ResponseSignUpData>, t: Throwable) {
                Log.e("NetworkTest", "error: $t")
            }
        })
    }







🤍이번 과제를 통해 배운 내용 & 성장한 내용🤍


☝서버를 익혔습니다
서버가 뭔지 정말 하나도 모르고 다 처음 보는 코드와 개념 투성이어서 조금은 어렵게 느껴졌었습니다 😥
그래도! 실습과 과제를 통해... 아주 조금은.. 이해를 한 것 같다는 생각이 듭니다!
더 복습하고 공부하면서 제대로 이해하고 넘어가겠습니다!




7주차

7️⃣ Seventh Week

onBoarding autoLogin autoLogin cancel backstack
ezgif com-gif-maker (12) ezgif com-gif-maker (13) ezgif com-gif-maker (14) ezgif com-gif-maker (16)



LEVEL1



🤍view는 notion을 참고하여 제작했습니다🤍


1-1. 온보딩 화면 만들기


nav_onboarding.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/nav_onboarding"
    app:startDestination="@id/onboardingFragment1">

    <fragment
        android:id="@+id/onboardingFragment1"
        android:name="com.example.myapplication.view.onboarding.OnboardingFragment1"
        android:label="fragment_onboarding1"
        tools:layout="@layout/fragment_onboarding1" >
        <action
            android:id="@+id/action_onboardingFragment1_to_onboardingFragment2"
            app:destination="@id/onboardingFragment2" />
    </fragment>

    <fragment
        android:id="@+id/onboardingFragment2"
        android:name="com.example.myapplication.view.onboarding.OnboardingFragment2"
        android:label="OnboardingFragment2" >
        <action
            android:id="@+id/action_onboardingFragment2_to_onboardingFragment3"
            app:destination="@id/onboardingFragment3" />
    </fragment>

    <fragment
        android:id="@+id/onboardingFragment3"
        android:name="com.example.myapplication.view.onboarding.OnboardingFragment3"
        android:label="OnboardingFragment3">
        <action
            android:id="@+id/action_onboardingFragment3_to_signInActivity"
            app:destination="@id/signInActivity" />
    </fragment>
    <activity
        android:id="@+id/signInActivity"
        android:name="com.example.myapplication.view.login.SignInActivity"
        android:label="activity_main"
        tools:layout="@layout/activity_signin" />
</navigation>



OnboardingFragment1


각 프레그먼트별로 buttonEvent를 생성했습니다


fun initBtnEvent() {
        binding.btnNext.setOnClickListener {
            findNavController().navigate(R.id.action_onboardingFragment1_to_onboardingFragment2)
        }
    }



1-2. SharedPreferences 활용해서 자동로그인/자동로그인 해제


activity_cancel_auto_login

<?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"
    tools:context=".view.profile.CancelAutoLoginActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:background="@color/pink"
        android:id="@+id/constraintLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/tv_setting"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:layout_marginTop="30dp"
            android:layout_marginBottom="30dp"
            android:fontFamily="@font/noto_sans_kr_regular"
            android:text="환경설정"
            android:textColor="@color/white"
            android:textFontWeight="800"
            android:textSize="30sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


    </androidx.constraintlayout.widget.ConstraintLayout>


    <TextView
        android:id="@+id/tv_off_auto_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:fontFamily="@font/noto_sans_kr_regular"
        android:text="자동로그인 해제"
        android:textColor="@color/maingray"
        android:textFontWeight="400"
        android:textSize="18sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/constraintLayout" />

    <LinearLayout
        android:id="@+id/ll_line"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_marginTop="20dp"
        android:background="@color/lightgray"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_off_auto_login" />


</androidx.constraintlayout.widget.ConstraintLayout>



SiginInActivity

private fun initClickEvent() {
    binding.ivAutoLogin.setOnClickListener {
        binding.ivAutoLogin.isSelected = !binding.ivAutoLogin.isSelected
            SOPTSharedPreferences.setAutoLogin(this, binding.ivAutoLogin.isSelected)
        }
    }

private fun isAutoLogin() {
    if(SOPTSharedPreferences.getAutoLogin(this)) {
         shortToast("자동로그인 완료")
         startActivity(Intent(this, HomeActivity::class.java))
         finish()
    }
}



CancelAutoLoginActivity

private fun initClickEvent() {
    binding.tvOffAutoLogin.setOnClickListener {
        val settings: SharedPreferences = getSharedPreferences("USER_AUTH", MODE_PRIVATE)
        val editor: SharedPreferences.Editor = settings.edit()
        editor.remove("int")
        editor.clear()
        editor.commit()
    }
}



1-3 본인이 사용하는 Util 클래스 코드 및 패키징 방식
util에서는 세미나 시간에 다룬 shortToast를 정의해둔 상태입니다.
자주 사용하는 토스트 메시지 기능을 클래스로 만들어 여러 곳에서 사용할 수 있었습니다.

fun Context.shortToast(message: String) {
  Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

- 패키징 방식
-자주 생성되는 클래스인 adapter, api, data, util, view를 중심으로 하여 패키지를 나눴습니다.

┣ 📂adapter
┣ 📂api
┣ 📂data
┣ 📂util
┗ 📂view

┣ 📂camera
┣ 📂home
┣ 📂login
┣ 📂onboarding
┗ 📂profile

LEVEL2



2-1. NavigationComponent에서 BackStack관리

<fragment
      android:id="@+id/onboardingFragment2"
      android:name="com.example.myapplication.view.onboarding.OnboardingFragment2"
      android:label="OnboardingFragment2" >
      <action
          android:id="@+id/action_onboardingFragment2_to_onboardingFragment3"
          app:destination="@id/onboardingFragment3"
          app:popUpTo="@id/onboardingFragment2"
          app:popUpToInclusive="true"/>
  </fragment>







🤍이번 과제를 통해 배운 내용 & 성장한 내용🤍


☝navigation
보통 어플을 실행했을때 자주 접했던 온보딩 화면을 만들 수 있는 기회라서 뜻깊고 앞으로 많이 활용될 것 같아 굉장히 많이 배운 것 같습니다.

✌util에 대해 이해했습니다
항상 자주 사용하는 부분에서 꼭 저렇게 써야하나라는 것을 많이 생각했는데, 이번 세미니와 과제를 통해 util을 배우고, 반복되는 코드를 단순화 할 수 있는 기회가 되었습니다.

👌package기능에 대해 이해했습니다
클래스가 너무 많아서 이제 뭐가 뭔지 헷갈리기 시작했는데, 이때 딱 패키징에 대해서 배우고 활용해보는 기회가 되었습니다! 앞으로 제가 정의한 패키징 방식에 따라 사용하면 나중에도 보다 프로젝트를 관리하기 좋을 것 같다는 생각이 들었습니다.




About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published