1. 앱바 사용하기
구글의 머티리얼 디자인(material design)은 모바일과 데스크톱, 그리고 그 밖에 다양한 장치를 아우르는 일관된 애플리케이션 디자인 지침입니다. 구글에서는 머티리얼 디자인을 다음처럼 소개합니다.
질감이 느껴지는 표면과 대담하고 선명한 그래픽 디자인, 그리고 아름답고 직관적인 사용자 경험을 위한 자연스러운 애니메이션을 특징으로 한다.
이러한 머티리얼 디자인 지침에 맞게 앱을 개발하려면 다양한 뷰가 필요한데, 구글은 이를 지원하려고 머티리얼 라이브러리를 제공합니다.
앱바 레이아웃 - 화면 위쪽 영역 꾸미기
앱바(AppBar)란 화면 위쪽의 꾸밀 수 있는 영역을 의미합니다. 앱바를 이용해 화면 위쪽 영역의 크기만 늘릴 수도 있지만 메뉴를 출력하는 툴바를 포함할 수도 있습니다. 그리고 툴바 이외에 이미지나 문자열을 함께 출력하는 등 앱바를 이용하면 화면의 위쪽 영역을 다양하게 꾸밀 수 있습니다.
머티리얼 라이브러리에서는 이러한 앱바를 구현하는 데 도움을 주는 앱바 레이아웃을 제공합니다. 앱바 레이아웃도 하나의 뷰이므로 레이아웃 XML 파일에 등록합니다. 다음은 앱바 레이아웃(AppBarLayout)에 툴바를 포함한 예입니다. 이처럼 앱바를 사용할 때는 대부분 앱바 레이아웃 안에 툴바를 포함합니다.
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
앱바 레이아웃을 사용하면 툴바뿐만 아니라 여러 가지 콘텐츠를 함께 표시할 수 있습니다. 예를 들어 다음 처럼 layout_height 속성을 이용해 위쪽 영역을 크게 만들거나 이미지를 표시할 수도 있습니다.
<com.google.android.material.appbar.AppBarLayout
(... 생략 ...)
android:layout_height="242dp">
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.AppBarLayout ... 생략 ...>
<androidx.appcompat.widget.Toolbar ... 생략 ... />
<ImageView ... 생략 ... />
</com.google.android.material.appbar.AppBarLayout>
2. 머티리얼 라이브러리로 화면 구성하기
1. 빌드 그래들 작성하기
android {
...
buildFeatures {
viewBinding = true
}
}
2. 이미지 파일 복사하기
/res/drawable/baseball.png 파일을 추가합니다.
3. 레이아웃 XML 파일 작성하기
<MainActivity.kt>
package com.example.myapplication12
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.example.myapplication12.databinding.ActivityMainBinding
import com.google.android.material.tabs.TabLayoutMediator
class MainActivity : AppCompatActivity() {
lateinit var toggle: ActionBarDrawerToggle
class MyFragmentPagerAdapter(activity: FragmentActivity): FragmentStateAdapter(activity){
val fragments: List<Fragment>
init {
fragments= listOf(OneFragment(), TwoFragment(), ThreeFragment())
}
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//add......................................
setSupportActionBar(binding.toolbar)
toggle = ActionBarDrawerToggle(this, binding.drawer, R.string.drawer_opened,
R.string.drawer_closed)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toggle.syncState()
val adapter = MyFragmentPagerAdapter(this)
binding.viewpager.adapter = adapter
TabLayoutMediator(binding.tabs, binding.viewpager){ tab, position ->
tab.text = "Tab${(position + 1)}"
}.attach()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
//이벤트가 toggle 버튼에서 제공된거라면..
if(toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
}
<MyAdapter.kt>
package com.example.myapplication12
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication12.databinding.ItemRecyclerviewBinding
class MyViewHolder(val binding: ItemRecyclerviewBinding): RecyclerView.ViewHolder(binding.root)
class MyAdapter(val datas: MutableList<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun getItemCount(): Int{
return datas.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
= MyViewHolder(ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val binding=(holder as MyViewHolder).binding
binding.itemData.text= datas[position]
}
}
class MyDecoration(val context: Context): RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val index = parent.getChildAdapterPosition(view) + 1
if (index % 3 == 0) //left, top, right, bottom
outRect.set(10, 10, 10, 60)
else
outRect.set(10, 10, 10, 0)
view.setBackgroundColor(Color.parseColor("#28A0FF"))
ViewCompat.setElevation(view, 20.0f)
}
}
<OneFragment.kt>
package com.example.myapplication12
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication12.databinding.FragmentOneBinding
class OneFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentOneBinding.inflate(inflater, container, false)
val datas = mutableListOf<String>()
for(i in 1..20) {
datas.add("Item $i")
}
val layoutManager = LinearLayoutManager(activity)
binding.recyclerview.layoutManager = layoutManager
val adapter = MyAdapter(datas)
binding.recyclerview.adapter = adapter
binding.recyclerview.addItemDecoration(MyDecoration(activity as Context))
return binding.root
}
}
<TwoFragment.kt>
package com.example.myapplication12
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class TwoFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_two, container, false)
}
}
<ThreeFragment.kt>
package com.example.myapplication12
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class ThreeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_three, container, false)
}
}
<res/layout/activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/drawer">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="242dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="242dp"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginBottom="50dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="AppBar Title">
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/baseball"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00000000"
android:elevation="4dp"
app:theme="@style/ToolbarIconColor"
app:titleTextColor="#FFFFFF"
app:layout_collapseMode="pin"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:background="#00000000"
app:layout_collapseMode="parallax"
app:tabMode="scrollable"
app:tabTextColor="#FFFFFF"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Extended FAB"
app:icon="@android:drawable/ic_input_add"
app:layout_anchor="@id/viewpager"
app:layout_anchorGravity="bottom|right"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/main_drawer_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/menu_navigation"/>
</androidx.drawerlayout.widget.DrawerLayout>
<res/layout/fragment_one.xml>
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<res/layout/fragment_two.xml>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".OneFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Two Fragment!!"
android:textSize="25dp"
android:textStyle="bold"
android:gravity="center"/>
</FrameLayout>
<res/layout/fragment_three.xml>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".OneFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Three Fragment!!"
android:textSize="25dp"
android:textStyle="bold"
android:gravity="center"/>
</FrameLayout>
<res/layout/item_recyclerview.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/item_root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:layout_margin="8dp">
<TextView
android:id="@+id/item_data"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="16dp" />
</LinearLayout>
<res/layout/navigation_header.xml>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#FF0000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Navigation Title"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="20dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="30dp"
android:layout_marginLeft="30dp"/>
</RelativeLayout>
</res/menu/menu_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title="search"
app:showAsAction="always"
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
<item android:title="setting"/>
</menu>
</res/menu/menu_navigation.xml>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:icon="@android:drawable/ic_menu_share"
android:title="아이템1"/>
<item
android:icon="@android:drawable/ic_menu_help"
android:title="아이템2"/>
<item
android:icon="@android:drawable/ic_menu_search"
android:title="아이템3"/>
<item
android:icon="@android:drawable/ic_menu_add"
android:title="아이템4"/>
</menu>
</res/values/strings.xml>
<resources>
<string name="app_name">My Application</string>
<string name="drawer_opened">Opened Drawer</string>
<string name="drawer_closed">Closed Drawer</string>
</resources>
</res/values/themes/themes.xml>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.MyFirstApplication" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
<style name="Theme.MyFirstApplication" parent="Base.Theme.MyFirstApplication" />
<style name="ToolbarIconColor" parent="ThemeOverlay.AppCompat.ActionBar">
<item name="colorControlNormal">#FFFFFF</item>
</style>
</resources>
'Android' 카테고리의 다른 글
+[깡쌤의 안드로이드 프로그래밍 with 코틀린][5. 컴포넌트 이해하기] 14. 브로드캐스트 리시버 컴포넌트 (0) | 2024.12.25 |
---|---|
[깡쌤의 안드로이드 프로그래밍 with 코틀린][5. 컴포넌트 이해하기] 13. 액티비티 컴포넌트 (0) | 2024.12.25 |
[깡쌤의 안드로이드 프로그래밍 with 코틀린][4. 구글의 라이브러리로 화면 구성하기] 11. 제트팩 라이브러리 (0) | 2024.12.25 |
[깡쌤의 안드로이드 프로그래밍 with 코틀린][3. 앱의 기본 기능 구현하기] 10. 다이얼로그와 알림 이용하기 (0) | 2024.12.25 |
[깡쌤의 안드로이드 프로그래밍 with 코틀린][3. 앱의 기본 기능 구현하기] 9. 리소스 활용하기 (0) | 2024.12.25 |