
여러개 아이템 중에서 하나를 선택하는 방식의 선택위젯은 어댑터를 사용해야 한다.
어댑터에서 데이터를 관리하도록 할 뿐만 아니라 화면에 보여지는 뷰도 어댑터의 getView 메소드에서 결정한다
선택위젯은 원본 데이터를 위젯에 직접 설정하지 않고 어댑터라는 클래스를 사용한다!
리스트뷰는 그냥 껍데기고 어댑터가 데이터와 뷰를 관리한다.
안드로이드에서 제공하는 대표적인 선택 위젯들은 어댑터를 사용한다.

어댑터를 사용하는 코드의 형태는 다 비슷하니까 리스트뷰를 통해 익숙해지면 좋다.
선택위젯에서 선택하는 하나하나를 아이템이라고 한다
텍스트 이미지 등 여러가지가 아이템이 될 수 있다.
1) 아이템을 위한 XML 레이아웃 정의하기
리스트뷰에 들어갈 각 아이템의 레이아웃을 XML로 정의
2) 아이템을 위한 뷰 정의하기
리스트뷰에 들어갈 각 아이템을 하나의 뷰로 정의. 이 뷰는 여러 개의 뷰를 담고 있는 뷰 그룹이어야 함
부분화면처럼 1)에서 정의한 XML 레이아웃을 인플레이션 후 설정한다
3) 어댑터 정의하기
데이터 관리를 위한 어댑터 클래스를 만들고 그 안에 각 아이템으로 표시할 뷰를 리턴하는 getView 메소드 정의하기
4) 리스트뷰 정의하기
화면에 보여줄 리스트뷰를 만들고 그 안에 데이터가 선택되었을 때 호출될 리스너 객체 정의

먼저 activity_main.xml에 버튼과 리스트뷰를 하나씩 만들어준다.
package com.example.list;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.listView);
}
class SingerAdapter extends BaseAdapter{
ArrayList<String> litems = new ArrayList<String>();
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}
}
그리고 java 파일에서 리스트뷰를 아이디로 찾아준다.
그리고 나서 어댑터를 설정해줘야한다.
안드로이드에서 제공하는 다양한 어댑터가 있다. 이런 걸 사용하면 코드가 짧고 편리하다.
하지만 보통은 리스트뷰를 만들고 나서 리스뷰 안에 들어가는 이미지, 텍스트 등을 커스터마이징해야 해서 처음부터 리스트뷰 안의 아이템을 원하는대로 바꿀 수 있게 어댑터를 정의해서 사용하는 것도 방법이다.
따러서 BaseAdapter를 상속해서 새로운 어댑터를 만들면 된다.
오버라이딩 하기 위해 우클릭 > generate > implement methods 해준다.
또한 어댑터에서 데이터를 관리하기 위해 ArrayList를 만드는데 지금은 탬플릿 인자를 String으로 해놓았는데 String 말고 이름-전화번호를 묶어서 객체로 만들것이다.

package com.example.list;
public class Singeritem {
String name;
String mobile;
public Singeritem(String name, String mobile) {
this.name = name;
this.mobile = mobile;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
@Override
public String toString() {
return "Singeritem{" +
"name='" + name + '\'' +
", mobile='" + mobile + '\'' +
'}';
}
}
따라서 java>com.exmaple.list에 SingerItem 자바 파일을 만들어준다.
클래스를 정의하는데 이 때 멤버변수를 설정하고 우클릭 후 generate>constructor를 선택하면 편리하게 생성자를 알아서 만들어준다!!
그리고 우클릭 > generate > getter and setter 하면 게터 세터 메소드도 직접 만들어준다
그리고 우클릭 > generate > toString을 선택하면 toString도 만들어줌..
리스트뷰가 어댑터에게 몇개의 아이템이 있냐고 물어보는데 이때 getCount가 호출된다.
그리고 position 번째 아이템을 얻기 위해 getItem을 호출한다.
마찬가지로 getItemId는 아이디를 반환하는데 일단은 그냥 인덱스를 반환하도록 했다.
어댑터가 화면에 각 아이템이 보여질 때 뷰도 만들어야 한다. 이게 getView에서 이뤄진다.
반환형이 View다.
리턴해주는 View는 레이아웃으로 구성되고 레이아웃에 해당된는 것을 부분화면으로 정의하고 인플레이션 해서 객체를 만들고 리턴해주는게 가장 잘 쓰이는 방법이다.
xml 파일 하나와 java 소스파일이 부분화면을 위해 필요하다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/ic_launcher"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp"
>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이름"
android:textSize="30dp"
android:textColor="@color/design_default_color_primary_dark"
/>
<TextView
android:layout_marginTop="8dp"
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="전화번호"
android:textSize="24dp"
android:textColor="@android:color/holo_orange_dark"
/>
</LinearLayout>
</LinearLayout>
즉 아이템 뷰를 만들기 위해 xml 파일과 자바 파일을 만들어준다.
먼저 xml파일이다. 하나의 아이템을 위한 레이아웃이 된다.
layout 디렉토리에 singer_item.xml로 만들었다.
사진, 이름, 전화번호가 표시되도록 했다.
두번째 TextView에서 사용한 android:color 가 안드로이드에 기본으로 있는 색상을 사용할 수 있다.
package com.example.list;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.zip.Inflater;
public class SingerItemView extends LinearLayout {
TextView textView1;
TextView textView2;
public SingerItemView(Context context) {
super(context);
init(context);
}
public SingerItemView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.singer_item,this,true);
textView1 = (TextView) findViewById(R.id.textView1);
textView2 = (TextView) findViewById(R.id.textView2);
}
public void setName(String name){
textView1.setText(name);
}
public void setMobile(String mobile){
textView2.setText(mobile);
}
}
다음은 java 파일을 만들어줘야 한다.
singer_item.xml이 리니어레이아웃 으로 만들어져 있다.
자바 클래스를 리니어레이아웃을 상속해서 만들면 바로 갖다 붙일 수 있다.
인플레이션을 하기 위해 시스템 자체에서 돌고 있는 레이아웃인플레이터를 가져다 사용한다.
그리고 inflate 메소드의 두번재 인자로 this를 전달하는데
이 클래스 자체가 LinearLayout을 상속했기 때문에 이것 자체가 뷰로 쓰일 수 있다.
이렇게 인플레이션을 하면 뷰를 findViewById로 가져다 쓸 수 있다.
그리고 이제 이름과 전화번호 정보를 설정할 수 있도록 setName과 setMobile 메소드를 정의해준다.
이제 아이템 뷰를 정의했다.
package com.example.list;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.listView);
SingerAdapter adapter = new SingerAdapter();
adapter.addItem(new SingerItem("소녀시대","010-1000-10000"));
adapter.addItem(new SingerItem("에스파","010-2000-10000"));
adapter.addItem(new SingerItem("블랙핑크","010-3000-10000"));
adapter.addItem(new SingerItem("우주소녀","010-4000-10000"));
adapter.addItem(new SingerItem("오마이걸","010-5000-10000"));
listView.setAdapter(adapter);
}
class SingerAdapter extends BaseAdapter{
ArrayList<SingerItem> items = new ArrayList<SingerItem>();
public void addItem(SingerItem item){
items.add(item);
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int i) {
return items.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
SingerItemView itemView = new SingerItemView(getApplicationContext());
SingerItem item = items.get(i);
itemView.setName(item.getName());
itemView.setMobile(item.getMobile());
return itemView;
}
}
}
getView에서 정의한 뷰를 생성자를 이용해 만든다.
안드로이드에서 모든 뷰는 생성자 인자로 getApplicationContext()를 전달한다.
그리고 ArrayList에서 i 인덱스의 데이터를 가져와서 뷰의 내용을 만들어준다.
그리고 ArrayList에 SingerItem 객체를 추가하기 위해서 addItem 메소드도 public으로 추가해줬다.
onCreate에서 이를 이용해서 데이터를 추가해준다.
또한 어댑터 객체를 만들고 리스트뷰에 등록해야한다.
어댑터를 생성자로 생성하고 데이터 추가 후 리스트뷰에 setAdapter 메소드로 등록해줬다.

