-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
전남대Android_오진우_1주차 과제 #35
base: fivejinw
Are you sure you want to change the base?
Changes from all commits
e15f6d0
83f72d5
38f158a
bbd28cf
4cb00ca
6cb51ac
72060a8
b3bf8d9
1e6b013
35ac9da
847e50d
ff5a8b4
a33025b
a082d60
8ded020
8d5fd23
d3218c0
7bc6c79
a22f786
9860402
9f22f83
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,33 @@ | ||
# android-contacts | ||
# android-contacts - 간단한 연락처 구현(1주차) | ||
## 구현할 기능 목록 | ||
|
||
**지정된 형식의 데이터를 입력하는 기능** | ||
- [x] 문자열을 입력할 수 있는 기능 | ||
- [x] 숫자만 입력할 수 있는 기능 | ||
- [x] 날짜 선택 기능 | ||
- [x] 성별 선택 기능 | ||
|
||
**더보기 기능** | ||
- [x] 더보기를 클릭하면 숨겨져 있던 입력 폼을 드러낼 수 있는 기능 | ||
|
||
**저장 기능** | ||
- [x] 저장 버튼을 클릭하면 토스트 메세지를 출력 | ||
- [x] 이름, 전화번호의 칸이 채워져 있지 않으면 저장이 되지 않으면 그에 맞는 토스트 메세지를 출력 | ||
|
||
**취소 기능** | ||
- [x] 취소 버튼을 클릭하면 토스트 메세지를 출력 | ||
|
||
## step2 구현할 기능 목록 | ||
|
||
**연락처 추가 기능** | ||
- [x] + 버튼을 통해 연락처를 추가하는 창을 띄우는 기능 | ||
|
||
**연락처 출력 기능** | ||
- [x] 저장된 연락처들을 간단하게 이름만 띄워주는 기능 | ||
- [x] 각 연락처를 클릭하면 상세 화면을 띄워주는 기능 | ||
- [x] 상세화면에서 적힌 내용만 출력하는 기능 | ||
|
||
**연락처 저장 기능** | ||
- [x] 저장 버튼을 누르면 연락처를 저장할 수 있는 기능 | ||
- [x] 뒤로가기 버튼을 누를 때 만약 작성된 내용이 있다면 확인 팝업이 나타나는 기능 | ||
- [x] 취소 버튼을 누를 때 만약 작성된 내용이 있다면 확인 팝업이 나타나는 기능 |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,96 @@ | ||||||||||
package campus.tech.kakao.contacts | ||||||||||
|
||||||||||
import android.os.Bundle | ||||||||||
import android.view.View | ||||||||||
import android.widget.TextView | ||||||||||
import androidx.activity.enableEdgeToEdge | ||||||||||
import androidx.appcompat.app.AppCompatActivity | ||||||||||
import androidx.core.view.ViewCompat | ||||||||||
import androidx.core.view.WindowInsetsCompat | ||||||||||
|
||||||||||
class DetailActivity : AppCompatActivity() { | ||||||||||
lateinit var name: TextView | ||||||||||
lateinit var phoneNumber: TextView | ||||||||||
lateinit var mail: TextView | ||||||||||
lateinit var birthday: TextView | ||||||||||
lateinit var gender: TextView | ||||||||||
lateinit var memo: TextView | ||||||||||
lateinit var nameInputField: TextView | ||||||||||
lateinit var phoneNumberInputField: TextView | ||||||||||
lateinit var mailInputField: TextView | ||||||||||
lateinit var birthdayInputField: TextView | ||||||||||
lateinit var genderInputField: TextView | ||||||||||
lateinit var memoInputField: TextView | ||||||||||
|
||||||||||
override fun onCreate(savedInstanceState: Bundle?) { | ||||||||||
super.onCreate(savedInstanceState) | ||||||||||
setContentView(R.layout.activity_detail) | ||||||||||
|
||||||||||
initVar() | ||||||||||
bindField() | ||||||||||
setVisibleCompletedFields() | ||||||||||
} | ||||||||||
|
||||||||||
fun initVar(){ | ||||||||||
name = findViewById(R.id.name) | ||||||||||
phoneNumber = findViewById(R.id.phone_number) | ||||||||||
mail = findViewById(R.id.mail) | ||||||||||
birthday = findViewById(R.id.birthday) | ||||||||||
gender = findViewById(R.id.gender) | ||||||||||
memo = findViewById(R.id.memo) | ||||||||||
nameInputField = findViewById(R.id.input_name_field) | ||||||||||
phoneNumberInputField = findViewById(R.id.input_phone_number_field) | ||||||||||
mailInputField = findViewById(R.id.input_mail_field) | ||||||||||
birthdayInputField = findViewById(R.id.input_birthday_field) | ||||||||||
genderInputField = findViewById(R.id.input_gender_field) | ||||||||||
memoInputField = findViewById(R.id.input_memo_field) | ||||||||||
} | ||||||||||
|
||||||||||
fun bindField(){ | ||||||||||
val intent = intent | ||||||||||
nameInputField.setText(intent.getStringExtra("name")) | ||||||||||
phoneNumberInputField.setText(intent.getStringExtra("phoneNumber")) | ||||||||||
mailInputField.setText(intent.getStringExtra("mail")) | ||||||||||
birthdayInputField.setText(intent.getStringExtra("birthday")) | ||||||||||
genderInputField.setText(intent.getStringExtra("gender")) | ||||||||||
memoInputField.setText(intent.getStringExtra("memo")) | ||||||||||
Comment on lines
+51
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. intent 에서 공통으로 사용하는 key 들은 따로 관리하는 편이 좋습니다. 수동으로 복붙을 진행하다보면, 키 복사를 제대로 하지 못하는 등의 휴먼에러도 발생할 수 있으니까요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. companion object 를 사용하여 const 로 관리해주시면 좋을 것 같네요 :)
|
||||||||||
} | ||||||||||
|
||||||||||
fun setVisibleCompletedFields() { | ||||||||||
if(ExistMail()){ | ||||||||||
mail.visibility = View.VISIBLE | ||||||||||
mailInputField.visibility = View.VISIBLE | ||||||||||
Comment on lines
+61
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. View.isVisible 을 통해 visibility 컨트롤이 더 쉽습니다.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 또한 isVisible 을 활용한다면 아래처럼 if 분기를 태우지 않더라도 처리할 수 있습니다.
|
||||||||||
} | ||||||||||
if(ExistBirthday()){ | ||||||||||
birthday.visibility = View.VISIBLE | ||||||||||
birthdayInputField.visibility = View.VISIBLE | ||||||||||
} | ||||||||||
if(ExistGender()){ | ||||||||||
gender.visibility = View.VISIBLE | ||||||||||
genderInputField.visibility = View.VISIBLE | ||||||||||
} | ||||||||||
if(ExistMemo()){ | ||||||||||
memo.visibility = View.VISIBLE | ||||||||||
memoInputField.visibility = View.VISIBLE | ||||||||||
} | ||||||||||
|
||||||||||
} | ||||||||||
|
||||||||||
|
||||||||||
|
||||||||||
fun ExistMail(): Boolean { | ||||||||||
return mailInputField.text.toString() != "" | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. String 의 isEmpty 함수를 활용한다면 조금 더 명확하게 코드를 표현할 수 있을 것 같아요 :) |
||||||||||
} | ||||||||||
|
||||||||||
fun ExistBirthday(): Boolean { | ||||||||||
return birthdayInputField.text.toString() != "" | ||||||||||
} | ||||||||||
|
||||||||||
fun ExistGender(): Boolean { | ||||||||||
return genderInputField.text.toString() != "" | ||||||||||
} | ||||||||||
|
||||||||||
fun ExistMemo(): Boolean { | ||||||||||
return memoInputField.text.toString() != "" | ||||||||||
} | ||||||||||
Comment on lines
+81
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 함수명은 kotlin naming convention 에 따라 소문자로 시작하는 편이 좋습니다. |
||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package campus.tech.kakao.contacts | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.os.Bundle | ||
import android.util.Log | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import android.widget.TextView | ||
import androidx.activity.enableEdgeToEdge | ||
import androidx.activity.result.ActivityResultLauncher | ||
import androidx.activity.result.contract.ActivityResultContracts | ||
import androidx.appcompat.app.AppCompatActivity | ||
import androidx.core.view.ViewCompat | ||
import androidx.core.view.WindowInsetsCompat | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
import androidx.recyclerview.widget.RecyclerView | ||
|
||
class ListActivity : AppCompatActivity() { | ||
lateinit var resultLauncher: ActivityResultLauncher<Intent> | ||
lateinit var descriptionText: TextView | ||
lateinit var plusButton: TextView | ||
lateinit var recyclerView: RecyclerView | ||
lateinit var contactList: MutableList<Contact> | ||
lateinit var adapter: RecyclerViewAdapter | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_list) | ||
|
||
initVar() | ||
initListener() | ||
|
||
} | ||
|
||
fun initVar(){ | ||
contactList = mutableListOf<Contact>() | ||
adapter = RecyclerViewAdapter(contactList, LayoutInflater.from(this), this) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adapter 를 초기화하는 것 또한 recycler view 를 초기화하는 것과 같은 맥락이므로, initRecyclerView 로 이동하는 것은 어떨까요? |
||
plusButton = findViewById<TextView>(R.id.plus_item_button) | ||
descriptionText = findViewById<TextView>(R.id.description_text) | ||
initRecyclerView() | ||
initResultLauncher() | ||
} | ||
|
||
fun initRecyclerView() { | ||
recyclerView = findViewById<RecyclerView>(R.id.recyclerView) | ||
recyclerView.adapter = adapter | ||
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) | ||
} | ||
|
||
fun initResultLauncher() { | ||
resultLauncher = | ||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | ||
if (result.resultCode == RESULT_OK) { | ||
val contact = Contact( | ||
result.data?.getStringExtra("name") ?: "", | ||
result.data?.getStringExtra("phoneNumber") ?: "", | ||
result.data?.getStringExtra("mail") ?: "", | ||
result.data?.getStringExtra("birthday") ?: "", | ||
result.data?.getStringExtra("gender") ?: "", | ||
result.data?.getStringExtra("memo") ?: "", | ||
) | ||
Log.d("contact2", contact.name) | ||
contactList.add(contact) | ||
setDescriptionTextVisibilityGone() | ||
adapter.notifyItemInserted(contactList.size) | ||
} | ||
} | ||
} | ||
fun initListener(){ | ||
plusButton.setOnClickListener { | ||
moveToAddContact() | ||
} | ||
} | ||
fun moveToAddContact() { | ||
val intent = Intent(this@ListActivity, MainActivity::class.java) | ||
resultLauncher.launch(intent) | ||
} | ||
|
||
fun setDescriptionTextVisibilityGone() { | ||
descriptionText.visibility = View.GONE | ||
} | ||
|
||
} | ||
|
||
class RecyclerViewAdapter( | ||
var contactList: MutableList<Contact>, | ||
var inflater: LayoutInflater, | ||
var context: Context | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. context 를 변수로 넘기는 것은 금기시해야할 것 중 하나입니다. inflater 또한 파라미터로 받을 필요는 없을 것 같구요.
|
||
) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() { | ||
|
||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inner class 로 구현하지 않았으면 해요. 필요하다면 userTitle 과 userName 을 설정할 수 있는 함수를 만드는 편이 좋을 것 같습니다. |
||
val userTitle: TextView | ||
val userName: TextView | ||
|
||
init { | ||
userTitle = itemView.findViewById(R.id.user_title) | ||
userName = itemView.findViewById(R.id.user_name) | ||
itemView.setOnClickListener { | ||
val position: Int = adapterPosition | ||
val intent = Intent(context, DetailActivity::class.java) | ||
val sendContact = contactList.get(position) | ||
intent.putExtra("name", sendContact.name) | ||
intent.putExtra("phoneNumber", sendContact.phoneNumber) | ||
intent.putExtra("mail", sendContact.mail) | ||
intent.putExtra("birthday", sendContact.birthday) | ||
intent.putExtra("gender", sendContact.gender) | ||
intent.putExtra("memo", sendContact.memo) | ||
context.startActivity(intent) | ||
} | ||
} | ||
} | ||
|
||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { | ||
val view = inflater.inflate(R.layout.contact_item, parent, false) | ||
return ViewHolder(view) | ||
} | ||
|
||
override fun onBindViewHolder(holder: ViewHolder, position: Int) { | ||
holder.userTitle.text = contactList.get(position).name[0].toString() | ||
holder.userName.text = contactList.get(position).name | ||
} | ||
|
||
override fun getItemCount(): Int { | ||
return contactList.size | ||
} | ||
} | ||
|
||
class Contact( | ||
var name: String, | ||
var phoneNumber: String, | ||
var mail: String, | ||
var birthday: String, | ||
var gender: String, | ||
var memo: String | ||
) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ViewBinding 을 통해서 findViewById 를 사용하지 않고 처리해볼 수 있어요 :)