[Android/Flutter 교육] 20일차

MSU·2024년 1월 23일

Android-Flutter

목록 보기
20/85
post-thumbnail

강사님께서 화면이 달라도 id는 최대한 다 다르게 설정하는것을 권장하셨다.

코루틴 특강 전에 쓰레드 강의 예정

모든 네트워크 테스트는 와이파이 끄고 lte로 바꾸고 중계기가 없는 실내(방 안)에서 테스트
데이터 용량을 최소화 시키는 것이 중요

안드로이드 어플 개발 순서

  1. 화면부터 만들기(화면이 다수라면 화면 전환까지)
  2. 각 화면별 UI기능을 모두 구현
  3. 각 화면별 구현해야 하는 기능을 정의
  4. 각 화면별 구현해야 하는 기능을 구현

EX06

  • 내가 직접 만들었을 때는 체크박스 활성화를 위해 어떤 방법을 써야할지 able을 검색해서 나온 isClickable로 설정을했는데 강사님은 isEnabled로 설정하셨다. isClickable은 말그대로 클릭가능여부만 설정하는거라 시각적으로 비활성화 여부 확인이 어려웠는데 isEnabled=false로 비활성화를 시키면 시각적으로 회색으로 변경이되다보니 이게 훨씬 더 좋은 방법인 것 같다.

  • 나는 onCreate 안에서 모든 코드를 넣었는데 강사님은 한번에 넣지 않고 화면 요소 초기화 함수와 이벤트 함수를 따로 만들어서 호출하는 방식으로 구현하셨다.

  • 완성본

package kr.co.lion.ex06_view

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kr.co.lion.ex06_view.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    lateinit var activityMainBinding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(activityMainBinding.root)

        initView()
        setViewEvent()
    }

    // 화면 요소에 관련된 초기화
    fun initView(){
        // 취미 스위치는 on 상태로 설정한다.
        activityMainBinding.apply {
            switchHobby.isChecked = true
        }
    }

    // 화면 요소에 대한 이벤트 설정
    fun setViewEvent(){
        activityMainBinding.apply {
            // 취미 스위치 이벤트
            switchHobby.setOnCheckedChangeListener { buttonView, isChecked ->
                // on/off 상태로 분기한다.
                when(isChecked){
                    // on상태라면...
                    true -> {
                        // 활성화
                        checkBoxHobby1.isEnabled = true
                        checkBoxHobby2.isEnabled = true
                        checkBoxHobby3.isEnabled = true
                    }
                    false -> {
                        // 비활성화
                        checkBoxHobby1.isEnabled = false
                        checkBoxHobby1.isChecked = false
                        checkBoxHobby2.isEnabled = false
                        checkBoxHobby2.isChecked = false
                        checkBoxHobby3.isEnabled = false
                        checkBoxHobby3.isChecked = false
                    }
                }
            }

            // 버튼 이벤트
            buttonSubmit.setOnClickListener {
                // 아이디
                textViewResult.text = "아이디 : ${textFieldUserId.text}\n"
                // 비밀번호
                textViewResult.append("비밀번호 : ${textFieldUserPw.text}\n")
                // 사용자 이름
                textViewResult.append("이름 : ${textFieldUserName.text}\n")
                // 취미
                // 스위치의 on/off 상태에 따라 분기
                when(switchHobby.isChecked){
                    // off 상태면 취미가 없는 것으로 취급한다.
                    false -> textViewResult.append("선택한 취미는 없습니다.")
                    // on 상태면 체크박스에 체크한 것을 출력해준다.
                    true -> {
                        // 모든 체크박스가 체크되어 있지 않다면
                        if(checkBoxHobby1.isChecked == false
                            && checkBoxHobby2.isChecked == false
                            && checkBoxHobby3.isChecked == false){
                            textViewResult.append("선택한 취미는 없습니다.")
                        }else{
                            if(checkBoxHobby1.isChecked){
                                textViewResult.append("선택한 취미 : 축구\n")
                            }
                            if(checkBoxHobby2.isChecked){
                                textViewResult.append("선택한 취미 : 농구\n")
                            }
                            if(checkBoxHobby3.isChecked){
                                textViewResult.append("선택한 취미 : 야구\n")
                            }
                        }
                    }
                }
            }
        }
    }
}

