Android > listview - 커스텀리스트뷰 - Tag 사용
등록일 : 2017-07-05 18:46
조회수 : 93,839
오늘은 현재까지 또는 앞으로도 안드로이드 어플을 개발할 때 가장 많이 해야할 작업인 Custom ListView를 만드는 방법에 대해서 알아봅시다.
더 나아가 Tag를 사용하여 각각의 리스트마다의 데이터를 가져와 행동을 할 수 있게 정의 하는 방법을 소개하겠습니다.
저와 함께 이 글을 끝까지 보신다면, 여러 분도 Custom ListView를 자유자제로 사용이 가능할 것이라고 굳게 믿습니다.
오늘의 목표는 다음의 화면으로 구성되는 리스트뷰 만드는 것입니다.
위에서 통화 버튼(오른쪽)을 클릭시에 리스트에 입력된 전화번화를 Toast로 띄어 주는 것이 목표입니다.
Custom ListView의 제작단계는 다음과 같습니다.
1. Custom ListView Layout 정의하기
2. ListView의 한 Item의 정보를 저장할 Class 정의하기
3. ListView를 그려 줄 Adapter 정의하기
4. 사용하기
저의 경우는 목표와 같은 리스트 아이탬 레이아웃을 만들기 위해서 list_item_layout.xml 을 생성하여 작성하였습니다.
1. Custom ListView Layout 정의하기
listview_item.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="wrap_content"
android:padding="10dp" >
<ImageView
android:id="@+id/user_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="@string/notify" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/user_icon"
android:orientation="vertical" >
<TextView
android:id="@+id/user_name"
style="@style/small_text01"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:textSize="18sp" />
<TextView
android:id="@+id/user_phone_number"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:textSize="18sp" />
</LinearLayout>
<ImageButton
android:id="@+id/btn_send"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/btn_send"
android:contentDescription="@string/send" />
</RelativeLayout>
2. ListView의 한 Item의 정보를 저장할 Class 정의하기
이제 리스트뷰의 아이템 하나하나의 정보를 저장할 클래스를 에 생성해 주면 됩니다.
현재의 목표를 이루기 위해서 리스트뷰에 가져와야 할 정보들은 사용자아이콘, 이름 그리고 전화번호가 있습니다.
이를 저장할 하나의 클래스를 생성해주면 됩니다. 이 클래스는 정보를 저장(Set)할 생성자와 정보를 가져올 Getter를 만들어 주셔야 합니다.
ListView_User.java
public class ListView_User {
private Drawable mUserIcon;
private String mUserName;
private String mUserPhoneNumber;
ListView_User(Drawable userIcon, String userName, String userPhoneNumber) {
mUserIcon = userIcon;
mUserName = userName;
mUserPhoneNumber = userPhoneNumber;
}
public Drawable getUserIcon(){
return mUserIcon;
}
public String getUserName() {
return mUserName;
}
public String getUserPhoneNumber() {
return mUserPhoneNumber;
}
}
3. Adapter 생성하기
지금 생성할 Adpater는 ListView에 생성한 Layout을 맞추어 붙여주는 녀석이라고 생각하면 됩니다. Adapter의 행동은 다음과 같습니다.
1. 리스트의 한 아이템에 대한 정보를 가지고 있는 클레스 인스턴스를 받아옵니다.
2. inflater를 사용하여 미리 정의해둔 하나의 아이템 레이아웃을 가져 옵니다.
3. "1"에서 가져온 객체의 정보를 "2"에서 가져온 레이아웃에 넣어 줍니다.
4. 뷰를 반환해준다.
Adapter를 생성하기 위해서는 적합한 adapter를 상속받아야 합니다.
생성자를 생성해주시고, getView함수를 작성해주면 됩니다.
BaseAdapter를 사용한다면 데이터를 저장할 배열을 하나 만들고 배열에 정보를 저장하는 함수를 생성합니다.
또 자동생성된 함수의 몇몇 부분을 체워 줍니다. 소스코드에 자세한 주석을 달았습니다. 확인해주세요^^.
ListView_Adapter.java
public class ListView_Adapter extends BaseAdapter implements OnClickListener {
// Activity에서 가져온 객체정보를 저장할 변수
private ListView_User mUser;
private Context mContext;
// ListView 내부 View들을 가르킬 변수들
private ImageView imgUserIcon;
private TextView tvUserName;
private TextView tvUserPhoneNumber;
private ImageButton btnSend;
// 리스트 아이템 데이터를 저장할 배열
private ArrayList<ListView_User> mUserData;
public ListView_Adapter(Context context) {
super();
mContext = context;
mUserData = new ArrayList<ListView_User>();
}
@Override
/**
* @return 아이템의 총 개수를 반환
*/
public int getCount() {
// TODO Auto-generated method stub
return mUserData.size();
}
@Override
/**
* @return 선택된 아이템을 반환
*/
public ListView_User getItem(int position) {
// TODO Auto-generated method stub
return mUserData.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
/**
* getView
*
* @param position - 현재 몇 번째로 아이템이 추가되고 있는지 정보를 갖고 있다.
* @param convertView - 현재 사용되고 있는 어떤 레이아웃을 가지고 있는지 정보를 갖고 있다.
* @param parent - 현재 뷰의 부모를 지칭하지만 특별히 사용되지는 않는다.
* @return 리스트 아이템이 저장된 convertView
*/
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = convertView;
// 리스트 아이템이 새로 추가될 경우에는 v가 null값이다.
// view는 어느 정도 생성된 뒤에는 재사용이 일어나기 때문에 효율을 위해서 해준다.
if (v == null) {
// inflater를 이용하여 사용할 레이아웃을 가져옵니다.
v = ((LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.listview_item, null);
// 레이아웃이 메모리에 올라왔기 때문에 이를 이용하여 포함된 뷰들을 참조할 수 있습니다.
imgUserIcon = (ImageView) v.findViewById(R.id.user_icon);
tvUserName = (TextView) v.findViewById(R.id.user_name);
tvUserPhoneNumber = (TextView) v
.findViewById(R.id.user_phone_number);
btnSend = (ImageButton) v.findViewById(R.id.btn_send);
}
// 받아온 position 값을 이용하여 배열에서 아이템을 가져온다.
mUser = getItem(position);
// Tag를 이용하여 데이터와 뷰를 묶습니다.
btnSend.setTag(mUser);
// 데이터의 실존 여부를 판별합니다.
if (mUser != null) {
// 데이터가 있다면 갖고 있는 정보를 뷰에 알맞게 배치시킵니다.
if (mUser.getUserIcon() != null) {
imgUserIcon.setImageDrawable(mUser.getUserIcon());
}
tvUserName.setText(mUser.getUserName());
tvUserPhoneNumber.setText(mUser.getUserPhoneNumber());
btnSend.setOnClickListener(this);
}
// 완성된 아이템 뷰를 반환합니다.
return v;
}
// 데이터를 추가하는 것을 위해서 만들어 준다.
public void add(ListView_User user) {
mUserData.add(user);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// Tag를 이용하여 Data를 가져옵니다.
ListView_User clickItem = (ListView_User) v.getTag();
switch (v.getId()) {
case R.id.btn_send:
Toast.makeText(mContext, clickItem.getUserPhoneNumber(),
Toast.LENGTH_SHORT).show();
break;
}
}
}
4. 사용하기
자 이제 필요한 작업이 모두 끝났습니다. 이제 사용하기만 하면 됩니다. 사용법은 다음과 같습니다.
사용할 Activity 또는 fragment의 레이아웃에 리스트뷰 하나를 추가시켜 줍니다.
listview.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="match_parent">
<ListView
android:id="@+id/user_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</RelativeLayout>
다음으로는 Activity 또는 Fragment에서 다음의 과정을 해주시면 됩니다.
1. Adapter 생성
2. ListView 참조 후 Adapter 붙이기
3. 데이터 추가
4. 데이터 변경이 끝났다는 것을 Adapter에게 알려준다.
public class ListView_Main extends Activity {
private ListView userList;
private ListView_Adapter adapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO Auto-generated method stub
setContentView(R.layout.listview);
// Adapter 생성
adapter = new ListView_Adapter(getApplicationContext());
// 리스트뷰 참조 및 Adapter달기
userList = (ListView) findViewById(R.id.user_list);
userList.setAdapter(adapter);
// Data 추가
ListView_User u1 = new ListView_User(getResources().getDrawable(
R.drawable.icon_user1), "김씨", "010-1234-5678");
adapter.add(u1);
ListView_User u2 = new ListView_User(getResources().getDrawable(
R.drawable.icon_user1), "이씨", "010-8765-4321");
adapter.add(u2);
ListView_User u3 = new ListView_User(getResources().getDrawable(
R.drawable.icon_user1), "박씨", "010-0000-0000");
adapter.add(u3);
// Data가 변경 되있음을 알려준다.
adapter.notifyDataSetChanged();
}
}