커스텀 리스트뷰를 만들기 위해서 필요한 것들
    - xml 레이아웃 하나
    - 레이아웃에서의 listview 하나
    - 틀로 사용할 class 하나
    - 중간 연결다리 역할의 ArrayList 하나
    - ArrayAdapter를 상속받은 클래스 하나


결과로 만들어질 커스텀 리스트 뷰

하나의 틀에는
TextView 2개, 이미지 버튼 2개가 사용되었다.

이미지 버튼은 클릭이벤트가 있다.

 







1. 틀로 사용할 class 만들기
    실제 리스트에는 4개의 view가 있지만, 사실상 데이터를 입력받는 뷰는 textview 2개뿐이다.
    text 2개를 가지고 있을 수 있는 클래스를 만든다.

 class Contact {
private String Name;
private String PhoneNumber;
public Contact(String _Name, String _PhoneNumber)
{
this.Name = _Name;
this.PhoneNumber = _PhoneNumber;
}

public String getName() {
return Name;
}

public String getNumber() {
return PhoneNumber;
}
 } 

    주소록에 있는 데이터를 받아 올 클래스라서 이름을 contact라고 했다.(주소록은 contacts를 사용한다. 차이점을 두고자 s를 뺐다.)






2. ArrayList 만들기
    실제 데이터를 저장해서 가지고 있을 array list를 만든다. 
    화면에 출력되는건 후에 나올 코드의 결과로 나오는 커스텀 리스트 뷰이지만, 사실상 데이터는 array list가 가지고 있다.

 // arraylist 선언
 ArrayList<Contact> origin_list = new ArrayList<Contact>(); 

 array list는 위에서 만든 클래스의 형식으로 선언해준다. 클래스를 array로 가지고 있겠다는 의미이다.
 C에서 볼 수 있는 구조체 배열같은 기능을 해준다.

 // arraylist에 데이터 추가
 
 Contact temp;            // 데이터를 추가하는데 사용 할 객체 선언

 temp = new Contact("name1", "number1");    // 클래스 객체에 데이터 삽입
 origin_list.add(temp);                                 // array list에 데이터(객체) 추가
 temp = new Contact("name2", "number2");   
 origin_list.add(temp);

 이렇게 하면 2개의 데이터가 들어가 있는 array list가 만들어진다.
 add() 메소드를 통해 추가적으로 데이터를 계속 늘려갈 수 있다. 







3. xml layout
    사실 레이아웃은 틀을 잡는 것이라 사용할 뷰들이 있기만 하면 된다.
    내가 사용한 레이아웃은 LinearLayout을 사용했는데, 편의에 따라 Realative 등으로 사용하면 된다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:paddingTop="5px"
android:paddingBottom="5px" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout android:layout_width="320px"
android:layout_height="wrap_content" android:padding="6dip"
android:orientation="vertical">
<TextView android:id="@+id/toptext" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:gravity="center_vertical"
android:textSize="30px" android:textColor="@color/all_white"
android:ellipsize="end"></TextView>
<TextView android:id="@+id/bottomtext" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textSize="25px" android:textColor="@color/all_white"
android:singleLine="true" android:ellipsize="marquee"></TextView>
</LinearLayout>
<ImageButton android:id="@+id/button_call"
android:layout_width="80px" android:layout_height="60px"
android:layout_gravity="center_vertical"
android:src="@drawable/send_call" ></ImageButton>
<ImageButton android:id="@+id/button_message"
android:layout_width="80px" android:layout_height="60px"
android:layout_gravity="center_vertical" android:paddingLeft="10px"
android:src="@drawable/send_message" ></ImageButton>
</LinearLayout>  

    android:textColor ="@color/all_white" 에서의 값은 미리 strings.xml에 resource로 추가해둔 color 이다. 저렇게 쓰면 에러난다.


<resources>
...
...
    <color name="all_white">#FFFFFF</color>
    <color name="all_black">#000000</color>
</resources>









4. 액티비티에 연결되는 layout에서의 listview 하나 만들기
    실제로 setContentView 에 사용되는 R.layout 파일에 추가해두면 된다.

  <ListView android:id="@+id/main_listview"
             android:layout_width="fill_parent" android:layout_height="fill_parent"></ListView>
 










