안규 공부방

Android > listview - 커스텀리스트뷰 - 채팅 UI 예제

등록일 : 2017-07-05 18:48 조회수 : 423,118

카톡 같은 list 만들기는 카톡의 대화 내역처럼 나오도록 만드는 예제입니다.

custom list를 만들줄 알아야 하고 custom list에서 배경을 나인 패치를 사용하면 됩니다.

custom list를 만들려면 리스트로 사용할 xml을 준비해야 하는데요

아래와 같이 준비하였습니다.

핵심은 양쪽에 view를 두고 가운데 텍스트 뷰를 하나 둡니다.

view의 layout_weight를 각각1로 두고 사용안하는쪽을 GONE 처리 하면됩니다.

viewLeft.setVisibility(View.GONE);
 
	<?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="match_parent"
		android:layout_gravity="center_horizontal"
		android:orientation="horizontal"
		android:id="@+id/layout"
		android:gravity="center">

		<View        android:layout_width="wrap_content"
			android:layout_height="1dp"
			android:id="@+id/imageViewleft"
			android:background="#888888"
			android:layout_weight="1"
			android:layout_margin="10dp" />

		<TextView        android:id="@+id/text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#000000"
			android:text ="text"        />

		<View        android:layout_width="wrap_content"
			android:layout_height="1dp"
			android:id="@+id/imageViewright"
			android:background="#888888"
			android:layout_weight="1"
			android:layout_margin="10dp" />
	</LinearLayout>


리스트에 아이템을 추가할때에는 인자를 하나 더 둬서 오른쪽 왼쪽 어디에 둘건지를 결정합니다.

카톡에 보면 시간 변경선이 나오는 경우가 있는데 여기서는 2번 해당 경우 처리입니다.

View에 layout_height = 1dp로 설정하고 background색을 검은색으로 처리합니다.

- 리스트에 추가할때
		m_Adapter.add("처음",0);
		m_Adapter.add("이건 뭐지",1);
		m_Adapter.add("대화창이다",0);
		m_Adapter.add("2015/10/8",2);
		m_Adapter.add("쿨쿨",1);
		m_Adapter.add("쿨쿨쿨쿨",0);
		m_Adapter.add("재미있게",1);


- type에 따른 처리
		if( m_List.get(position).type == 0 ) {
			text.setBackgroundResource(R.drawable.inbox2);
			layout.setGravity(Gravity.LEFT);
			viewRight.setVisibility(View.GONE);
			viewLeft.setVisibility(View.GONE);
		}else if(m_List.get(position).type == 1){
			text.setBackgroundResource(R.drawable.outbox2);
			layout.setGravity(Gravity.RIGHT);
			viewRight.setVisibility(View.GONE);
			viewLeft.setVisibility(View.GONE);
		}else if(m_List.get(position).type == 2){
			layout.setGravity(Gravity.CENTER);
			viewRight.setVisibility(View.VISIBLE);
			viewLeft.setVisibility(View.VISIBLE);
		}
	


- 동작화면



이제부터 만드는 방법을 상세하게 알아보도록 하겠습니다.


1. 챗 백그라운드 이미지를 만듭니다. (나인패치)

res/drawable 폴더를 만들고 아래이미지 3개를 복사해 넣습니다.

       

inbox2.9.png   (입력메세지1 배경이미지)
outbox2.9.png   (입력메세지2 배경이미지)
datebg.9.png   (날짜 메세지 배경이미지)


2. activity_chatitem 만듭니다. (레이아웃)

layout/activity_chatitem.xml 내용입니다.
 
	<?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="match_parent"
		android:layout_gravity="center_horizontal"
		android:orientation="horizontal"
		android:id="@+id/layout"
		android:gravity="center">

		<View        android:layout_width="wrap_content"
			android:layout_height="1dp"
			android:id="@+id/imageViewleft"
			android:background="#888888"
			android:layout_weight="1"
			android:layout_margin="10dp" />

		<TextView        android:id="@+id/text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#000000"
			android:text ="text"        />

		<View        android:layout_width="wrap_content"
			android:layout_height="1dp"
			android:id="@+id/imageViewright"
			android:background="#888888"
			android:layout_weight="1"
			android:layout_margin="10dp" />
	</LinearLayout>



