-
Notifications
You must be signed in to change notification settings - Fork 4
๐ง๐ปโ๐ป Conventions
- Fragment ๋๋ Activity ์ฝ๋ ์ต์ํ๋ฅผ ์ํ ๋ฐ์ดํฐ๋ฐ์ธ๋ฉ ์งํฅ
- ๋ฆฌ์ฌ์ดํด๋ฌ ๋ทฐ ์์ดํ
์ ๋ฐ์ดํฐ ํด๋์ค๋ย
XxxItem
, xml์ ๋ฐ์ธ๋ฉ ๋ณ์๋ยitem
ย ์ฌ์ฉ - xml viewModel ๋ฐ์ธ๋ฉ ๋ณ์๋
viewModel
- ๊ธฐ๋ณธ ํ์:ย
[what]\_[where]\_[des]
ย ex) tv_addCalendar_titleHeader- ์น์ ์ ํ์คํ๊ฒ ๊ตฌ๋ถํ ์ ์๋ค.
- ์ธ๋๋ฐ๋ก ๊ตฌ๋ถ๋์ด ์ํ๋ ์ ๋ณด๋ฅผ ๊ณจ๋ผ ์ฝ๊ธฐ ํธํ๋ค.
- des๋ฅผ ์ฝ์ ๋์๋ ๊ตฌ๋ถํด์ ์ฝ์ ์ผ์ด ์๋ค.
- ๊ฐ ์ ์์ ๋ ๋จ์ด ์ด์์ด ํผ์ฉ๋ ๋๋ camel case๋ก ์์ฑ.
- ์นด๋ฉ ์ผ์ด์ค๋ก ๊ตฌ๋ถ๋์ง ์๋ ๋ทฐ(switch, toolbar, ...)๋ ํ ๋ค์์ ์ฌ์ฉ.
- ์ ๋์ฌ๋ simple style(textView -> tv)
Prefix | ํ๋ค์ |
---|---|
layout | LinearLayout, ConstraintLayout,include ... |
custom | CustomView |
tv | TextView |
btn | Button |
img | ImageView |
rv | RecyclerView |
cb | CheckBox |
cg | CheckGroup |
switch | Switch |
view | View |
toolbar | Toolbar |
๊ทธ ์ธ | CamelCase ์๊ธ์ ๋ฐ์ ์ง๊ธฐ |
์ฐธ๊ณ :ย ํค์ด๋๋ฌ drawable ๊ฐ์ด๋
<WHAT>(_<WHERE>)_<DESCRIPTION>(_<SIZE>)
- ์ด๋ฏธ์ง๊ฐ ์ฌ๋ฌ๊ตฐ๋ฐ์์ ํ์ฉ๋ ๊ฒฝ์ฐ,ย
<WHERE>
๋ ์๋ต ๊ฐ๋ฅํ๋ค. - ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ 1๊ฐ๋ฐ์ ์๋ ๊ฒฝ์ฐ,ย
<SIZE>
๋ ์๋ต ๊ฐ๋ฅํ๋ค.
What
Prefix | ์ค๋ช |
---|---|
btn_ | ๋ฒํผ์ผ๋ก ์ฐ์ด๋ ์ด๋ฏธ์ง |
ic_ | ์์ด์ฝ, ๋ฒกํฐ์ ์ฌ์ฉํ๋ ์ด๋ฏธ์ง |
bg_ | ๋ฒํผ์ด ์๋ ํ๋ฉด์ ๋ณด์ฌ์ง๋ ์ด๋ฏธ์ง |
img_ | ์ค์ ์ฌ์ง์ด๊ฑฐ๋ ์์ด์ฝํํ๊ฐ ์๋ ์ผ๋ฌ์คํธํํ์ ์ด๋ฏธ์ง |
div_ | divider๋ก ํ์ฉ๋๋ ์ด๋ฏธ์ง |
color_ | color selector |
Selector
- ๋ฐฐ๊ฒฝ์ด๋ ๋ฒํผ์์ View์ ์ํ์ ๋ฐ๋ผ์ drawable์ด ๋ณํด์ผ ํ๋ ๊ฒฝ์ฐ์ ๋ํ ์ด๋ฆ์ ์๋์ ๊ฐ๋ค.
์ํ | Suffix |
---|---|
Normal | _normal |
Pressed | _pressed |
Focused | _focused |
Disabled | _disabled |
Selected | _selected |
Activated | _activated |
Background
- ๋ฐฐ๊ฒฝ์์ด pressed์ํ์ ๋ฐ๋ผ์ white -> sky_blue๋ก ๋ณํ๋ ๊ฒฝ์ฐ๋ย
bg_white_to_sky_blue.xml
๋ก ํ๋ค. - ๋ฐฐ๊ฒฝ์ด white์์ 24dp๋ก ํ
๋๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ๋ ๊ฒฝ์ฐ๋ย
bg_white_radius_24dp.xml
๋ก ํ๋ค. - ๋ฐฐ๊ฒฝ์ด ํฌ๋ช
ํ๋ฉฐ ๋ฐฐ๊ฒฝ์ ์ ๋ง์ sky_blue์์ 8dp๋ก ํ
๋๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ๋ ๊ฒฝ์ฐ๋ย
bg_stroke_sky_blue_radius_8dp.xml
๋ก ํ๋ค. -
์์
- btn_call_normal.png: ์ ํ๊ฑธ๊ธฐ ๋ฒํผ ์ด๋ฏธ์ง
- btn_call_pressed.png: ์ ํ๊ฑธ๊ธฐ ๋ฒํผ ๋๋ ธ์๋์ ์ด๋ฏธ์ง
- btn_call.xml: ์ ํ๊ฑธ๊ธฐ ๋ฒํผ ์ด๋ฏธ์ง์ selector xml
- ic_dealer_gift.png: ๋๋ฌ๊ฐ ๋ณด๋ด์ค ๊ธฐํํฐ์ฝ์ ๋ณด์ฌ์ค๋ ํ์๋๋ ์ด๋ฏธ์ง
- img_splash_chart.png: ์คํ๋์ ํ๋ฉด์์ ๋ณด์ฌ์ง๋ ์ฐจํธ ์ด๋ฏธ์ง
-
item_<what>
: ๋ฆฌ์ฌ์ดํด๋ฌ ๋ทฐ ์์ดํ ๋ ์ด์์์ ์ฌ์ฉ -
view_<what>
: ์ปค์คํ ๋ทฐ ๋ ์ด์์์ ์ฌ์ฉ
Color
<!--color ๋ฆฌ์์ค ์ ๋ฆฌ-->
<color name="light_gray">#E4E4E4</color>
<color name="gray">#8D8D8D</color>
<color name="gray_alpha_30">#30000000</color>
<!--์ ๋ณ์ wHeRe_wHAt. ์ฌ๋ฌ ๊ณณ์์ ์ฌ์ฉ๋๋ค๋ฉด where ์๋ต ๊ฐ๋ฅ.-->
<color name="saveSchedule_titleText">@color/light_gray</color>
<color name="yearCalendarView_titleText">@color/gray</color>
<color name="close_background">@color/gray_alpha_30</color>
description์ ํ ๋ง ์์ฑ์ผ๋ก ๋ถ๋ฆฌ
<item name="titleTextColor">@color/yellow_500</item>
๋ ์ด์์์์ ์ฌ์ฉ์ ํ ๋ง ์์ฑ์ ์ฐธ์กฐ
style="@style/Theme.titleTextColor"
Mnemonic ์ฌ์ฉ
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ margin/padding 16dp
= โ์ผ๋ฐ ์น์ ํฌ๊ธฐ์ 100% ์ฌ์ฉโ
<dimen name="small_25">2dp</dimen>
<dimen name="small_50">4dp</dimen>
<dimen name="small_100">8dp</dimen> <!-- 50% of normal = 8dp -->
<dimen name="normal_100">16dp</dimen> <!-- 100% of normal = 16dp -->
<dimen name="normal_125">20dp</dimen> <!-- 125% of normal = 16dp + 4dp = 20dp -->
<dimen name="normal_150">24dp</dimen>
<dimen name="normal_175">28dp</dimen>
<dimen name="large_100">32dp</dimen> <!-- large_100 = 2 x normal_100 -->
<dimen name="large_125">40dp</dimen>
<dimen name="large_150">48dp</dimen>
<dimen name="large_175">56dp</dimen>
<dimen name="large_200">64dp</dimen>
์ผ๋ฐ ์น์์ ๋นํด ํจ์ฌ ํฐ dimensions์ ๊ฒฝ์ฐ
- ๊ธฐ๋ณธ ํ์ :
[what]_[where]_[des]_[size]
ex) keyline_all_text
<dimen name="size_selectVideo_player">64dp</dimen>
<WHAT>
Prefix | Usage |
---|---|
width | width in dp |
height | height in dp |
size | if width == height |
margin | margin in dp |
padding | padding in dp |
elevation | elevation in dp |
keyline | absolute keyline measured from view edge in dp |
textsize | size of text in sp |
Android - Dimensions by Conventions
- ์นด๋ฉ์ผ์ด์ค
- ๊ธฐ๋ณธ ํ์:ย
[des][View]
ย ex) customText
<style name="selectVideoOptionImage" parent="Widget.AppCompat.ImageButton">
<item name="android:layout_width">@dimen/large_125</item>
<item name="android:layout_height">@dimen/large_125</item>
<item name="elevation">@dimen/small_25</item>
<item name="android:padding">@dimen/small_100</item>
</style>
Style resource | Android Developers
๋จ์ด์ ์ฒซ ๊ธ์๋ง upper case
class Person
class User
1 ๋ 1 ๊ด๊ณ๋ฉด viewModel
1๋1 ๋ค ๊ด๊ณ๋ฉด ํ๋ค์
val viewModel: AddTaskViewModel by viewModels()
val activityViewModel: MainViewModel by viewModels()
val addTakAdapter = AddTaskAdapter()
์ฝํ๋ฆฐ ๊ณต์ ๋ฉ์๋ ๋ค์ด๋ฐ
์ฒซ ๋จ์ด๋ฅผ ์ ์ธํ ๋จ์ด๋ถํฐ ๋จ์ด์ ์ฒซ ๊ธ์๋ง upper case
๋์ฌ ํน์ ๋์ฌ๊ตฌ(๋์ฌ๋ก ์์)
fun getPersonId() {}
fun getUserId() {}
- ํ๋กํผํฐ
- ์์ฑ์
- init
- onCreate
- onCreateView
- ํจ์
- onDestroy
- companion object
interface Example{
// ๋๊ธฐ
fun A()
fun B()
fun C()
// ๋๊ธฐ
}
class D(
a,
b,
c // 140 space ๋ง์ถฐ์ (Arrange Option ๋ณ๊ฒฝํ๊ธฐ)
) : B {
// ๋๊ธฐ
private val _binding
private val binding = get() = _binding
private val viewModel by viewModels{}
private lateinit var
private val a = 3
init {
}
override onCreate()
private fun()
override onDestroy()
inner class C() {
}
companion object {
}
}
//single Event
class Adapter(val onClick : (String) -> Unit)
//Multiple Event
class Adapter(val onClick : MinSeokOnClickListener)
fun interface MinSeokOnCLickListener {
fun onClick(str : String)
fun onLongClick(str : String)
}
val onclickListener = object: MinSeokOnCLickListener {
fun onClick(str : String) {
}
fun onLongClick(str : String) {
}
}
Adapter(onclickListener)
Adapter(::onClick) // 3์ค ์ด์ ๋ถ๋ฆฌ
Adapter {
Log.d("asd", it)
} // 2์ค ์ด๋ด ์ฌ์ฉ
[What]Type
NetworkState(= retrofit Result) MultipleViewType
apply, also, with, let, run
- Scope ์ค์ฒฉ ์ง์(์ต๋ 2์ค์ฒฉ)
- it ์ง์ (๋ค๋ฅธ ์ด๋ฆ์ผ๋ก ์ ์ธํด์ ์ฐ๊ธฐ)
๋น๋๊ธฐ ํจ์
- fetch: Read
- post : Write view(viewModel.fetchData) -> viewModel(repo.fetchData) -> repo(source.fetchData)
์ถ๊ฐ
- add: list ์์ ๋ฃ์ ๋
- create: ์๋ก ์์ฑ
์กฐํ
- get: any
- find: nullable any
- is, has: boolean
ํ๋ฉด์ ํ
- show[Dialog]
- start[Activity]
- navigate[Fragment]
ํ๋ฉด ๊ฐฑ์
- show
- invalidate
else if ์ฌ์ฉ ๊ธ์ง -> when์ผ๋ก ๋ณํ else๋ ์ง์ ๊ณ ๋ ค ์ค๊ดํธ ๋ฌด์กฐ๊ฑด ์ฐ๊ธฐ
// ์ค๊ดํธ ํ์คํ ์ฌ์ฉํ๊ธฐ
if (true) {
foo()
} else {
bar()
}
// else ์ง์
โฌ๏ธ
bar()
if (true) {
foo()
}
// ์๋ ์ ๋ ฌ ์ฌ์ฉํ๊ธฐ
when {
aaa -> {
}
bbb -> {
}
}
// 2์ค ์ด์์ ์ค๊ดํธ ๋ด์์, 1์ค์ ์ค๊ดํธ x
when {
aaa -> foo()
bbb -> bar()
}
// early return
// else ๋ฌธ์ ๋ฏธ๋ฆฌ when ์์ ๋นผ์ return ์ํค๊ธฐ (else block์์ ์ฒ๋ฆฌํ ๊ฒ์ด ์์ ๋)
val xxx = ... ?: return
when(target) {
aaa -> {}
bbb -> {}
}
ShoppingFragment -> ShoppingDetailFragment
// 1. ShoppingFragment with Safe Args
override fun navigateToShoppingDetail(shoppingItemInfo: ShoppingItemInfo) {
val navAction = ShoppingFragmentDirections.actionShoppingFragmentToDetailFragment(shoppingItemInfo)
findNavController().navigate(navAction)
}
// 2 ShoppingDetailFragment
class ShoppingDetailFragment : Fragment(), ShoppingItemOnClickListener {
private val args: ShoppingDetailFragmentArgs by navArgs()
private val shoppingItemInfo : ShoppingItemInfo by lazy { args.shoppingItemInfo }
override fun onCreateView(...){...}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d("shoppingItemInfo",shoppingItemInfo.toString()) // ์ฌ์ฉ
}
resource -> ํ๋ฉด์ ๋ณด์ด๋๊ฐ๋ฅผ ๊ธฐ์ค์ผ๋ก string.xml์ ๋ถ๋ฆฌ ๊ฒฐ์
- ex: EXTRA_TITLE_ID = "title_id" ์์ ๋ค์ด๋ฐ์ upper snake case
์๋ฏธ ์๋ ์ซ์, ๋ฌธ์์ด์ companion์ const val ์ ์ธ
- ex: LOOP_COUNT = 10
- fromย โญ
- ํ๊ตญ์ด, snake case
instrument ok
fun `์ผ์ ์_์๋ชป_๊ฐ์ ธ์ฌ_๋`()
Issue #<number> type: subject
body(option)
footer(option)
- feat:ย ์๋ก์ด ๊ธฐ๋ฅ
- fix:ย ๋ฒ๊ทธ ์์
- docs:ย README, gitignore ์ฃผ์ ์์
- refactor:ย ์ฝ๋ ๋ฆฌํฉํฐ๋ง
- test:ย ํ ์คํธ ์ฝ๋๊ฐ ์ถ๊ฐ๋๊ฑฐ๋ ๋ฆฌํฉํฐ๋ง ์ ์ฌ์ฉํ๋ฉฐ ํ๋ก๋์ ์ฝ๋๋ ๋ณ๊ฒฝ๋์ง ์๋๋ค.
- chore:ย ํ๋ก์ ํธ ํ๊ฒฝ์ค์ ๋ณ๊ฒฝ, ๋น๋ ๊ตฌ์ฑ ๋ณ๊ฒฝ ๋ฑ์ ์ฌ์ฉ๋๋ฉฐ ํ๋ก๋์ ์ฝ๋๋ ๋ณ๊ฒฝ๋์ง ์๋๋ค.
- res
โ ์๋ฌธ์:
- 50์ ์ด๋ด
- ๊ตฌ์ด์ฒด/๋ฌธ์ฅํ X, ๋ช ๋ นํ์ผ๋ก ์์ฑ
- ๋ง์นจํ ์ฌ์ฉ ๋ถ๊ฐ
- ์๋ต ๊ฐ๋ฅ
- 72์ ์ด๋ด
- ์ด๋ค(What) ์์ ์ธ์ง, ์์ ์ ๋ชฉ์ (Why)์ ๋ํด ์์ฑ. ์์ ์ ํด๊ฒฐํ ๋ฐฉ์(How)์ ์์ฑ X
- Issue Tracker ID ํ์
- Issue Tracker ์
- Fixes: ์ด์ ์์ ์ค (์์ง ํด๊ฒฐ๋์ง ์์ ๊ฒฝ์ฐ)
- Resolves: ์ด์๋ฅผ ํด๊ฒฐํ์ ๋ ์ฌ์ฉ
- Ref: ์ฐธ๊ณ ํ ์ด์๊ฐ ์์ ๋ ์ฌ์ฉ
- Related to: ํด๋น ์ปค๋ฐ์ ๊ด๋ จ๋ ์ด์๋ฒํธ (์์ง ํด๊ฒฐ๋์ง ์์ ๊ฒฝ์ฐ)
๋ผ๋ฒจ ๋ฌ๊ธฐ(chore, bug, fix, feature, docs, help wanted, wrong, question)
- project๋ฌ๊ธฐ
- Milestone ๋ฌ๊ธฐ
- asignees ์ง์
# PR ๋ด์ฉ
...์์
๋ด์ฉ...
# ์งํ ์ํฉ
...์ฒดํฌํฌ์ธํธ...
์ฐธ๊ณ url
Mnemonic ์ฌ์ฉ
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ margin/padding 16dp
= โ์ผ๋ฐ ์น์ ํฌ๊ธฐ์ 100% ์ฌ์ฉโ
<dimen name="small_25">2dp</dimen>
<dimen name="small_50">4dp</dimen>
<dimen name="small_100">8dp</dimen> <!-- 50% of normal = 8dp -->
<dimen name="normal_100">16dp</dimen> <!-- 100% of normal = 16dp -->
<dimen name="normal_125">20dp</dimen> <!-- 125% of normal = 16dp + 4dp = 20dp -->
<dimen name="normal_150">24dp</dimen>
<dimen name="normal_175">28dp</dimen>
<dimen name="large_100">32dp</dimen> <!-- large_100 = 2 x normal_100 -->
<dimen name="large_125">40dp</dimen>
<dimen name="large_150">48dp</dimen>
<dimen name="large_175">56dp</dimen>
<dimen name="large_200">64dp</dimen>
์ผ๋ฐ ์น์์ ๋นํด ํจ์ฌ ํฐ dimensions์ ๊ฒฝ์ฐ
- ๊ธฐ๋ณธ ํ์ :
[what]_[where]_[des]_[size]
ex) keyline_all_text
<dimen name="size_selectVideo_player">64dp</dimen>
Prefix | Usage |
---|---|
width | width in dp |
height | height in dp |
size | if width == height |
margin | margin in dp |
padding | padding in dp |
elevation | elevation in dp |
keyline | absolute keyline measured from view edge in dp |
textsize | size of text in sp |
[Android - Dimensions by Conventions](https://medium.com/@june.pravin/dimensions-by-conventions-92b422e2216e)
- ์นด๋ฉ์ผ์ด์ค
- ๊ธฐ๋ณธ ํ์:ย
[des][View]
ย ex) customText
<style name="selectVideoOptionImage" parent="Widget.AppCompat.ImageButton">
<item name="android:layout_width">@dimen/large_125</item>
<item name="android:layout_height">@dimen/large_125</item>
<item name="elevation">@dimen/small_25</item>
<item name="android:padding">@dimen/small_100</item>
</style>
[Style resource | Android Developers](https://developer.android.com/guide/topics/resources/style-resource)