โ๏ธ ํ์ ๊ณผ์ / ์ฑ์ฅ ๊ณผ์ 1 (20.10.17 ์๋ฃ)
SignUpActivity ๋ง๋ค๊ธฐ / ํ๋ฉด ์ด๋ + @
-
๋ก๊ทธ์ธ ํ๋ฉด์์ "ํ์๊ฐ์ ํ๋ฌ๊ฐ๊ธฐ" ํด๋ฆญ ์ SignUpActivity๋ก ์ด๋
tv_signup.setOnClickListener { //ํ์๊ฐ์ ํ๋ฌ๊ฐ๊ธฐ val intent = Intent(this, SignUpActivity::class.java) startActivityForResult(intent, REQ_CODE) }
-
์ด๋ฆ / ์์ด๋ / ๋น๋ฐ๋ฒํธ ์ ๋ ฅ ํ ํ์๊ฐ์ ์งํ ( ํ๋๋ผ๋ ์ ๋ ฅ์ด ์๋์ด ์๋ ๊ฒฝ์ฐ ToastMessage ์ถ๋ ฅ ๐ฌ )
btn_signup.setOnClickListener { when { et_name.text.isNullOrBlank() -> Toast.makeText(this, "์ด๋ฆ์ ์ ๋ ฅํด์ฃผ์ธ์.", Toast.LENGTH_SHORT).show() et_id.text.isNullOrBlank() -> Toast.makeText(this, "์์ด๋๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์.", Toast.LENGTH_SHORT).show() et_password.text.isNullOrBlank() -> Toast.makeText(this, "๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์.", Toast.LENGTH_SHORT).show() else -> { Toast.makeText(this, "ํ์๊ฐ์ ์ ์ฑ๊ณตํ์์ต๋๋ค.", Toast.LENGTH_SHORT).show() val intent = Intent(this, LoginActivity::class.java) intent.putExtra("id", et_id.text.toString()) intent.putExtra("password", et_password.text.toString()) setResult(Activity.RESULT_OK, intent) finish() } } }
-
ํ์๊ฐ์ ์ฑ๊ณต ์ ์ด์ ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋ ( ํ์๊ฐ์ ์ ์ ๋ ฅํ ์์ด๋ / ๋น๋ฐ๋ฒํธ ์ ๋ ฅ๋ ์ํ )
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQ_CODE && resultCode == Activity.RESULT_OK) { et_id_login.setText(data!!.getStringExtra("id")) et_password_login.setText(data!!.getStringExtra("password")) finish() } }
โ๏ธ ์ฑ์ฅ ๊ณผ์ 2 (20.10.19 ์๋ฃ)
์๋ ๋ก๊ทธ์ธ
๐ ๊ฐ๋จํ ์ค์ ๊ฐ์ด๋ ๋ฌธ์์ด ๊ฐ์ ๋ฐ์ดํฐ๋ _SharedPreferences_๋ฅผ ์ฌ์ฉํด์ ๊ด๋ฆฌ ๋ฐ ์ฌ์ฉ ๊ฐ๋ฅ
-
SharedPreferences์ SharedPreferences์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ Editor ๊ฐ์ฒด ์์ฑ
var pref : SharedPreferences = getSharedPreferences("pref", Context.MODE_PRIVATE) var editor : SharedPreferences.Editor = pref.edit()
-
Editor๋ฅผ ์ฌ์ฉํด์ ํ์ผ์ ์์ด๋ / ๋น๋ฐ๋ฒํธ ์ ๋ณด ์ ์ฅ
editor.putString("id", et_id.text.toString()) editor.putString("password", et_password.text.toString()) editor.commit() //๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ์ญ์ ์ commit ํ์
-
SharedPreferences์ ์ ์ฅ๋ ๊ฐ ๊ฐ์ ธ์์ ์๋ ๋ก๊ทธ์ธ ์งํ
var pref: SharedPreferences = getSharedPreferences("pref", Context.MODE_PRIVATE) if (!(pref.getString("id", null).isNullOrBlank() || pref.getString("password", null).isNullOrBlank())) { val id = pref.getString("id", null).toString() //๊ฐ์ ๊ฐ์ ธ์ฌ ๋ ํ๋ผ๋ฏธํฐ๋ก key์ default๊ฐ์ ๋ฃ์ด์ค๋ค if (!id.isNullOrBlank()) { Toast.makeText(this, "${id}๋์ด ์๋๋ก๊ทธ์ธ ๋์์ต๋๋ค.", Toast.LENGTH_SHORT).show(); val intent = Intent(this, MainActivity::class.java) startActivityForResult(intent, REQ_CODE) } }
โ๏ธ ํ์ ๊ณผ์ (20.11.08 ์๋ฃ)
ํฌํธํด๋ฆฌ์ค Recyclerview ๋ง๋ค๊ธฐ
-
๋ฐ๋ณต๋ item view ์์ฑ - item_portpolio.xml
-
๋ฐฐ์น๋ฐฉํฅ ์ค์ - activity_portfolio.xml / PortfolioActivity.kt
-
data ํํ ๊ฒฐ์ - PortfolioData.kt
-
viewHolder ์์ฑ - PortfolioViewHolder.kt
๐ viewHolder๋ ๋ฐ๋ณต๋ item view ํ๋์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ ์์น ์ ๋ณด
-
adapter ์์ฑ - PortfolioAdapter.kt
-
recyclerView์ adapter ์ ์ฉ - PortfolioActivity.kt
portfolioAdapter = PortfolioAdapter(this) rcv_portfolio.adapter = portfolioAdapte
-
item ํด๋ฆญ ์ ์์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๊ธฐ ์ํ RecyclerView click event ์ฒ๋ฆฌ
( click event๋ฅผ adapter์์ ์ฒ๋ฆฌํ์ง ์๊ณ , activity (๋๋ fragment)์์ ์ฒ๋ฆฌํ๊ณ ์ ํ ๋์ ๋ฐฉ๋ฒ )
i ) adapter ๋ด์ custom click listener interface ์ ์
interface ItemClickListener { fun onItemClick(view: View, position: Int) }
ii ) listener ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ method์ ์ ๋ฌ๋ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ ๋ณ์ ์ถ๊ฐ
//listener ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๋ ๋ณ์ private lateinit var itemClickListener: ItemClickListener //ItemClickListener ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ adapter์ ์ ๋ฌํ๋ method fun setItemClickListener(itemClickListener: ItemClickListener) { this.itemClickListener = itemClickListener }
iii ) item view์ click listener๋ฅผ ์ฐ๊ฒฐ
override fun onBindViewHolder(holder: PortfolioViewHolder, position: Int) { holder.onBind(data[position]) holder.itemView.setOnClickListener{ itemClickListener.onItemClick(it, position) } }
iv ) activity (๋๋ fragment)์์ custom listener ๊ฐ์ฒด ์์ฑ ๋ฐ ์ ๋ฌ
portfolioAdapter.setItemClickListener(object : PortfolioAdapter.ItemClickListener { override fun onItemClick(view: View, position: Int) { val clickedPortfolioIntent = Intent(view.context, PortfolioDetailActivity::class.java) startActivity(clickedPortfolioIntent) })
๐ data๊ฐ ์์ผ๋ฉด adapter๊ฐ data list ์ค ํ๋๋ฅผ viewHolder์๊ฒ ์ ๋ฌํ๊ณ viewHolder๋ ์ ๋ฌ ๋ฐ์ data๋ฅผ view์ ๋ฟ๋ ค์ค๋ค
โ๏ธ ์ฑ์ฅ ๊ณผ์ 1 (20.11.16 ์๋ฃ)
GridLayout ๋ง๋ค๊ธฐ
๐ menu์์ LinearLayout ํด๋ฆญ ์ ๋ฐฐ์น ๋ฐฉํฅ -> Linear / GridLayout ํด๋ฆญ ์ ๋ฐฐ์น ๋ฐฉํฅ -> Grid
-
๋ฐฐ์น ๋ฐฉํฅ ์ ํ์ ์ํ menu ์์ฑ
i ) res ํด๋ ์์ menu directory ์์ฑ ํ menu directory ์์ xml ํ์ผ ์์ฑํด์ menu item ์ค์
ii ) option menu ์ง์ ์ ์ํด onCreateOptionsMenu() ์ฌ์ ์
override fun onCreateOptionsMenu(menu: Menu?): Boolean { val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.layout, menu) return true }
-
Grid ๋ฐฉํฅ์ ์ํ ์๋ก์ด layout ์์ฑ
-
adapter์์ viewType์ ๋ฐ๋ผ inflate๋๋ view๋ฅผ ์ง์
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PortfolioViewHolder { var view = when (viewType) { 1 -> { LayoutInflater.from(context).inflate(R.layout.item_portfolio, parent, false) } else -> { LayoutInflater.from(context).inflate(R.layout.item_portfolio_grid, parent, false) } } return PortfolioViewHolder(view) } override fun getItemViewType(position: Int): Int { return viewType }
-
activity์์ ์ ํ๋๋ menu item์ ๋ฐ๋ผ viewType๊ณผ LayoutManager๋ฅผ ์ง์
override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item?.itemId) { R.id.menu_linear -> { portfolioAdapter.viewType = 1 rcv_portfolio.layoutManager = LinearLayoutManager(this) } R.id.menu_grid -> { portfolioAdapter.viewType = 2 rcv_portfolio.layoutManager = GridLayoutManager(this, 3, RecyclerView.VERTICAL, false) } } return super.onOptionsItemSelected(item) }
โ๏ธ ํ์ ๊ณผ์ (20.11.30 ์๋ฃ)
BottomNavigation + ViewPager + TabLayout ์ฌ์ฉํด์ ํ๋กํ view ๊ตฌํํ๊ธฐ
BottomNavigation + ViewPager
-
res ํด๋ ์์ menu directory ์์ฑ ํ menu directory ์์ xml ํ์ผ ์์ฑํด์ menu item ์ค์ - navigation.xml
-
res ํด๋ ์์ color directory ์์ฑ ํ color directory ์์ xml ํ์ผ ์์ฑํด์ icon selector ์ค์ - selector_nav.xml
-
๋ฐฐ์น ์ค์ - activity_main.xml
-
viewPager adapter ์์ฑ - MainPagerAdapter.kt
class MainPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT){ override fun getItem(position: Int): Fragment { return when(position) { 0 -> ProfileFragment() //index๊ฐ 0์ผ๋ 1 -> LinearFragment() else -> GridFragment() } } override fun getCount() = 3 }
-
viewPager์ adapter ์ ์ฉ - MainActivity.kt
viewPager_main.adapter = MainPagerAdapter(supportFragmentManager)
-
viewPager์ ํ๋ฉด์ ํ์ ๊ฐ์งํ๋ listener ์ค์ - MainActivity.kt
viewPager_main.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { // viewPager์ ์ด๋ -> ํ๋จ ํญ์ ์ฒดํฌ ์ํ ๋ณํ override fun onPageScrollStateChanged(state: Int) { } override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { } override fun onPageSelected(position: Int) { // navigation ๋ฉ๋ด ์์ดํ ์ฒดํฌ main_bottomNavigation.menu.getItem(position).isChecked = true } })
-
bottomNavigation item ํด๋ฆญ ์ ํด๋ฆญ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ listener ์ค์ - MainActivity.kt
main_bottomNavigation.setOnNavigationItemSelectedListener { // ํ๋จ ํญ์ ์ฒดํฌ ์ด๋ฒคํธ -> ํด๋นํ๋ ํ์ด์ง๋ก ์ด๋ var index by Delegates.notNull<Int>() when (it.itemId) { R.id.nav_profile -> index = 0 R.id.nav_linear -> index = 1 R.id.nav_grid -> index = 2 } viewPager_main.currentItem = index true }
TabLayout
-
๋ฐฐ์น ์ค์ - fragment_profile.xml
-
viewPager adapter ์์ฑ - ProfilePagerAdapter.kt
-
viewPager์ adapter ์ ์ฉ - ProfileFragment.kt
-
tabLayout์ ViewPager ์ฐ๋ - ProfileFragment.kt
tabLayout_profile.setupWithViewPager(viewPager_profile)
-
tab title ์ค์ - ProfileFragment.kt
๐ ๋ฐ๋์ viewPager์ ์ฐ๋ ํ ์์ฑํด์ผํ๋ค
tabLayout_profile.apply { getTabAt(0)?.text = "INFO" getTabAt(1)?.text = "OTHER" }
โ๏ธ ํ์ ๊ณผ์ (20.12.03 ์๋ฃ)
๋ก๊ทธ์ธ/ํ์๊ฐ์ ์๋ฒ ํต์ ๊ตฌํํ๊ธฐ
-
Request/Response ๊ฐ์ฒด ์์ฑ
-
SignUpRequest.kt
data class SignUpRequest ( val email: String, val password: String, val userName: String )
-
SignUpResponse.kt
data class SignUpResponse( val data: Data, val status: Int, val success: Boolean, val message: String ) { data class Data( val email: String, val password: String, val userName: String ) }
-
SignInRequest.kt
data class SignInRequest( val email: String, val password: String )
-
SignInResponse.kt
data class SignInResponse( val data: Data, val status: Int, val success: Boolean, val message: String ) { data class Data( val email: String, val password: String, val userName: String ) }
-
-
retrofit interface ์์ฑ - SoptService.kt
interface SoptService { @Headers("Content-Type:application/json") @POST("/users/signup") fun signup( @Body body: SignUpRequest ): Call<SignUpResponse> @Headers("Content-Type:application/json") @POST("/users/signin") fun signin( @Body body: SignInRequest ): Call<SignInResponse> }
-
๊ตฌํ์ฒด ์์ฑ - SoptServiceImpl.kr
object SoptServiceImpl { // ์ฑ๊ธํค์ผ๋ก ๋ง๋๋ ์ค์ ๊ตฌํ์ฒด // -> ๊ฐ์ฒด๋ ํ๋๋ง ์์ฑํ๊ณ ํ๋ก์ ํธ ์ด๋์๋ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ๋์์ธ ํจํด // object: ์ฑ๊ธํค ๊ฐ์ฒด๋ก ์ฌ์ฉํ๊ธฐ ์ํด object๋ก ์ ์ธ private const val BASE_URL = "http://15.164.83.210:3000" private val retrofit: Retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) //gson ์ฐ๋: retrofit์์ ๋ฐ์์ค๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ฝ๊ฒ ๋ณํ .build() // Retrofit ๊ฐ์ฒด ์์ฑ val service: SoptService = retrofit.create(SoptService::class.java) // Interface ๊ฐ์ฒด๋ฅผ ๋๊ฒจ ์ค์ ๊ตฌํ์ฒด ์์ฑ }