5. ArrayAdapter를 상속받은 클래스 만들기


 
    // Custom adapter Class
    private class ContactsAdapter extends ArrayAdapter<Contact> {
    
     private ArrayList<Contact> items;
     public ContactsAdapter(Context context, int textViewResourceId, ArrayList<Contact> items) {
super(context, textViewResourceId, items);
this.items = items;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

View v = convertView;

if ( v == null ) {

// vi(layoutInflater)는 Layout Inflater를 사용해 만든다.
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
// 현재의 position을 가지고 item을 가져온다. item은 이름과 전화번호가 들어있다.
Contact p = items.get(position);

if ( p != null )
{
// 2개의 텍스트뷰를 셋팅해준다.
TextView tt = (TextView)v.findViewById(R.id.toptext);
TextView bt = (TextView)v.findViewById(R.id.bottomtext);

// 셋팅한 텍스트뷰의 텍스트에 이름과 전화번호를 넣어준다.
tt.setText(p.getName());
bt.setText("  " + p.getNumber());
}         
// imagebutton 셋팅
     ImageButton ib_call = (ImageButton)v.findViewById(R.id.button_call);
     ImageButton ib_message = (ImageButton)v.findViewById(R.id.button_message);
       
     // 현재의 태그 입력, 이미지 버튼 클릭시 사용하기 위해 저장
     ib_call.setTag(position);
     ib_message.setTag(position);

// image button, send_call on click listner
ib_call.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 태그 불러오기
int position = Integer.parseInt( (v.getTag().toString()) );
Contact p = items.get(position);
if ( p != null ){
// 전화걸기 액티비티 실행
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + p.getNumber())));
}
}
});

// image button, send_message on click listner
ib_message.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 태그 불러오기
int position = Integer.parseInt( (v.getTag().toString()) );
Contact p = items.get(position);
// 문자보내기 액티비티 실행
if ( p != null ){
startActivity(new Intent(Intent.ACTION_SENDTO, Uri.parse("sms:" + p.getNumber())));
}
}
});     
return v;
}   
    }
  




    위의 아답타처럼 전화를 걸고 문자를 보내는 기능을 수행하려면 uses-permission이 필요하다.
    이는 AndroidManifest.xml 에 추가해 주어야 한다. </manifest> 윗부분에 추가해주면 된다.

    <uses-permission android:name = "android.permission.CALL_PHONE" ></uses-permission>  
    <uses-permission android:name = "android.permission.SEND_SMS"></uses-permission>
 









실제 더 이쁘게 꾸밀 수 있겠지만, 우선은 이정도에서 마무리.
커스텀 리스트뷰와 주소록접근 등을 합쳐서 전화번호검색주소록을 만들었다.
(사실 너무 간단한 어플이라 기능이랄것도 없는 어플이다. 필요에 의해 만들었다는 표현이 더 맞겠다.)
Posted by croute