3. activity_main 만듭니다. (레이아웃)

layout/activity_main.xml 내용입니다.

채팅을 입력할 수 있는 EditText, Button 등의 위젯이 들어있는 Layout 이며 위에서 만든 custom listview를 포함시킬 Layout 입니다.

 
	<?xml version="1.0" encoding="utf-8"?>
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="vertical"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		>
		<LinearLayout
			android:layout_width="fill_parent"
			android:id="@+id/im1"
			android:layout_height="wrap_content"
			android:layout_weight="1"
			>
			<FrameLayout
				android:layout_width="fill_parent"
				android:layout_height="wrap_content">
				<ListView
					android:id="@+id/listView1"
					android:listSelector="#00000000"
					android:cacheColorHint="#00000000"
					android:divider="#000000"
					android:layout_width="fill_parent"
					android:layout_height="wrap_content"
					android:transcriptMode="alwaysScroll"/>
			</FrameLayout>
		</LinearLayout>
		<LinearLayout
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:background="#2F4F4F"
			android:layout_below="@id/im1"
			android:orientation="horizontal">
			<TextView
				android:layout_width="20dp"
				android:layout_height="wrap_content"
				/>
			<EditText
				android:hint="메세지를 입력하세요"
				android:id="@+id/editText1"
				android:inputType="textMultiLine"
				android:maxLines="4"
				android:layout_width="200dp"
				android:layout_height="wrap_content"/>

			<Button
				android:id="@+id/button1"
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:text="전 송" />

		</LinearLayout>
	</LinearLayout>
	


3. MainActivity.java 만듭니다.
 
		public class MainActivity extends Activity {
			   ListView m_ListView;
			   CustomAdapter m_Adapter;
			@Override
			protected void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.activity_main);
				
				// 커스텀 어댑터 생성
				m_Adapter = new CustomAdapter();

				// Xml에서 추가한 ListView 연결
				m_ListView = (ListView) findViewById(R.id.listView1);

				// ListView에 어댑터 연결
				m_ListView.setAdapter(m_Adapter);
				
				m_Adapter.add("이건 뭐지",1);
				m_Adapter.add("쿨쿨",1);
				m_Adapter.add("쿨쿨쿨쿨",0);
				m_Adapter.add("재미있게",1);
				m_Adapter.add("놀자라구나힐힐 감사합니다. 동해물과 백두산이 마르고 닳도록 놀자 놀자 우리 놀자",1);
				m_Adapter.add("재미있게",1);
				m_Adapter.add("재미있게",0);
				m_Adapter.add("2015/11/20",2);
				m_Adapter.add("재미있게",1);
				m_Adapter.add("재미있게",1);
						
			}

		}


Adapter 에 연결하여 추가하는 간단한 예제 입니다.

실제 처리는 CustomAdapter.java 파일에서는 모두 처리하게 됩니다.

다음은 CustomAdapter 에서 처리하는 로직을 보겠습니다.


