제트팩
구글에서는 안드로이드 앱을 개발하는 데 필요한 다양한 라이브러리 모음을 제트팩이라는 이름으로 제공한다. androidx로 시작하는 패키지명을 사용한다.
제트팩의 목적은 다음 3가지이다.
appcompat 라이브러리
androidx 라이브러리에서 가장 많이 사용하는 appcompat 라이브러리는 안드로이드 앱의 화면을 구성하는 액티비티를 만들며 API 레벨의 호환성 문제를 해결해 준다.
appcompat 라이브러리를 이용해서 액티비티를 만들 때는 플랫폼 API의 Activity가 아니라 다음처럼 appcompat의 AppCompatActivity 클래스를 상속받아 작성한다.
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(){
}
액션바
액티비티의 구성 요소인 액션바는 화면 위쪽에 타이틀 문자열이 출력되는 영역을 의미한다. 액티비티가 출력되는 전체 창은 액션바와 콘텐츠 영역으로 구분된다.
<item android:id="@+id/menu_search"
android:title="search"
app:showAsAction="always"
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
프래그먼트
프래그먼트는 텍스트 뷰나 버튼처럼 액티비티 화면을 구성하는 뷰인데, 그 자체만으로는 화면에 아무것도 출력되지 않는다. 프래그먼트가 다른 뷰와 다른 점은 액티비티처럼 동작한다는 것이다.
프래그먼트는 뷰이지만 그 자체로는 화면에 아무것도 출력되지 않는다. 따라서 먼저 프래그먼트 화면을 구성하는 레이아웃 XML 파일을 작성해야 한다.
리사이클러 뷰
여러 가지 항목을 나열할 때 리사이클러 뷰를 이용한다.
다음과 같은 구성 요소를 이용해야 한다.
뷰 페이저2
뷰 페이저는 스와이프 이벤트로 화면을 전환할 때 사용한다.
먼저 레이아웃 XML 파일에 뷰 페이저2를 추가한다.
리사이클러 뷰 어댑터를 이용한다.
화면 3개를 뷰 페이저2로 제공하는 어댑터라면 이 어덥터를 뷰 페이저2에 적용하면 된다.
binding.viewpager.adapter = MyPagerAdapter(datas)
드로어 레이아웃
드로어 레이아웃은 액티비티 화면에 보이지 않던 내용이 왼쪽이나 오른쪽에 손가락의 움직임에 따라 밀려 나오는 기능을 한다.
최상위에는 <androidx.drawerlayout.widget.DrawerLayout> 태그를, 그 아래에는 과 태그를 선언한다. 태그가 2개인 것이 중요하다. 이렇게 XML 설정만 해도 첫 번째 태그에 해당하는 화면이 알아서 나오고 사용자가 화면 끝을 밀면 두 번째 태그에 해당하는 화면이 나타난다.
제트팩을 이용해 화면 구성하기
그럼 이를 종합적으로 활용해 화면을 구성해보겠다.
먼저 프래그먼트를 3개 생성해준다. 각각 OneFragment, TwoFragment, ThreeFragment라는 이름으로 작성해준다.
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 onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
val width = parent.width
val height = parent.height
val dr: Drawable? = ResourcesCompat.getDrawable(context.resources, com.google.android.material.R.drawable.abc_ab_share_pack_mtrl_alpha ,null)
val drWidth = dr?.intrinsicWidth
val drHeight = dr?.intrinsicHeight
val left = width/2 - drWidth?.div(2) as Int
val top = height/2 - drHeight?.div(2) as Int
c.drawBitmap(
BitmapFactory.decodeResource(context.resources, com.google.android.material.R.drawable.abc_ab_share_pack_mtrl_alpha),
left.toFloat(),
top.toFloat(),
null)
}
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)
outRect.set(10, 10, 10, 60)
else
outRect.set(10, 10, 10, 0)
view.setBackgroundColor(Color.parseColor("#28A0FF"))
ViewCompat.setElevation(view, 20.0f)
}
}
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 14..23){
datas.add("SSU CSE $i 학번")
}
val adapter = MyAdapter(datas)
val layoutManager = LinearLayoutManager(activity)
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.adapter = adapter
binding.recyclerView.addItemDecoration(MyDecoration(activity as Context))
return binding.root
}
}
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)
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
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_main, menu)
val menuItem = menu?.findItem(R.id.menu_search)
val searchView = menuItem?.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextChange(newText: String?): Boolean {
return true
}
override fun onQueryTextSubmit(query: String?): Boolean {
Log.d("kkang", "search text: $query")
return true
}
})
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
}
좋은 정보 감사합니다