Development/Android

17. Custom Adapter

궁선이 2018. 5. 5. 01:43

오늘 포스팅 할 내용은
Custom Adapter 라는 이름으로는 잘 이해가 안되는 것입니다.
이것은 리스트 뷰, 그리드 뷰에 장착하여
내가 원하는 레이아웃을 리스트나 그리드에 보여주는 역할을 해줍니다.
물론 리스너도 장착해 레이아웃 속성들에 대한 이벤트도 수신하여 줍니다.
이번 포스팅에서는 ListView를 기준으로 설명하겠습니다.
다음 포스팅에서 GridView에도 사용해 볼 것입니다.

Custom Adapter을 리스트 뷰에 장착하는 순서는 다음과 같습니다.
1) 리스트뷰에 보여줄 레이아웃 제작
2) 레이아웃에 표시할 데이터들의 객체를 생성할 Data클래스 생성
3)Custom Adapter클래스를 생성하여 Base Adapter 상속 및 추상 메서드 구현
4)MainActivity에서 Adapter클래스의 객체 생성 및  ListView에 부착
5)변경사항 발생 시 notifyDataSetChanged()호출

리스트 뷰 생성은 저번 포스팅에서 진행하였으니 간략히 넘어가겠습니다.

1. 리스트 뷰에 보여줄 레이아웃 제작

다음 레이아웃의 xml 소스입니다.
이제 이 레이아웃을 리스트뷰에 부착할 것입니다.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_marginTop="10dp" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="80dp"> <ImageView android:id="@+id/iv_image" android:layout_marginLeft="20dp" android:layout_gravity="center_vertical" android:src="@drawable/hamnurger" android:layout_width="70dp" android:layout_height="65dp" /> <LinearLayout android:layout_weight="1" android:layout_marginLeft="10dp" android:layout_gravity="center_vertical" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:maxLength="9" android:ellipsize="end" android:id="@+id/tv_name" android:textSize="20dp" android:textColor="#f25b5b" android:layout_marginBottom="10dp" android:text="hamburger" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_pnum" android:text="01012341234" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> </LinearLayout>
2. Data 클래스 생성

위 레이아웃에서 표시할 데이터 들을 담을 Data클래스 입니다.
참고로 R.drawble.xx 는 int형입니다.

//Data.java public class Data{ private String name; private String call; private int category; public Data(String name, String call,int category){ this.name = name; this.call = call; this.category = category; } String getName(){ return name; } String getCall(){ return call; } int getCategory(){ return category; } }
3. Custom Adapter 생성

코드설명을 시작하도록 하겠습니다.

먼저 리스트뷰에 표시되는 list는 어댑터 안의 list입니다.
MainActivity의 ArrayList의 객체와 어댑터의 datalist를 연결시켜 MainActivity에서 list에 변화가 생기면 그 변화가 어댑터의 datalist에 전달됩니다.

Context는 MainActivity를 어댑터 안에서 접근하기 위해 지정해 놓았습니다.

ViewHolder는 우리가 리스트뷰에 적용할 레이아웃의 컴포넌트들에 접근하고 그 객체를 생성하기 위한 클래스입니다. 이 ViewHolder는 리스트뷰의 각 항목에 대한 View에 포함되어 따라다닙니다.

Inflater는 레이아웃을 리스트뷰에 붙이기위한 것입니다.

getView에대해서 중점으로 설명하겠습니다.
getView는 notiffySetDataChanged()가 호출되면 
MainActivity에서 어댑터에 붙여놓은 ArrayList의 갯수 만큼 호출됩니다.
각 position은 0 부터 ArrayList의 size-1 까지 호출이 되며,
리스트뷰의 해당 position의 메뉴칸을 인자로 넘겨받습니다.
앞에서 말했다시피 MainActivity와 어댑터의 ArrayList는 연결된 상태이므로
어댑터 내에서는 어댑터 내의 datalist에 접근해서 데이터를 수정하면 됩니다.

이 getView가 실질적으로 리스트뷰에 레이아웃을 붙여주는 역할을 합니다.
1) 처음 호출 시 각 리스트뷰 항목에는 View가 붙어있지 않아 null 입니다.
2) View가 없었으므로 레이아웃도 붙어있지 않으므로 레이아웃을 inflate해주며 View에 붙여놓을
ViewHolder도 생성하고 붙여줍니다.
3) 처음 호출한 것이 아니라면 View가 존재하므로 ViewHolder에 View에 있는 ViewHolder을 넘겨받습니다.
4) VIewHoler에 각 데이터에있는 데이터를 넘겨받아 세팅하여 줍니다.
5) view를 return하여줍니다.
6) 다음 position으로 이동합니다.

public class DataAdapter extends BaseAdapter{ private ArrayList<Data> dataList; private Context context; private ViewHolder viewHolder; private LayoutInflater inflater; public DataAdapter(Context context, ArrayList<Data> dataList){ this.context = context; this.dataList = dataList; this.inflater = LayoutInflater.from(context); } @Override public int getCount() { return dataList.size(); } @Override public Data getItem(int position) { return dataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final int x = position; View v = convertView; if (v == null) { viewHolder = new ViewHolder(); v = inflater.inflate(R.layout.menu, null); viewHolder.iv_image = (ImageView) v.findViewById(R.id.iv_image); viewHolder.tv_name = (TextView) v.findViewById(R.id.tv_name); viewHolder.tv_pnum = (TextView) v.findViewById(R.id.tv_pnum); v.setTag(viewHolder); }else{ viewHolder = (ViewHolder)v.getTag(); } viewHolder.iv_image.setImageResource(dataList.get(position).getCategory()); viewHolder.tv_name.setText(dataList.get(position).getName()); viewHolder.tv_pnum.setText(dataList.get(position).getCall()); return v; } class ViewHolder{ public ImageView iv_image = null; public TextView tv_name = null; public TextView tv_pnum = null; } }
4. MainActivity

자세한 설명은 생략하겠습니다.

public class MainActivity extends AppCompatActivity { ArrayList<Data> instanceList = new ArrayList<>(); Data data_container; DataAdapter dataAdapter; ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListView(); } public void initListView() { dataAdapter = new DataAdapter(this, instanceList); listView = (ListView) findViewById(R.id.listview); listView.setAdapter(dataAdapter); } }

설명이 다소 복잡한 감이 있습니다.
위 코드대로는 생성하여도 리스트에 아무 반응이 없을 것 입니다.
따로 ArrayList에 데이터를 추가해주어 테스트를 해보시기 바랍니다.
감사합니다.