ProgressBar

  • 오래 걸리는 작업이 있을 경우 작업
  • Material3의 Progress indicators
  • 3초의 법칙 : 화면이 3초이상 반응이 없을 경우 사용자는 어플이 멈췄다고 생각함
  • 화면 표시 순서
    1. 사용자가 화면 전환
    2. 인디케이터 표시
    3. 텍스트 부터 받아오기
    4. 이미지 받아오기
  • 작업중임을 표시하는것보다 progressbar를 안써도 될 만큼 화면을 빠르게 보여주는게 더 중요함, 서버로부터 받아오는 데이터 용량을 최소화 시키는 것이 중요함
  1. 주요 속성
  • indeterminate : true로 주면 애니메이션이 계속 나오는 상태로 보여준다.
  1. 주요 프로퍼티
  • progress : 현재 진행바의 크기를 설정해준다. 최소 0, 최대 100
  1. 주요 메서드
  • setProgress : 현재 진행바의 크기를 설정해준다. 두 번째 매개변수에 true를 넣어주면 애니메이션 효과가 나타난다.

SeekBar

  • 사용자가 직접 값을 정할 수 있음
  • Material3의 Sliders
  1. 주요 속성
  • valueFrom : 최소 값
  • valueTo : 최대 값
  1. 주요 프로퍼티
  • value

RecyclerView

보여질 항목의 전체 개수
어떤 데이터인지
어떤 모양으로 보여줄지
이 3가지를 어댑터를 통해 결정

  • AdapterView : 무한개의 항목을 보여주는 목적으로 사용하는 뷰들
    Adapter를 사용하기 때문에 AdapterView라고 부른다.
  • Adapter : View를 구성하기 위해 필요한 정보를 가지고 있는 요소
    RecyclerView 구성을 위해 필요한 코드들이 작성되어 있다.
class MainActivity : AppCompatActivity() {

    lateinit var activityMainBinding: ActivityMainBinding

    // 이미지의 id
    var imageRes = arrayOf(
        R.drawable.imgflag1,
        R.drawable.imgflag2,
        R.drawable.imgflag3,
        R.drawable.imgflag4,
        R.drawable.imgflag5,
        R.drawable.imgflag6,
        R.drawable.imgflag7,
        R.drawable.imgflag8
    )
    
    // 문자열1
    val textData1 = arrayOf(
        "토고", "프랑스", "스위스", "스페인", "일본", "독일", "브라질", "대한민국"
    )

    // 문자열2
    val textData2 = arrayOf(
        "탈락", "진출", "탈락", "진출", "탈락", "진출", "진출", "진출"
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(activityMainBinding.root)
    }
}
  1. MainActivity 안에 inner 클래스를 작성한다
    inner class RecyclerViewAdapter{

    }
  1. ViewHolder 클래스를 작성해준다.
    inner class RecyclerViewAdapter{

        ViewHolder
        inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root){
             매개변수로 들어오는 바인딩객체를 담을 프로퍼티
            var rowBinding:RowBinding

            init{
                this.rowBinding = rowBinding
            }
        }
    }
  1. adapter 클래스를 Adapter를 상속받게 구현해준다.
class MainActivity : AppCompatActivity() {
...

    inner class RecyclerViewAdapter : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolderClass>(){

        //ViewHolder
        inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root){
            // 매개변수로 들어오는 바인딩객체를 담을 프로퍼티
            var rowBinding:RowBinding

            init{
                this.rowBinding = rowBinding
            }
        }

