ืื ื ืืกืคืจืื ืืื ืืืฆื ืืืฆืืจ ืืคืืืงืฆืื ืคืฉืืื ืืืืฉืื ืืืคืื ืืงืืืืื. ืืืชืจ ืืืืง, ืงืืืืื 1.3.21, ืื ืืจืืืื 4, ืื ืืจืืืื ืกืืืืื 3. ืืืืืจ ืืืื ืืขื ืืื, ืงืืื ืื, ืืื ืฉืืชืืื ืืช ืืจืื ืืคืืชืื ืืคืืืงืฆืืืช ืื ืืจืืืื. ืื ืืืคืฉืจ ืื ืืืืื ืื ืืืื ืื ืขืืื ืืชืื ืืืคืืืงืฆืื.
ืืืฉืืื ืื ืืืื ืฉืืืืฉื ืืืฉืจ ืชืฆืืจืื ืืืฉื ืืช ืืืืช ืืืืคืื ืืืืจื ืฉืืืืืื ืืืืืช ืืืกืขืื ืื ืืืช ืงืคื. ืืืืื ืฉืื ืชืืื ืืืื ืืฉืืืจืื ืืืค ืืืืฆืจืื, ืื ืืืชืจ ืืกืืจืช ืืขืจืืืช, ืืื ืืชืืืื ืฉื ืคืืชืื ืืคืืืงืฆืื ืืื ืืขื ืืื ืืื ืืงืจื.
ืื ื ืืืืืจืื: ืืื ืงืืจืื Habr - ืื ืื ืฉื 10 ืจืืื ืืขืช ืืจืฉืื ืืื ืงืืจืก Skillbox ืืืืฆืขืืช ืงืื ืืืืื ืฉื Habr.
Skillbox ืืืืืฆื: ืงืืจืก ืืขืฉื
"ืืคืชื ืกืืืืจื PRO .
ืื ื ืจืืืช ืืืคืืืงืฆืื ืืคืขืืื:
ืืื ืืกืื ืืช ืืืืื ืืจืฆืื ืืืกืืื ืืืืื, ืืช ืืกืคืจ ืืืฉืชืชืคืื ืืืคืืฉ ืืืงืืืื ืืช ืืชืืฆืื - ืืืืช ืืืืค ืฉืืืื ืืืฉืืืจ.
ืชืืืืช ืืขืืืื
ืืืฉืง ืืืืฉืื ืืืื ื ืจืื ืื:
ืคืขืืื ืจืืฉืื ื -
ืคืขืืืืช ืืืฉืชืืฉ ื ืืชืืืช ืืคืจืืืงื ืืกืืจ ืืจืื ืืืืื ืืื ืืืืืืจ ืืื. ืืื ืืฆืคืืช ืื, ืคืชื ืืช View -> Tool Windows -> TODO.
ืื ื ืืืืืื ืืช ืืคืจืืืงื ืืคืืชืืื ืืช colors.xml ืืื ืืืขืจืื ืืช ืืื ืืฆืืขืื. strings.xml ืืืื ื ืชืื ื ืืงืกื (ืืชืืืืช), ื-styles.xml ืืืื ืืกืคืจ ืชืื ืืืช ืืืคื ืื.
ืคืืชืื ืืืืจ ืขืืืช
ืคืชื ืืช activity_main.xml ืืืืกืฃ ืืช ืืงืื ืืืื ื-LinearLayout (#1):
<TextView
android_id="@+id/expensePerPersonTextView"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_paddingTop="30dp"
style="@style/h1Bold"
android_textColor="@color/colorAccent"
android_text="0"/>
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_paddingBottom="25dp"
style="@style/h2"
android_textColor="@color/colorAccent"
android_text="@string/perPersonStaticText"/>
ืขืืฉืื ืืชื ืืืื ืืกืื ื ืืช ืกืคืจืืืช ืืขืจืืื ืื ืืฉืืง ืขื ืฆืืขืื ืืืืฆืขืืช
ืืขืช ืืคืจืืืงื ื ืจืื ืื:
ืืคื ืฉืืชื ืืืื ืืจืืืช, ืืขืืืืืช ืืืืฉืืืช ืขื ืกืื ืื ืชืื ืื ืฉืืืื ืืืฉืชืืฉ.
ืคืืชืื ืืืืจ ืืืฉืืื ืืช
ืืืกืฃ ืืช ืืงืื ืืืื ื-LinearLayout ืืืืจ ืกืขืืฃ ืืืืฆืืืช (#2):
<LinearLayout
android_layout_width="match_parent"
android_layout_height="match_parent"
android_orientation="vertical"
android_background="@color/colorAccent">
<! โ TODO #3: Build Bill Section โ
โฆ
</LinearLayout>
ืื ื ืกืืืจืื ืืช ื-LinearLayout ืืืืจ ืจืฉืืืช ื-TODOs, ืืืืืจ ืืื ืืืกืืคืื ืงืื ืืืฉ, ืืืืงืืื ืืืชื ืืชืื ื-LinearLayout (#3):
<TextView
android_layout_margin="15dp"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
style="@style/h4"
android_text="@string/billStaticText"/>
<EditText
android_id="@+id/billEditText"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
android_inputType="numberDecimal"
android_maxLines="1"
style="@style/h2Bold"
android_text="0"/>
ืืืืืื ืฉืืืฉืืื ืืขืืงืจืืช ืฉื ืืืคืืืงืฆืื ืืื ืืืฉื ืขืืืืืช ืืืฉืืืช ืขืืืจ ืื ืืฉืชืชืฃ ืืืคืืฉ ืืกืขืื, costPerPersonTextView ืืืืืช ืืช ืืชืคืงืื ืืขืืงืจื.
EditText ืืืืื ืืช ืืงืื ืืฉืืจื ืืืช, ืคืจืืืจ ืื ืืืื ืืืืืช ืืืืืจ ื- NumberDecimal inputType.
ืื ื ืืฉืืงืื ืืช ืืคืจืืืงื ืืืืืงื ืืืื ืืกืื ืืช ืืคืจืืืจืื ืื ืืง ืืืื (ืืืกืืช, ืฆืืืืช ืฉืืืจืืช ืืื')
ืคืืชืื ืืืืจ "ืื ืฉืื ืืืืคืื".
ืืื ืืืืกืืฃ ืืืืจืช ื ืคื ืืืค, ืืืืง ืืช ืืงืื ืืืื ืืงืืข LinearLayout ืืืืฉ (#4):
<TextView
android_layout_margin="15dp"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
style="@style/h4"
android_text="@string/tipStaticText"/>
<LinearLayout
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_orientation="horizontal">
<ImageButton
android_id="@+id/subtractTipButton"
style="@style/operationButton"
android_layout_marginLeft="20dp"
android_layout_marginStart="20dp"
android_src="@drawable/subtract"/>
<TextView
android_id="@+id/tipTextView"
android_layout_margin="15dp"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
android_layout_weight="1"
style="@style/h2Bold"
android_text="20%"/>
<ImageButton
android_id="@+id/addTipButton"
style="@style/operationButton"
android_layout_marginEnd="20dp"
android_layout_marginRight="20dp"
android_src="@drawable/add"/>
</LinearLayout>
ืืืง ืื ืฉื ืืงืื ืืืจืื ืืื ืืืฉื ืืืืืืง ืืช ืกืืื ืืืืค. ืขืจื ืืืงืกื ืืืืืืจ ืืืจืืจืช ืืืื ืืื 20. ืืืฆื ื Image ืืกืืคืงืื ืขื ืกืืืื ืืชืืงืืื ืขื ืืจืฉืืืช ืืชืืื.
ืืขืชืง ืืช ืืงืืข ืืืืืืื ืืืืกืฃ ืืช ืืืืจืื ืืืืื (#5):
- ืืืื ImageButton (ืืคืืชืชPeopleButton, addPeopleButton)
- TextView ids(numberOfPeopleStaticText, numberOfPeopleTextView)
- DefaultText ืขืืืจ numberOfPeopleTextView (ืืืื ืืืืืช 4).
ืืขืช, ืืืฉืจ ืืชื ืืคืขืื ืืช ืืืคืืืงืฆืื, ืืฉ ืืืืื ืืช ืืืืกืืฃ ืืช ืกืืื ืืืฉืืื ืืช, ืื ืืคืชืืจื "ืืืกืฃ/ืืืกืืจ" ืคืืขืืื, ืื ืขืืืื ืื ืงืจื ืืืื.
ืืืกืคืช ืชืฆืืืืช
ืคืชื ืืช MainActivity.kt ืืืืกืฃ ืืช ืื ืืคืื ืงืฆืื initViews (#6):
private fun initViews() {
expensePerPersonTextView = findViewById(R.id.expensePerPersonTextView)
billEditText = findViewById(R.id.billEditText)
addTipButton = findViewById(R.id.addTipButton)
tipTextView = findViewById(R.id.tipTextView)
subtractTipButton = findViewById(R.id.subtractTipButton)
addPeopleButton = findViewById(R.id.addPeopleButton)
numberOfPeopleTextView = findViewById(R.id.numberOfPeopleTextView)
subtractPeopleButton = findViewById(R.id.subtractPeopleButton)
//TODO #8: Bind Buttons to Listener
//TODO #16: Bind EditText to TextWatcher
}
ืืกืืื ืืช ืืืคืชืืจืื
ืืื ืืืืกืืฃ ืชืืืื ืืืืืฆืืช ืืคืชืืจืื, ืื ื ืืืืฉืืื ืืช View.OnClickListener ืืจืืช ืืืืชื (#7):
class MainActivity: AppCompatActivity(), View.OnClickListener {
ืื ื ืืชื ืืืื ืืืจืืื ืืช ืืคืจืืืงื ืืขืช; ืขืืื ืืืฆืข ืืกืคืจ ืฉืืืื ื ืืกืคืื (#8):
override fun onClick(v: View?) {
when (v?.id) {
R.id.addTipButton -> incrementTip()
R.id.subtractTipButton -> decrementTip()
R.id.addPeopleButton -> incrementPeople()
R.id.subtractPeopleButton -> decrementPeople()
}
}
ืืืืื ืช ืืคืชืืจืื ืืืชืืื, ืงืืืืื ืืืจืื ืืื ืืืื ืืื ืื! ืืืกืฃ ืืช ืืงืื ืืืื ืืื ืคืื ืงืฆืืืช ืืืืืื ืืืืคืืชื
(ืืก' 9 - ืืก' 12):
private fun incrementTip() {
if (tipPercent != MAX_TIP) {
tipPercent += TIP_INCREMENT_PERCENT
tipTextView.text = String.format("%d%%", tipPercent)
}
}
private fun decrementTip() {
if (tipPercent != MIN_TIP) {
tipPercent -= TIP_INCREMENT_PERCENT
tipTextView.text = String.format("%d%%", tipPercent)
}
}
private fun incrementPeople() {
if (numberOfPeople != MAX_PEOPLE) {
numberOfPeople += PEOPLE_INCREMENT_VALUE
numberOfPeopleTextView.text = numberOfPeople.toString()
}
}
private fun decrementPeople() {
if (numberOfPeople != MIN_PEOPLE) {
numberOfPeople -= PEOPLE_INCREMENT_VALUE
numberOfPeopleTextView.text = numberOfPeople.toString()
}
}
ืืื ืืงืื ืืื ืขื ืคืื ืงืฆืืืช ืืืืืื ืขื ืขืจืืื ืืงืกืืืืืื (MAX_TIP & MAX_PEOPLE). ืื ืืกืฃ, ืืงืื ืืื ืขื ืคืื ืงืฆืืืช ืืืคืืชื ืขื ืขืจืื ืืื ืืืื (MIN_TIP & MIN_PEOPLE).
ืืขืช ืื ื ืืงืฉืจืื ืืช ืืืคืชืืจืื ืืืืืื ืื ืืคืื ืงืฆืืืช initViews (#13):
private fun initViews() {
...
addTipButton.setOnClickListener(this)
subtractTipButton.setOnClickListener(this)
addPeopleButton.setOnClickListener(this)
subtractPeopleButton.setOnClickListener(this)
//TODO #15: Bind EditText to TextWatcher
}
ืืขืช ืชืืื ืืืืกืืฃ ื ืืงืื ืืืืืืื, ืืืคืื ืืืกืคืจ ืืฉืชืชืคื ืืคืืืฉื. ืืืื, ืขืืฉืื ืืืืจ ืืื ืืฉืื...
ืกืขืืฃ ืืืฉืื ืขืืืืืช
ืงืื ืื ืืืฉื ืขืืืืืช (#14):
private fun calculateExpense() {
val totalBill = billEditText.text.toString().toDouble()
val totalExpense = ((HUNDRED_PERCENT + tipPercent) / HUNDRED_PERCENT) * totalBill
val individualExpense = totalExpense / numberOfPeople
expensePerPersonTextView.text = String.format("$%.2f", individualExpense)
}
ืืืื, ืืื ื ืงืจืืช ืคืื ืงืฆืื ืฉืืืคืฉืจืช ืืงืืช ืืืฉืืื ืืช ืืกืคืจ ืืื ืฉืื ืืืืจื ืืืืฉื ืืืคืื (#15):
private fun incrementTip() {
โฆ
}
private fun decrementTip() {
โฆ
}
private fun incrementPeople() {
โฆ
}
private fun decrementPeople() {
โฆ
}
ืืืื ื ืคืขืื ืืช ืืืคืืืงืฆืื. ืื ื ืจืื ืืขืืื ื ืืืจ. ืืื ืื ืืืื ืืืืืช ืืื ืืืชืจ.
ืื ืชื ืกื ืืืกืืจ ืืช ืกืืื ืืืฉืืื ืืืืืจ ืืื ืืืืืื ืืช ืืกืคืจ ืืืืคืื ืื ืืืืจืื, ืืืคืืืงืฆืื ืชืงืจืืก ืื ืืื ืขืืืื ืืืืงื ืืืื ืขืจื ืืขืืืช ืืืคืก. ืืชืจื ืืื, ืื ืชื ืกื ืืฉื ืืช ืืช ืกืืื ืืืฉืืื, ืืืืืืื ืื ืืขืืืื ื.
ืฉืืืื ืืืจืื ืื
ืืืกืฃ TextWatcher (#16):
class MainActivity: AppCompatActivity(), View.OnClickListener, TextWatcher {
ืืืืจ ืืื ืื ื ืืืืืขืื ืืช ืืืืื billEditText (#17):
billEditText.addTextChangedListener(ืื)
ืื ืืกืฃ, ืื ื ืืืกืืคืื ืงืื ืืืคืขืืช TextWatcher (#18):
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (!billEditText.text.isEmpty()) {
calculateExpense()
}
}
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
ืืืื, ืขืืฉืื ืืืืจื ืืื ืขืืื! ืืื ืืื, ืืชืืช "ืืืฉืืื ืขืฆืืช" ืืฉืื ืืงืืืืื.
Skillbox ืืืืืฆื:
- ืงืืจืก ืืขืฉื ืฉื ืชืืื
"ืื ื ืืคืชื ืืชืจืื PRO" .- ืงืืจืก ืืงืืื
"ืืคืชื C#" .- ืงืืจืก ืืขืฉื ืื ืฉื ื
"ืืคืชื PHP ื-0 ื-PRO" .
ืืงืืจ: www.habr.com