- split an Activity into multiple Layouts (HorizontalScrollView, Inflater)
- Create and manage ListView (Adapter)
Multiple Layouts
- Sometimes, we need more than one Layout
- Sometimes, we need partial arrangement
- Some place needs linear arrangement, or some place needs scrollView
- A layout is allowed to contain other Layouts
- All Layouts are also have constrains and attributes for arrangement
- It actually similar with inserting Views into a Layout
Inflation & LayoutInflater
- Kotlin source는 "objectified"된 resource만 사용할 수 있음
- xml resource를 kotlin object로 convert 해줘야함
- ex) setContentView
- To use XML contents in the kotlin source codes, we need objectified Views
- setContentView function convert contents defined in XML to Kotlin object
- XML contents를 objectify하는 프로세스를 Inflation이라고 함
- LayoutInflater는 Inflation과 거의 같은 operation을 함
- layout을 runtime 동안에 바꿔주기 위해 Inflator가 필요함
Adapter
- ListView: A ViewGroup which groups several items and display them in vertical scrollable list
- The list items are automatically inserted to the ListView using Adapter
- Adapter pull contents from a source
- To make ListView,
- 1) Custom Adapter -> .kt file
- 2) Custom List Layout -> .xml file
- 3) Set custom adapter to listview
Practice
- file structure는 아래와 같음
MainActivity.kt
Restaurant.kt
CustomAdapter.kt
activity_main.xml
item.xml
sub_layout.xml
"item.xml"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<ImageView
android:id="@+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
</LinearLayout>
- listview의 item
"sub_layout.xml"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<ImageView
android:id="@+id/leftImageView"
android:layout_width="200dp"
android:layout_height="100dp"
tools:srcCompat="@tools:sample/avatars" />
<ImageView
android:id="@+id/rightImageView"
android:layout_width="200dp"
android:layout_height="100dp"
tools:srcCompat="@tools:sample/avatars" />
</LinearLayout>
- SHOW SUB LAYOUT 버튼을 누르면 출력됨
"activity_main.xml"
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/source"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<HorizontalScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="300dp"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/pizza"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="@+id/hamburger"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="@+id/chicken"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
</HorizontalScrollView>
<Button
android:id="@+id/showButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SHOW SUB LAYOUT"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/scrollview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/showButton">
</LinearLayout>
<ListView
android:id="@+id/reslistview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/scrollview"
tools:layout_editor_absoluteY="290dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
- constraint 잘 맞춰야함
- layout의 구조는 아래와 같음
"Restaurant.kt"
package com.example.week4
class Restaurant (val id: Int, val name: String)
"CustomAdapter.kt"
package com.example.week4
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
class CustomAdapter (val context: Context, val items: ArrayList<Restaurant>): BaseAdapter(){
override fun getCount(): Int{
return items.size
}
override fun getItem(position: Int): Any{
return items[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getView(i: Int, cvtView: View?, parent: ViewGroup?): View{
val inflater: LayoutInflater =
LayoutInflater.from(context)
val view: View = inflater.inflate(R.layout.item,null)
var imgView = view.findViewById<ImageView>(R.id.imageView)
var textView = view.findViewById<TextView>(R.id.textView)
textView.text = items[i].name
imgView.setImageResource(items[i].id)
return view
}
}
- BaseAdapter를 Extend함
- Context parameter 정의 및 item들을 저장하기 위한 Arraylist를 parameter로 정의
- getCount(), getItem(), getItemId를 override 해줌
- getView()를 override 해줌
- imgView는 setImageResource()를 이용하여 item[i].id로 참조한 이미지로 할당
- textView는 item list에서 해당하는 index의 name으로 할당
"MainActivity.kt"
package com.example.week4
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ListView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var container = findViewById<LinearLayout>(R.id.container)
var showButton = findViewById<Button>(R.id.showButton)
showButton.setOnClickListener {
val layoutInflater: LayoutInflater =
applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
layoutInflater.inflate(R.layout.sub_layout, container, true)
var leftImageView = findViewById<ImageView>(R.id.leftImageView)
var rightImageView = findViewById<ImageView>(R.id.rightImageView)
leftImageView.setImageResource(R.drawable.bbq)
rightImageView.setImageResource(R.drawable.bhc)
}
val pizzaButton = findViewById<Button>(R.id.pizza)
pizzaButton.setOnClickListener{
val pizzaData = ArrayList<Restaurant>()
pizzaData.add(Restaurant(R.drawable.domino, "domino pizza"))
pizzaData.add(Restaurant(R.drawable.pizzanarachickengongju, "pizza nara chicken gong"))
pizzaData.add(Restaurant(R.drawable.pizzahut, "pizza hut"))
val myAdapter = CustomAdapter(applicationContext, pizzaData)
val listView = findViewById<ListView>(R.id.reslistview)
listView.adapter = myAdapter
}
val hamburgerButton = findViewById<Button>(R.id.hamburger)
hamburgerButton.setOnClickListener{
val hamburgerData = ArrayList<Restaurant>()
hamburgerData.add(Restaurant(R.drawable.burgerking, "burger king"))
hamburgerData.add(Restaurant(R.drawable.lotteria, "lotte ria"))
hamburgerData.add(Restaurant(R.drawable.momstouch, "moms touch"))
hamburgerData.add(Restaurant(R.drawable.mcdonalds, "mc donald"))
val myAdapter = CustomAdapter(applicationContext, hamburgerData)
val listView = findViewById<ListView>(R.id.reslistview)
listView.adapter = myAdapter
}
val chickenButton = findViewById<Button>(R.id.chicken)
chickenButton.setOnClickListener{
val chickenData = ArrayList<Restaurant>()
chickenData.add(Restaurant(R.drawable.bbq, "bb q"))
chickenData.add(Restaurant(R.drawable.bhc, "bh c"))
chickenData.add(Restaurant(R.drawable.goobne, "goob ne"))
val myAdapter = CustomAdapter(applicationContext, chickenData)
val listView = findViewById<ListView>(R.id.reslistview)
listView.adapter = myAdapter
}
}
}
- container layout과 showButton을 정의하고, setOnClickListener를 이용해 버튼이 클릭 될 경우 leftImageView와 rightImageView가 container layout에 출력되도록 설정
- pizzaButton, hamburgerButton, chickenButton을 각각 생성해줌
- setOnClickListener 안에 버튼이 클릭 될 경우 실행할 프로세스를 정의함
- pizzaData를 생성하고 pizza item들을 add 해줌
- myAdapter를 정의하여 CustomAdapter를 할당해주고, CustomAdapter에 Context와 pizzaData를 인수로 넣어줌
- listView를 생성해주고, listView에 myAdapter를 할당해주어 item들 (pizza들)을 삽입해줌
- hamburgerButton과 chickenButton도 마찬가지로 setOnClickListener에서 adapter를 이용해 listView 구현