        // ViewHolder 객체를 생성하여 반환한다.
        // 새롭게 항목이 보여질 때 재사용 가능한 항목이 없다면 이 메서드를 호출한다.
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {
            // View Binding
            val rowBinding = RowBinding.inflate(layoutInflater)
            // View Holder
            val viewHolderClass = ViewHolderClass(rowBinding)

            // 반환한다.
            return viewHolderClass
        }
        
        // RecyclerView를 통해 보여줄 항목 전체의 개수를 반환한다.
        override fun getItemCount(): Int {
            return imageRes.size
        }

        // 항목의 View에 보여주고자 하는 데이터를 설정한다.
        // 첫 번째 매개변수 : ViewHolder객체. 재사용 가능한 것이 없다면 onCreateViewHolder 메서드를 호출하고 반환하는 ViewHolder 객체가 들어오고
        // 재사용 가능한 것이 있다면 재사용 가능한 ViewHolder객체가 들어온다.
        // 두 번째 매개변수 : 구성하고자 하는 항목의 순서값(0부터 1씩 증가)
        override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {
            holder.rowBinding.imageViewRow.setImageResource(imageRes[position])
            holder.rowBinding.textViewRow1.text = textData1[position]
            holder.rowBinding.textViewRow2.text = textData2[position]
        }
    }
...
}

MainActivity에서 어댑터 객체를 생성하여 적용해준다.

class MainActivity : AppCompatActivity() {
...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(activityMainBinding.root)

        activityMainBinding.apply {
            // 어댑터 객체 생성
            val recyclerViewAdapter = RecyclerViewAdapter()
            // 어댑터를 적용해준다.
            recyclerView.adapter = recyclerViewAdapter
            // RecyclerView의 항목을 보여줄 방식을 설정한다.
            // 위에서 아래 방향
            recyclerView.layoutManager = LinearLayoutManager(this@MainActivity) // 그냥 this는 activityMainBinding을 의미하게 되므로 MainActivity를 지칭할 수 있게 @를 붙여준다.


            // RecyclerView Decoration

            // 기본 구분선 넣기
            // val deco = DividerItemDecoration(this@MainActivity, DividerItemDecoration.VERTICAL)
            // recyclerView.addItemDecoration(deco)

            // Material3 구분선 Divder 넣기 (구분선 범위를 직접 지정할 수 있음)
            val deco = MaterialDividerItemDecoration(this@MainActivity, DividerItemDecoration.VERTICAL)
            // 구분선 좌측 여백
            // deco.dividerInsetStart = 450
            // 구분선 우측 여백
            // deco.dividerInsetEnd = 200
            recyclerView.addItemDecoration(deco)
        }
    }
...
}

각 항목에 이벤트를 추가해줄 수 있다.

...
        //ViewHolder
        inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root){
            // 매개변수로 들어오는 바인딩객체를 담을 프로퍼티
            var rowBinding:RowBinding

            init{
                this.rowBinding = rowBinding

                // 현재 항목을 누르면 반응하는 리스너
                // adapterPosition 프로퍼티 : 항목의 순서값
                // 사용자가 터치한 항목이 몇 번째 항목인가로 사용한다.
                this.rowBinding.root.setOnClickListener {
                    activityMainBinding.textView.text = "선택한 항목 : ${textData1[adapterPosition]}"
                }
                // View의 가로길이는 최대크기로 맞춰주어야 항목 옆의 공백을 눌러도 클릭이 된다.
                // 직접 코드로 셋팅을 해줘야 한다.
                this.rowBinding.root.layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, // 가로길이
                    ViewGroup.LayoutParams.WRAP_CONTENT  // 세로길이
                )
            }
        }
...

EX07

리사이클러뷰의 갱신 방법




※ 출처 : 멋쟁이사자 앱스쿨 2기, 소프트캠퍼스 
profile
안드로이드공부

0개의 댓글