DEV Community

dss99911
dss99911

Posted on • Originally published at dss99911.github.io

Android UI 위젯 완벽 가이드

Android UI 위젯 완벽 가이드

Android에서 자주 사용되는 UI 위젯들의 사용법과 팁을 알아봅니다.

RecyclerView

RecyclerView는 대용량 데이터셋을 효율적으로 표시하는 위젯입니다.

기본 설정

recyclerView.apply {
    layoutManager = LinearLayoutManager(context)
    adapter = myAdapter
    setHasFixedSize(true)
}
Enter fullscreen mode Exit fullscreen mode

Grid Layout

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    app:spanCount="2"
    tools:listitem="@layout/item_grid" />
Enter fullscreen mode Exit fullscreen mode

Item Decoration

recyclerView.addItemDecoration(
    DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
)
Enter fullscreen mode Exit fullscreen mode

Item Animation

recyclerView.itemAnimator = DefaultItemAnimator()
Enter fullscreen mode Exit fullscreen mode

Layout Animation

<!-- res/anim/layout_animation_fall_down.xml -->
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_animation_fall_down"
    android:delay="15%"
    android:animationOrder="normal" />
Enter fullscreen mode Exit fullscreen mode
recyclerView.layoutAnimation = AnimationUtils.loadLayoutAnimation(
    context, R.anim.layout_animation_fall_down
)
Enter fullscreen mode Exit fullscreen mode

스크롤 비활성화

android:nestedScrollingEnabled="false"
Enter fullscreen mode Exit fullscreen mode

DiffUtil 사용

class UserDiffCallback : DiffUtil.ItemCallback<User>() {
    override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
        return oldItem == newItem
    }
}

class UserAdapter : ListAdapter<User, UserViewHolder>(UserDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        // ViewHolder 생성
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(getItem(position))
    }
}
Enter fullscreen mode Exit fullscreen mode

ConstraintLayout

ConstraintLayout은 복잡한 레이아웃을 플랫하게 만들 수 있는 강력한 레이아웃입니다.

Chain 사용

<!-- 수평 체인 -->
<Button
    android:id="@+id/button1"
    app:layout_constraintHorizontal_chainStyle="spread"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toStartOf="@id/button2" />

<Button
    android:id="@+id/button2"
    app:layout_constraintStart_toEndOf="@id/button1"
    app:layout_constraintEnd_toEndOf="parent" />
Enter fullscreen mode Exit fullscreen mode

Chain Style 종류:

  • spread: 균등 분배
  • spread_inside: 양쪽 끝은 붙이고 내부만 균등 분배
  • packed: 중앙에 모음

Guideline

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />
Enter fullscreen mode Exit fullscreen mode

Barrier

여러 뷰의 끝에 동적으로 배리어를 설정합니다.

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/barrier"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:barrierDirection="end"
    app:constraint_referenced_ids="text1,text2,text3" />
Enter fullscreen mode Exit fullscreen mode

Group

여러 뷰의 visibility를 한번에 제어합니다.

<androidx.constraintlayout.widget.Group
    android:id="@+id/group"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:visibility="gone"
    app:constraint_referenced_ids="button1,button2,text1" />
Enter fullscreen mode Exit fullscreen mode

Percent 크기

<View
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintWidth_percent="0.5"
    app:layout_constraintHeight_percent="0.3" />
Enter fullscreen mode Exit fullscreen mode

CoordinatorLayout

CoordinatorLayout은 자식 뷰들 간의 상호작용을 조정합니다.

기본 구조

<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <!-- 컨텐츠 -->

    </androidx.core.widget.NestedScrollView>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Enter fullscreen mode Exit fullscreen mode

Scroll Flags

  • scroll: 스크롤 시 사라짐
  • enterAlways: 아래로 스크롤하면 바로 나타남
  • enterAlwaysCollapsed: 상단에서만 전체 표시
  • exitUntilCollapsed: 최소 높이까지만 줄어듦
  • snap: 중간 상태 없이 표시/숨김

FAB with Snackbar

FAB이 Snackbar가 나타날 때 자동으로 위로 이동합니다.

Snackbar.make(view, "Message", Snackbar.LENGTH_LONG)
    .setAction("Action", null)
    .show()
Enter fullscreen mode Exit fullscreen mode

AppBar

Toolbar 설정

setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
    setDisplayHomeAsUpEnabled(true)
    setHomeAsUpIndicator(R.drawable.ic_menu)
}
Enter fullscreen mode Exit fullscreen mode

Up 버튼 처리

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        android.R.id.home -> {
            onBackPressed()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}
Enter fullscreen mode Exit fullscreen mode

NavigationDrawer

<com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/nav_header"
    app:menu="@menu/drawer_menu" />
Enter fullscreen mode Exit fullscreen mode
navigationView.setNavigationItemSelectedListener { menuItem ->
    when (menuItem.itemId) {
        R.id.nav_home -> { /* 처리 */ }
    }
    drawerLayout.closeDrawers()
    true
}
Enter fullscreen mode Exit fullscreen mode

TabLayout with ViewPager

<com.google.android.material.tabs.TabLayout
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabIndicatorColor="@color/primary"
    app:tabSelectedTextColor="@color/primary" />

<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Enter fullscreen mode Exit fullscreen mode
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
    tab.text = "Tab ${position + 1}"
}.attach()
Enter fullscreen mode Exit fullscreen mode

ViewStub

필요할 때만 inflate되는 경량 뷰입니다.

<ViewStub
    android:id="@+id/stub"
    android:inflatedId="@+id/inflated_layout"
    android:layout="@layout/expensive_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
Enter fullscreen mode Exit fullscreen mode
binding.stub.setOnInflateListener { _, inflated ->
    // inflated 뷰 사용
}
binding.stub.inflate()
Enter fullscreen mode Exit fullscreen mode

View 관련 팁

descendantFocusability

하위 뷰들의 포커스를 차단합니다.

android:descendantFocusability="blocksDescendants"
Enter fullscreen mode Exit fullscreen mode

clipChildren

자식 뷰가 부모 영역 밖에도 그릴 수 있게 허용합니다.

android:clipChildren="false"
Enter fullscreen mode Exit fullscreen mode

setAddStatesFromChildren

자식 뷰의 상태가 부모 뷰에 영향을 미치게 합니다.

viewGroup.setAddStatesFromChildren(true)
Enter fullscreen mode Exit fullscreen mode

결론

Android의 다양한 UI 위젯들을 적절히 활용하면 복잡한 UI도 효율적으로 구현할 수 있습니다. ConstraintLayout으로 플랫한 뷰 계층을 유지하고, RecyclerView로 대용량 리스트를 처리하며, CoordinatorLayout으로 스크롤 연동 애니메이션을 구현하세요.


Originally published at https://dss99911.github.io

Top comments (0)