안드로이드 여러가지 View

이영준·2023년 4월 18일
0

📌 텍스트 뷰

🔑 AutoCompleteTextView

자동완성을 지원하는 텍스트 뷰

  • 첫 글자부터 일치하는 데이터만 검색
  • Adapter가 필요
  • completionThreshold 속성값으로 검색이 시작되는 문자의 수를 결정
    <AutoCompleteTextView
        android:id="@+id/main_auto_complete_tv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:completionThreshold="2"
        android:hint="검색어를 입력하세요"
        android:maxLines="1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

adapter로 데이터를 전달해주어야하므로

        val wordList = mutableListOf("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
        val adapter = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, wordList)

        binding = ActivityAutoCompleteBinding.inflate(layoutInflater).apply {
            mainAutoCompleteTv.setAdapter(adapter)
        }

간단한 arrayAdapter를 사용한다.

+ MultiAutoCompleteTextView

를 사용하면 , 를 tokenizer로 사용하여 2개 이상의 값을 검색할 수 있다.

        binding = ActivityMultiAutoBinding.inflate(layoutInflater).apply {
            mainMultiAutoCompleteTv.apply {
                setAdapter(adapter)
                setTokenizer(MultiAutoCompleteTextView.CommaTokenizer())
            }
        }

이 외에 중간부터 검색되는 기능 등을 위해서는

        binding.mainMultiAutoCompleteTv.addTextChangedListener {
            
        }

textChangedListener등을 정의하여 직접 구현해주어야 한다.

🔑 TextInputLayout

EditText에 입력된 텍스트를 기반으로 텍스트가 유동적으로 반응하도록 하기 위해 Material Design에서 만든 뷰이다.

https://m2.material.io/components/text-fields/android#using-text-fields
간단한 예제로 비밀번호를 아이콘을 누르면 입력 내용을 보이게 하는 등을 따로 코드 작업 없이 할 수 있다.

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="User Name"
        app:endIconMode="password_toggle"
        app:startIconDrawable="@drawable/baseline_favorite_24">

        <com.google.android.material.textfield.TextInputEditText
            android:inputType="textPassword"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/teal_200" />
    </com.google.android.material.textfield.TextInputLayout>

에러 아이콘 및 메시지

TextInputLayout isErrorEnabled, error를 멤버변수로가지고 있고, 각각
에러 아이콘을 보여줄지, 에러 메시지를 무엇으로 할지를 의미한다.

        binding.num.addTextChangedListener {
            if(it.toString().toInt() >= 1000){
                binding.outlinedTextField1.isErrorEnabled = true
                binding.outlinedTextField1.error = "1000보다 작아야 합니다"
            }
            else{
                binding.outlinedTextField1.isErrorEnabled = false
                binding.outlinedTextField1.error = null
            }
        }

📌 ScrollView

스크롤 뷰 해당 영역을 화면 스크롤이 되도록 해준다.

  • 하나의 뷰만 감쌀 수 있기 때문에 linearLayout 등 특정레이아웃으로 뷰들을 묶은 다음 그 레이아웃을 스크롤 뷰 안에 넣는다.
  • RecyclerView처럼 기본적으로 스크롤이 달린 뷰와 함께 사용한다면 의도치 않은 동작이 발생할수 있으므로 주의해야 한다.
  • HorizontalScrollView 는 태그로 horizontal scrollview를 만들 수 있다.

🔑 NestedScrollView

보통 RecyclerView가 ScrollView 안에 들어가는 경우에 종종 쓰는데, recycler뷰가 따로 스크롤 되지 않고 전체와 같이 스크롤 되도록 해준다.