애뮬레이터에서 실행하면 이렇게 보인다.
리스트뷰 이렇게 만드는 연습을 많이 해서 익숙하게 해야 한다.

지금 이미지를 다 같은 걸로 만들었는데 이미지도 제각기 다른걸로 바꿔보자.
singer_item.xml의 이미지 뷰에 id를 설정해주고 SingerItemview.java에서 이 id를 이용하면 된다.
package com.example.list;
public class SingerItem {
String name;
String mobile;
int resId;
public SingerItem(String name, String mobile, int resId) {
this.name = name;
this.mobile = mobile;
this.resId = resId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public int getResId() {
return resId;
}
public void setResId(int resId) {
this.resId = resId;
}
@Override
public String toString() {
return "Singeritem{" +
"name='" + name + '\'' +
", mobile='" + mobile + '\'' +
'}';
}
}
이미지는 id로 지정하는데 int형이다.
따라서 int resId 멤버변수 추가해준다.
그리고 관련 게터, 세터랑 생성자도 수정해준다.
package com.example.list;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.zip.Inflater;
public class SingerItemView extends LinearLayout {
TextView textView1;
TextView textView2;
ImageView imageView;
public SingerItemView(Context context) {
super(context);
init(context);
}
public SingerItemView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.singer_item,this,true);
textView1 = (TextView) findViewById(R.id.textView1);
textView2 = (TextView) findViewById(R.id.textView2);
imageView = (ImageView) findViewById(R.id.imageView);
}
public void setName(String name){
textView1.setText(name);
}
public void setMobile(String mobile){
textView2.setText(mobile);
}
public void setImage(int resId){
imageView.setImageResource(resId);
}
}
설정한 뷰에도 이미지 뷰를 추가해준다.
init에서 이미지 뷰도 설정해준다.
그리고 setImage 메소드도 추가해준다.
package com.example.list;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.listView);
SingerAdapter adapter = new SingerAdapter();
adapter.addItem(new SingerItem("소녀시대","010-1000-10000",R.drawable.ic_launcher_foreground));
adapter.addItem(new SingerItem("에스파","010-2000-10000",R.drawable.ic_launcher_background));
adapter.addItem(new SingerItem("블랙핑크","010-3000-10000",R.drawable.ic_launcher_background));
adapter.addItem(new SingerItem("우주소녀","010-4000-10000",R.drawable.ic_launcher_background));
adapter.addItem(new SingerItem("오마이걸","010-5000-10000",R.drawable.ic_launcher_background));
listView.setAdapter(adapter);
}
class SingerAdapter extends BaseAdapter{
ArrayList<SingerItem> items = new ArrayList<SingerItem>();
public void addItem(SingerItem item){
items.add(item);
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int i) {
return items.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
SingerItemView itemView = new SingerItemView(getApplicationContext());
SingerItem item = items.get(i);
itemView.setName(item.getName());
itemView.setMobile(item.getMobile());
itemView.setImage(item.getResId());
return itemView;
}
}
}
그리고 생성자도 전부 마지막에 이미지 id 까지 추가해준다.