4. CustomAdapter.java 만듭니다.
 
		public class CustomAdapter extends BaseAdapter {
			public class ListContents{
				String msg;
				int type;
				ListContents(String _msg,int _type)
				{
					this.msg = _msg;
					this.type = _type;
				}
			}

			private ArrayList m_List;
			public CustomAdapter() {
				m_List = new ArrayList();
			}
			// 외부에서 아이템 추가 요청 시 사용
			public void add(String _msg,int _type) {

				m_List.add(new ListContents(_msg,_type));
			}

			// 외부에서 아이템 삭제 요청 시 사용
			public void remove(int _position) {
				m_List.remove(_position);
			}
			@Override
			public int getCount() {
				return m_List.size();
			}

			@Override
			public Object getItem(int position) {
				return m_List.get(position);
			}

			@Override
			public long getItemId(int position) {
				return position;
			}

			@Override
			public View getView(int position, View convertView, ViewGroup parent) {
				final int pos = position;
				final Context context = parent.getContext();

				TextView        text    = null;
				CustomHolder    holder  = null;
				LinearLayout    layout  = null;
				View            viewRight = null;
				View            viewLeft = null;



				// 리스트가 길어지면서 현재 화면에 보이지 않는 아이템은 converView가 null인 상태로 들어 옴
				if ( convertView == null ) {
					// view가 null일 경우 커스텀 레이아웃을 얻어 옴
					LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
					convertView = inflater.inflate(R.layout.activity_chatitem, parent, false);

					layout    = (LinearLayout) convertView.findViewById(R.id.layout);
					text    = (TextView) convertView.findViewById(R.id.text);
					viewRight    = (View) convertView.findViewById(R.id.imageViewright);
					viewLeft    = (View) convertView.findViewById(R.id.imageViewleft);


					// 홀더 생성 및 Tag로 등록
					holder = new CustomHolder();
					holder.m_TextView   = text;
					holder.layout = layout;
					holder.viewRight = viewRight;
					holder.viewLeft = viewLeft;
					convertView.setTag(holder);
				}
				else {
					holder  = (CustomHolder) convertView.getTag();
					text    = holder.m_TextView;
					layout  = holder.layout;
					viewRight = holder.viewRight;
					viewLeft = holder.viewLeft;
				}

				// Text 등록
				text.setText(m_List.get(position).msg);

				if( m_List.get(position).type == 0 ) {
					text.setBackgroundResource(R.drawable.inbox2);
					layout.setGravity(Gravity.LEFT);
					viewRight.setVisibility(View.GONE);
					viewLeft.setVisibility(View.GONE);
				}else if(m_List.get(position).type == 1){
					text.setBackgroundResource(R.drawable.outbox2);
					layout.setGravity(Gravity.RIGHT);
					viewRight.setVisibility(View.GONE);
					viewLeft.setVisibility(View.GONE);
				}else if(m_List.get(position).type == 2){
					text.setBackgroundResource(R.drawable.datebg);
					layout.setGravity(Gravity.CENTER);
					viewRight.setVisibility(View.VISIBLE);
					viewLeft.setVisibility(View.VISIBLE);
				}

				

				// 리스트 아이템을 터치 했을 때 이벤트 발생
				convertView.setOnClickListener(new OnClickListener() {

					@Override
					public void onClick(View v) {
						// 터치 시 해당 아이템 이름 출력
						Toast.makeText(context, "리스트 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();                                
					}
				});

				

				// 리스트 아이템을 길게 터치 했을때 이벤트 발생
				convertView.setOnLongClickListener(new OnLongClickListener() {

					@Override
					public boolean onLongClick(View v) {
						// 터치 시 해당 아이템 이름 출력
						Toast.makeText(context, "리스트 롱 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();
						return true;
					}
				});

				return convertView;
			}

			private class CustomHolder {
				TextView    m_TextView;
				LinearLayout    layout;
				View viewRight;
				View viewLeft;
			}
		}
		


ViewHolder 에 대한 소스가 포함되어 있습니다.

ViewHolder 는 getView의 속도 향상을 위해 사용됩니다.

한번의 findViewByID 로 재사용 하기 위해 viewHolder를 사용 합니다.

샘플소스 입니다.
 
※ 혹시 도움이 되셨다면 댓글에 한마디 남겨주세요!
작성자   비밀번호
자동글 방지     (자동글 방지 기능입니다.)
내용   댓글달기 
ssd    2020-04-29 19:42
삭제
저도 msg랑 type에서 글씨가 빨갛게 뜨는데 알수 있을까요
 
eo    2017-10-18 11:07
삭제
text.setText(m_List.get(position).msg);

if( m_List.get(position).type == 0 ) {
text.setBackgroundResource(R.drawable.inbox2);
layout.setGravity(Gravity.LEFT);
viewRight.setVisibility(View.GONE);
viewLeft.setVisibility(View.GONE);
}else if(m_List.get(position).type == 1){
text.setBackgroundResource(R.drawable.outbox2);
layout.setGravity(Gravity.RIGHT);
viewRight.setVisibility(View.GONE);
viewLeft.setVisibility(View.GONE);
}else if(m_List.get(position).type == 2){
text.setBackgroundResource(R.drawable.datebg);
layout.setGravity(Gravity.CENTER);
viewRight.setVisibility(View.VISIBLE);
viewLeft.setVisibility(View.VISIBLE);
}
이 부분에서 msg , type 쪽이 빨간줄로 에러나는데 왜그럴까요?
 
이메일 문의 : cak0280@nate.com  
Copyright 2000 By ENTERSOFT.KR All Rights Reserved.