그냥 scrollview안에 recyclerview 넣은 경우

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:descendantFocusability="blocksDescendants"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:textSize="20sp"
                android:background="@android:color/holo_green_light"
                android:gravity="center"
                android:text="Lorem ipsum dolor sit amet" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:textSize="20sp"
                android:background="@android:color/holo_red_light"
                android:gravity="center"
                android:text="consectetur adipisicing elit" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:textSize="20sp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="sed do eiusmod tempor incididunt" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:textSize="20sp"
                android:background="#00ffff"
                android:gravity="center"
                android:text="ut labore et dolore magna aliqua. " />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:textSize="20sp"
                android:background="@android:color/holo_orange_light"
                android:gravity="center"
                android:text="Ut enim ad minim veniam," />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:background="@android:color/holo_purple"
                android:gravity="center"
                android:text=" quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/main_rv2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:listitem="@layout/recyclerview_item" />

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

사용방법은 단순히 scrollview 태그 대신 nestedScrollView를 사용하면 된다.

nestedScrollView 안에 넣은 경우

📌 Spinner

여러가지 항목을 목록형태로 보여주는 뷰이다.


역시 adapter로 데이터를 연결해주어야 하고, 선택에 따른 분기 실행을 할 수 있다.
``


```kotlin
 val idolList = arrayOf("아이유", "브레이브걸스", "방탄소년단", "SG워너비", "블랙핑크", "아이즈원", "샤이니", "트와이스", "ITZY", "오마이걸")
        val spinnerAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, idolList)

        binding = ActivitySpinnerBinding.inflate(layoutInflater).apply {
            mainSpinner.adapter = spinnerAdapter
            mainSpinner.onItemSelectedListener = object : OnItemSelectedListener{
                override fun onItemSelected(
                    parent: AdapterView<*>?,
                    view: View?,
                    position: Int,
                    id: Long
                ) {
                    Toast.makeText(this@SpinnerActivity, "position:$position", Toast.LENGTH_SHORT).show()
                }

                override fun onNothingSelected(parent: AdapterView<*>?) {
                    TODO("Not yet implemented")
                }

            }
        }

📌 Floating Action Button

이 역시 Material Design에서 제공하는 컴포넌트가 있다.

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:src="@drawable/outline_done_black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

🔑 FAB 애니메이션 기능 추가

이 생성한 플로팅 버튼에 움직이는 기능 등의 애니메이션을 추가하면서 버튼을 누를 때 다른 버튼들이 위로 펼쳐올라오게끔 하려고 한다.

애니메이션 문서의 ObjectAnimator를 사용하여 뷰에 대해 x,y축에 대한 변경을 할 수 있다
https://developer.android.com/develop/ui/views/animations/prop-animation
https://developer.android.com/guide/topics/graphics/prop-animation?hl=ko

(x축방향으로 100위치에 1000밀리초동안 이동)

                binding.fab.ObjectAnimator.ofFloat(fab, "translationX", 100f).apply {
                    duration = 1000
                    start()
                }

(버튼 누를 때마다 서로 다른 버튼 여러개를 각각 다른 y축 값에 배치하도록 토글하는 함수)

    private fun toggle() {
        if (isOpen) {
            ObjectAnimator.ofFloat(binding.fab1, "translationY", 0f).apply {
                start()
            }
            ObjectAnimator.ofFloat(binding.fab2, "translationY", 0f).apply {
                start()
            }
        } else {
            ObjectAnimator.ofFloat(binding.fab1, "translationY", -300f).apply {
                start()
            }
            ObjectAnimator.ofFloat(binding.fab2, "translationY", -600f).apply {
                start()
            }
        }
        isOpen = !isOpen
    }

📌 ViewStub

중요도가 낮거나 거의 사용되지 않는 뷰를 나중에 실제로 필요할 때까지로딩을 지연시키기 위해 사용
따라서 빈 껍데기만 미리 마련하고 나중에 실제 뷰를 렌더링 할 때 사용되는 빈 껍데기 뷰이다.
RecyclerView도 위의 원리로 돌아간다.

    <ViewStub
        android:id="@+id/main_stub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inflatedId="@+id/layout_viewstub"
        android:layout="@layout/layout_viewstub"/>

layout 속성에 뷰에넣을 그림 등의 레이아웃을 넣어주고
visibility를 VISIBLE로 하거나 stub.visibility = View.VISIBLE , inflate()를 통해 화면에 렌더링해준다. visible로 하는 것 또한 inflate되지 않은 뷰는 inflate 해주는 코드가 내장되어있기 때문에 가능한 것이다.

            mainBtnShow.setOnClickListener {
//                mainStub.visibility = View.VISIBLE
                mainStub.inflate()
            }

inflate는 한번 이미 inflate된것을 또하려고 하면 오류가 나니 주의해야 한다.

                if (mainStub.parent is ViewGroup)
                    mainStub.inflate()

조건문을 통해 inflate를 제어하는 등의 코드를 써야한다.

📌 include

xml에 같은 레이아웃을 여러번 복사붙여넣기하는 것이 아닌, 자주 사용하는 레이아웃을 따로 만들고 필요할 때마다 사용하기 위한 뷰.

layout_include로 만든 xml 파일을 include 태그로 재사용하기

    <include
        layout="@layout/layout_include"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

📌 requestFocus

레이아웃에서 특정 뷰에 포커스를 두도록 하기 위해 사용하는 뷰

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <requestFocus />
    </EditText>

이에 더해 포커스가 있는 뷰를 코드상에서 currentFocus로 가져올 수도 있다.
참고로 currentFocus는 view가 invisible하다면 가져와지지 않고 null 을 반환한다.

📌 DrawerLayout, NavigationView

DrawerLayout과 NavigationView는 일반적으로 함께사용한다.
xml 최상단을 DrawerLayout으로 하고 메뉴가 열리기 전화면을 activity, 열린 메뉴의 화면은 NavigationView가 담당한다.

그리고 activity의 레이아웃을 navigationView의 레이아웃보다 앞에 선언해야 한다.


<androidx.drawerlayout.widget.DrawerLayout
              .
              .
              .
              mainView 영역
              .
              .
              .
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#CCCBCB"
        android:orientation="vertical"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/drawer"
        app:itemTextColor="@color/red"/>

</androidx.drawerlayout.widget.DrawerLayout>

navigationView를 화면에 보여지게 할 때는

        binding.mainInclude.mainBtn.setOnClickListener {
            binding.mainDrawerLayout.openDrawer(GravityCompat.START) //어느 쪽에서 open 할 지
        }

위와 같이
NavigationView를 띄우는 것이 아닌 DrawerLayout의 openDrawer를 불르면 안의 navigation을 불러준다.

🔑 좌상단에 메뉴바로 네비게이션바 띄우기

supportActionBar?.setDisplayHomeAsUpEnabled(true)

supportActionBar?.setDisplayHomeAsUpEnabled(true)를 작성하면 좌상단에 기본으로 백 버튼을 가진 아이콘이 보여진다. 엄밀히 말하면 Home을 활성화시켜주는 것이다.

supportActionBar?.setHomeAsUpIndicator(R.drawable.baseline_menu_24)

적당히 원하는 아이콘으로 바꿔주고

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if(item.itemId == android.R.id.home){
            Log.d("싸피", "onOptionsItemSelected: ${item.itemId}")
            if(binding.mainDrawerLayout.isDrawerOpen(GravityCompat.START))
                binding.mainDrawerLayout.closeDrawer(GravityCompat.START)
            else
                binding.mainDrawerLayout.openDrawer(GravityCompat.START)
        }

        return super.onOptionsItemSelected(item)
    }

onOptionsItemSelected를 오버라이딩한다. 참고로 툴바의 좌상단 아이콘 영역은 앞서 언급한대로 Home이므로 item.itemId == android.R.id.home와 같이 작성해준다.

profile
컴퓨터와 교육 그사이 어딘가

0개의 댓글