[Android-Kotlin] 6주차
화면 구성하기: 액티비티 값 주고받기 뷰바인딩
package com.example.activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { //Entry Point (시작점)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
안드로이드의 시작점 (entry point)는 AndroidManifest.xml에 정의되어있다. 드래그하여 표시한 부분이 안드로이드의 entry point라고 할 수 있음.
com.example.activity 우클릭>New>Activity>Empty Activity 로 SubActivity 생성 가능.
액티비티명 끝에 Activity라고 붙이면 Layout 명이 activty_어쩌고로 생성된다.
해당 액티비티를 시작점으로 하고 싶을 시 Launcher Activity 항목을 체크해주면 된다.
SubActivity를 시작점으로 하고 싶을시 드래그 해놓은 해당 부분(<intent-filter>)를 해당 SubActivity <activity></> 안에 넣어주면 된다.
package com.example.activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.activity.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) { //Entry Point (시작점)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding.btnStart.setOnClickListener {
val intent = Intent(this,SubActivity::class.java)
startActivity(intent)
}
}
}
버튼이 클릭되면 서브액티비티를 실행하도록 하는 MainActivity 코드.
버튼이 클릭되면 putExtra로 전달된 값이 SubActivity로 전달되어 서브액티비티에서 그 화면을 보여주도록 하였다. 아래는 MainActivity 코드이다.
package com.example.activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.activity.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) { //Entry Point (시작점)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding.btnStart.setOnClickListener {
val intent = Intent(this,SubActivity::class.java)
//Intent의 값이 담기는 공간: Bundle
intent.putExtra("from1","Hello Bundle")
intent.putExtra("from2",2022)
//value에 들어가는 타입에 따라 자동으로 타입이 결정됨.
startActivity(intent)
}
}
}
package com.example.activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.activity.databinding.ActivitySubBinding
class SubActivity : AppCompatActivity() {
val binding by lazy { ActivitySubBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sub)
with(binding){
to1.text=intent.getStringExtra("from1") //SubActivity가 intent값을 가져옴.
to2.text="${intent.getIntExtra("from2",0)}"
//만약 받아오는 key값이 없을 경우 default 값을 정해줌.
//text에는 정수형 int를 바로 가져올 수 없으므로 문자열 템플릿 사용함.
}
}
}
SubActivity로 intent의 값이 전달된다. 이때, value값에 따라 getExtra를 다르게 호출해야함에 주의한다.
다음으로는 SubActivity에서 MainActivity로 전달하는 경우이다. 메소드로는 startActivityForResult(intent,requestCode)를 사용한다. (현재는 잘 사용하지 않는 기능인듯.)
package com.example.activity
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.activity.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) { //Entry Point (시작점)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding.btnStart.setOnClickListener {
val intent = Intent(this,SubActivity::class.java)
//Intent의 값이 담기는 공간: Bundle
intent.putExtra("from1","Hello Bundle")
intent.putExtra("from2",2022)
//value에 들어가는 타입에 따라 자동으로 타입이 결정됨.
startActivityForResult(intent,99)
}
}
//아래 resultCode로 SubActivity의 RESULT.OK가 전달됨.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode==Activity.RESULT_OK){
when(requestCode){
99->{
//subActivity에서 returnValue라는 id(name)로 전달하므로 "returnValue"로 받음.
//val message=data?.getStringExtra("returnValue")
//로 해도 되고,
//또는 let scope함수를 사용하여 return value값이 없을 경우를 처리 가능하다.
data?.getStringExtra("returnValue").let{ message->
Toast.makeText(this,message,Toast.LENGTH_SHORT).show()
}
}
}
}
}
}
ctrl+O에서 onActivityResult 함수메소드를 불러온다.
package com.example.activity
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.activity.databinding.ActivitySubBinding
class SubActivity : AppCompatActivity() {
val binding by lazy { ActivitySubBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sub)
with(binding){
to1.text=intent.getStringExtra("from1") //SubActivity가 intent값을 가져옴.
to2.text="${intent.getIntExtra("from2",0)}"
//만약 받아오는 key값이 없을 경우 default 값을 정해줌.
//text에는 정수형 int를 바로 가져올 수 없으므로 문자열 템플릿 사용함.
btnClose.setOnClickListener {
val returnIntent= Intent()
//닫은 후에 자신을 호출한 쪽으로 전달하는 intent이기 때문에 MainActivity 쓸 필요 없음.
val message=editMessage.text.toString()
returnIntent.putExtra("returnValue",message)
//정상적으로 종료되었음을 result_ok로 mainactivity측에 알려줌.
setResult(Activity.RESULT_OK,returnIntent)
finish()
}
}
}
}
edittext에 값을 입력하고 버튼을 클릭하면 화면이 닫기면서 main activity로 edittext의 입력값이 전달되도록하였다. 성공적으로 전달되면 메인 액티비로 RESULT.OK를 함께 전송한다.
화면 구성하기: 스피너
package com.example.spinner
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import com.example.spinner.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var data=listOf("-선택하세요-","1월","2월","3월")
//스피너 콘테이너에 데이터를 넣기 위해서는 중간에 매개 역할이 필요함 -> adaptor
//문자열의 컬렉션이므로 <String>으로 함.
//거의 안드로이드에서 제공하는 클래스들은 context에 this가 많이 들어감 (ex. Intent..)
//두번째 매개변수에는 스피너가 보여주는 목록의 레이아웃 파일을 지정해줌.
//안드로이드에 만들어져있는 아래와 같은 레이아웃을 사용해줄 수 있고, 또는 직접 만들어줄수도 있음.
//3번째 매개변수에는 넣어줄 콘텐트들을 넣는다.
var adaptor= ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)
binding.spinner.adapter=adaptor
}
}
package com.example.spinner
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import com.example.spinner.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
var data=listOf("-선택하세요-","1월","2월","3월")
//스피너 콘테이너에 데이터를 넣기 위해서는 중간에 매개 역할이 필요함 -> adaptor
//문자열의 컬렉션이므로 <String>으로 함.
//거의 안드로이드에서 제공하는 클래스들은 context에 this가 많이 들어감 (ex. Intent..)
//두번째 매개변수에는 스피너가 보여주는 목록의 레이아웃 파일을 지정해줌.
//안드로이드에 만들어져있는 아래와 같은 레이아웃을 사용해줄 수 있고, 또는 직접 만들어줄수도 있음.
//3번째 매개변수에는 넣어줄 콘텐트들을 넣는다.
var adaptor= ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)
binding.spinner.adapter=adaptor
binding.spinner.onItemSelectedListener=object: AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
//선택하면 동작하는 메소드
val selected= data.get(p2) //data에서 값을 가져와서 selected에 넣어줌.
binding.result.text=selected
}
override fun onNothingSelected(p0: AdapterView<*>?) {
//아무것도 선택되지 않았을때 동작되는 메소드
}
}
}
}
onItemSelectedListener기능을 사용하여 스피너의 항목값을 선택하면 동작하는 메소드를 작성해준다.
다음과 같이 실행되는 것을 확인 가능하다.
package com.example.spinner
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import com.example.spinner.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
var data=listOf("-선택하세요-","1월","2월","3월")
//스피너 콘테이너에 데이터를 넣기 위해서는 중간에 매개 역할이 필요함 -> adaptor
//문자열의 컬렉션이므로 <String>으로 함.
//거의 안드로이드에서 제공하는 클래스들은 context에 this가 많이 들어감 (ex. Intent..)
//두번째 매개변수에는 스피너가 보여주는 목록의 레이아웃 파일을 지정해줌.
//안드로이드에 만들어져있는 아래와 같은 레이아웃을 사용해줄 수 있고, 또는 직접 만들어줄수도 있음.
//3번째 매개변수에는 넣어줄 콘텐트들을 넣는다.
var adaptor= ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)
with(binding){
spinner.adapter=adaptor
spinner.onItemSelectedListener=object: AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
//선택하면 동작하는 메소드
val selected= data.get(p2) //data에서 값을 가져와서 selected에 넣어줌.
result.text=selected
}
override fun onNothingSelected(p0: AdapterView<*>?) {
//아무것도 선택되지 않았을때 동작되는 메소드
}
}
}
}
}
with 스코프함수로 깔끔하게 정리가능하다.
화면 구성하기: 리사이클러뷰
다음과 같이 위젯들을 배치한다.
다음 res/layout폴더에 new resource file을 추가하여 레이아웃을 생성하고,
코틀린 클래스 파일을 하나 추가 생성하여 코드를 작성한다.
package com.example.recycleview
data class Memo (var num:Int, var title:String,var timestamp:Long)
val memolst= mutableListOf<Memo>()
for(idx in 1..100){
val memo= Memo(idx,"헬로", 12345678)
memolst.add(memo)
}
위와 같은 코드들을 작성하여 라사이클러뷰의 아이템 레이아웃들을 하나씩 넣어주는 기능을 하도록 할 수 있다.
package com.example.recycleview
data class Memo (var no:Int, var title:String,var timestamp:Long)
Memo 클래스의 내용이다.
package com.example.recycleview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.recycleview.databinding.ActivityMainBinding
import com.example.recycleview.databinding.ItemRecyclerBinding
import java.text.SimpleDateFormat
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
//1. 데이터를 불러온다
val data=loadData()
//2. 어댑터를 생성
val customAdapter=CustomAdapter(data)
//3. 화면의 RecyclerView와 연결
binding.recyclerView.adapter=customAdapter
//4. 레이아웃 매니저 설정
binding.recyclerView.layoutManager=LinearLayoutManager(this)
}
fun loadData(): MutableList<Memo>{
val memoList= mutableListOf<Memo>()
for(no in 1..100){
val title="이것이 안드로이드다. $no"
val date=System.currentTimeMillis()
val memo=Memo(no,title,date)
memoList.add(memo)
}
return memoList
}
}
//아래의 adapter가 holder를 가지고 아이템 레이아웃의 값을 세팅한다는 의미
class CustomAdapter(val listData:MutableList<Memo>): RecyclerView.Adapter<CustomAdapter.Holder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding=ItemRecyclerBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return Holder(binding)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
//1. 사용할 데이터를 꺼내고
val memo=listData.get(position)
//2. 홀더에 데이터를 전달
holder.setMemo(memo)
}
override fun getItemCount(): Int {
return listData.size
}
//RecyclerView의 ViewHolder을 상속받음. 상속받을때 생성자로 사용하는 View를 넘겨줘야.
class Holder(val binding:ItemRecyclerBinding):RecyclerView.ViewHolder(binding.root){
//클릭처리는 init에서만 한다.
lateinit var currentMemo:Memo
init{
binding.root.setOnClickListener {
val title=binding.textTitle.text
Toast.makeText(binding.root.context,"클릭된 아이템 : $title",Toast.LENGTH_SHORT).show()
}
}
//3. 받은 데이터를 화면에 출력한다.
fun setMemo(memo:Memo){
//클릭을 했을때 현재 메모 정보를 표시.
currentMemo=memo
with(binding){
textNo.text="${memo.no}"
textTitle.text=memo.title
val sdf=SimpleDateFormat("yyyy-MM-dd")
val formattedDate=sdf.format(memo.timestamp)
textDate.text=formattedDate
}
}
}
}
화면 구성하기: 프래그먼트
부드럽게 화면전환하고싶을때 프래그먼트 전체를 사용함으로써 구현 가능
화면전환 등등
와 같이 fragment를 만들어서 layout속성으로 해당 xml을 넣어주면 미리보기로 보는 것도 가능하다.
이보다 framelayout으로 구성하는 것이 더 훨씬 화면넘김이 부드럽다.
package com.example.fragment
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.fragment.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}
//val listFragment by lazy{ListFragment()}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setFragment()
}
fun setFragment(){
// 1. 사용할 프래그먼트 생성
val listFragment = ListFragment()
//2. 트랜잭션 생성
val transaction=supportFragmentManager.beginTransaction()
//3. 트랜잭션을 통해서 프래그먼트 삽입
transaction.add(R.id.listFragment,listFragment)
transaction.commit()
}
}
framelayout으로 화면을 구성하고 다음과 같은 MainActivity코드를 작성했다.
package com.example.fragment
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.fragment.databinding.ActivityMainBinding
import com.example.fragment.databinding.FragmentListBinding
class ListFragment : Fragment() {
lateinit var mainActivity: MainActivity
lateinit var binding: FragmentListBinding
override fun onAttach(context: Context) {
super.onAttach(context)
if(context is MainActivity) mainActivity=context
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding= FragmentListBinding.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btnNext.setOnClickListener {
mainActivity.goDetail()
}
}
}
listFragment의 class 코드
package com.example.fragment
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.fragment.databinding.FragmentDetailBinding
import com.example.fragment.databinding.FragmentListBinding
class DetailFragment : Fragment() {
lateinit var mainActivity: MainActivity
lateinit var binding: FragmentDetailBinding
override fun onAttach(context: Context) {
super.onAttach(context)
if(context is MainActivity) mainActivity=context
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding= FragmentDetailBinding.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btnBack.setOnClickListener {
mainActivity.goBack()
}
}
}
detailFragment의 클래스 코드
'💻STUDY > ANDROID STUDY' 카테고리의 다른 글
8주차 스터디 정리 (0) | 2022.07.18 |
---|---|
[Android-Kotlin] 7주차 (0) | 2022.05.25 |
[Android-Kotlin] 5주차 (0) | 2022.05.09 |
[Android-Kotlin] 4주차 (0) | 2022.05.02 |
[Android-Kotlin] 3주차 (0) | 2022.04.02 |
댓글