댓글을 달아 주세요

  1. 방문객 2011.02.06 12:19  댓글주소  수정/삭제  댓글쓰기

    안녕하세요
    안드로이드 기초 공부하고 있는 학생입니다.
    제가 지금 배우고 있는데 실습해보려고 했던 것이 딱 위에 어플리케이션 입니다.
    구런데 어디가 잘못되었는지 위에 설명해주신 대로 아무리 해도 에러가 너무 많이 뜹니다.
    죄송하지만 혹시 위에 전체 소스를 좀 보여주실 순 없으신가요?
    정말 너무나 간저해서 이렇게 부탁드립니다.
    3일밤 새우고도 안되니 너무 스트레스가 받더군요;;;
    암튼, 가능하시다면 mh1022@hanmail.net로 연락 부탁드립니다.
    감사합니다^^

    • Favicon of https://croute.me BlogIcon croute 2011.02.06 13:16 신고  댓글주소  수정/삭제

      이 소스코드는 백업을 해두지 않아서 가지고있지는 않구요
      에러메시지를 써주시면 도움이 될 수 있을 것 같습니다.

      아마 ArrayAdapter 만드는 부분에서 에러가 나지 싶은데요.
      처음 시작하실때 이해가 잘 안되시는 부분에
      xml과 activity의 연결, xml과 adapter의 연결일거라고 생각됩니다.

      이 포스트에 있는 xml 코드는 adapter를 위한 코드입니다.
      하나의 row(inflater, 또는 view)를 만들어서
      getview에서 계속해서 돌면서 생산, 재활용하는 것입니다.

  2. 방문객 2011.02.08 10:11  댓글주소  수정/삭제  댓글쓰기

    감사합니다^^
    말씀하신대로 ArrayAdapter부분에서 The type ArrayList is not generic; it cannot be parameterized with arguments <Contact>
    이라고 에러가 나는데요,
    구글링으로 찾아서 자바 컴파일링레벨도 다 맞추고 했는데 안됩니다.
    혹시 해결방법이 있을까요?

    그리고 Arraylist클래스에서는extends activity를 쓸 필요가 없는게 맞나요?

    • Favicon of https://croute.me BlogIcon croute 2011.02.08 12:13 신고  댓글주소  수정/삭제

      기본적인 Activity를 사용하시면
      Activity 안에 ListView를 만드는거구요

      ListActivity였나.. ListActivity를 사용하면
      그 자체가 리스트인 activity이기때문에 그냥 쓰시면 됩니다.


      generic 문제가 발생하는것 같은데.
      그 부분에는 기본적으로는 Integer, String 등의
      arrayList안에 들어갈 데이터의 형(클래스)이 들어가면 됩니다.

      여기서는 String이 두개 넣을 것이기 때문에

      Contact 라는 클래스를 만들어서
      (클래스는 기본적으로 하나의 틀이 되는 것이기 때문에)
      그 안에 String 객체 2개를 만들고,
      그 Contact 클래스를 사용해 ArrayList를 만드는 것입니다.

  3. chrees 2012.07.05 19:13  댓글주소  수정/삭제  댓글쓰기

    안녕하세요^^
    Croute님의 글 잘 보았습니다.
    좋은 글 감사합니다.

    그런데 제가 그대로 따라해 보았는데
    Activity 쪽에서 리스트뷰에 어댑터를 추가하였더니 자꾸 오류가 나요... ㅠ_ㅠ
    혹시 괜찮으시다면 왜 그런지 알려주실 수 있을까요?

    다음과 같이 소스코드를 작성하였습니다.

    MP3Adapter adapter = new MP3Adapter(getApplicationContext(), R.id.text_mpitems, array);

    ListView list = (ListView)findViewById(R.id.listMP3);
    list.setAdapter(adapter);

    내일은 금요일이네요. 좋은 주말 되세요. ^^

    • Favicon of https://croute.me BlogIcon croute 2012.07.08 19:15 신고  댓글주소  수정/삭제

      안녕하세요~ ㅎㅎ

      실제 코드만 보고 유추하기에는,
      R.id.text_mpitems 또는 array 에서 문제가 생길것이라고 보는데요,

      R.id.text_mpitems를 통해 어댑터에서 각 row를 만들겁니다. 이때 제대로 view를 찾지 못하면 발생할 것 같구요,
      array가 생성(new)되지 않아도 에러가 날거구요.

      ListView에서 R.id.listMP3가 해당 액티비티에 없어도 에러가 날거구요.


      실제 코드보다는 에러코드(Log)를 보는것이 에러를 잡는데 용이합니다.

  4. chrees 2012.07.10 10:01  댓글주소  수정/삭제  댓글쓰기

    답변 정말 감사합니다. ^^

    그런데 array쪽이나 xml파일쪽은 잘 따라했는지 문제가 없는 것 같아요.

    extends ListActivity로 바꿔서

    setListAdapter(adapter);

    이렇게 적용시켰더니 아무 문제 없이 아주 잘 됩니다. ^^

    특정 listview에 listview.setAdapter(adapter); 로 적용시켰더니 자꾸 오류가 나네요. ㅠ_ㅠ

    ArrayAdapter랑 ListAdapter랑 상속관계가 없어서 그런가 싶기도 하고...

    아직 초보라 로그보고 고칠 자신은 없고...

    일단 애써보겠습니다. ㅠ_ㅠ

    답변 감사합니다!

  5. 생초보 2014.12.13 17:33  댓글주소  수정/삭제  댓글쓰기

    위의 방법으로 DB도 연동 시킬 수 있나요?

  6. 안드초보 2018.05.12 16:38  댓글주소  수정/삭제  댓글쓰기

    안녕하세요! 제가 지금 너무 필요한 부분인것같은데요 저 2번쨰 arraylist 만들기는 어디에다가 적어주는건가요..?