티스토리 뷰

Android

11. 리스트뷰, 그리드뷰 : ListView, GridView

알 수 없는 사용자 2018. 10. 14. 19:51


이번 포스팅에서는

리스트뷰와 그리드뷰를 

다루어 보도록 하겠습니다.

이 둘의 성격은 비슷하므로

예제는 그리드뷰를 통해서 

알아보도록 하겠습니다.

==========================================================


리스트뷰, 그리드뷰 : ListView, GridView




1. ListView, GridView : What?


 리스트뷰와 그리드뷰는 사용자가 정의한 데이터를 목록화하여 아이템 단위로 구성하여 화면에 출력하는 ViewGroup의 한 종류입니다. 


리스트뷰와 그리드뷰의 다른점은 리스트뷰는 1차원 형태, 그리드뷰는 2차원 형태라는 것입니다.

쉽게 말해 리스트뷰 경우에는 1열로만 나열할 수 있다면, 그리드뷰는 격자 형태로 1열 이상으로 데이터를 나열할 수 있는 것입니다.





2. ListView, GridView : When, Why?


 리스트뷰는 대표적으로 SMS 문자를 받으면 나타나는 목록이라든지, 전화번호부 같은 목록이 있습니다.

이러한 리스트뷰는 아이폰이나 안드로이드처럼 손가락으로 터치하는 방식을 사용하는 단말에서는 리스트뷰가 쉽고 직관적이기 때문에 여러 개의 아이템 중에 선택하는 기능을 넣을 때 더 자주 사용됩니다. 특히 웹으로 화면을 만들 때 많이 사용되는 테이블 형태의 위젯 대신에 모바일에서는 리스트를 사용하는 경우가 많은데 그 이유는 테이블과 같이 많은 정보가 한꺼번에 보이는 경우에는 사용자가 손가락으로 터치할 수 있는 영역이 너무 작기 때문입니다.

[출처] Do it! 안드로이드 앱 프로그래밍



 그리드뷰는 대표적으로 갤러리를 예로 들 수 있겠습니다.

그리드뷰는 리스트뷰와 같지만 단순히 1자로 나열하는 것이아니라 여러 열로 마치 행렬과 같은 구조로 나열할 수 있는 것입니다. 주로 화면이 큰 PC 또는 웹에서 자주 사용하는 테이블형태와 유사하게 데이터를 보여줍니다. 하지만 스마트폰의 터치에서는 그리드뷰보다 리스트뷰를 활용해 한 줄의 아이템을 여러 개의 열처럼 보이도록 만든 후 리스트뷰를 그냥 사용하는 경우가 더 많다고 합니다.


[그리드뷰 예시]





3. ListView, GridView : How?


 리스트뷰와 그리드뷰는 선택 위젯이라고 부릅니다. 일반 위젯과 달리 선택 위젯으로 부르는 이유는 어댑터 패턴을 사용하기 때문입니다. 데이터를 위젯이 아닌 어댑터에 설정해야 하며 화면에 보이는 뷰도 어댑터에서 만드는 것입니다.





 [참고] Do it! 안드로이드 앱 프로그래밍



위의 그림처럼 원본 데이터를 위젯이 직접 설정하지 않고 중간에 어댑터가 존재하여 리스트뷰와 그리드뷰에 들어갈 데이터를 관리하는 동시에 리스트뷰와 그리드뷰에 띄워줄 view를 결정하는 역할을 합니다.





정리한다면 위 그림과 같이 표현할 수 있습니다. 데이터를 가진 객체를 어댑터에서 관리하다가 선택 위젯 목록에 띄워줄 View를 결정하여 주는 것입니다.

즉, 데이터 객체에서 뽑은 데이터로 만들어진 ImageView, textView와 같은 집합들로 이루어진 또 하나의 뷰를 만들어 이 뷰를 선택 위젯 목록에 띄워주는 것입니다.

선택 위젯 목록에 존재하는 하나하나 아이템들도 뷰입니다.


그리드뷰의 경우에는 속성에 numColumns 속성이 있어 이 속성에 지정한 값이 열로 지정되어 격자 형태의 구성이 가능한 것입니다.

결국 그리드뷰와 리스트뷰의 구현할 때 차이는 numColumns의 유무 차이뿐입니다.






4. GridView : Example?



 ① 데이터 아이템이 담길 뷰를 위한 XML 레이아웃을 생성합니다.

 

[singeritem.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="wrap_content">

<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/singer" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView"
android:textSize="20dp" />

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView2"
android:textSize="20dp" />
</LinearLayout>
</LinearLayout>


왼쪽에는 이미지가, 오른쪽에는 이름과 전화번호가 올 수 있는 텍스트뷰를 2개 생성했습니다.




 ② 데이터 아이템을 위한 뷰의 기능을 정의할 클래스를 설계합니다.


[SingerViewer.java]

public class SingerViewer extends LinearLayout {

TextView textView;
TextView textView2;
ImageView imageView;
public SingerViewer(Context context) {
super(context);

init(context);
}

public SingerViewer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);

init(context);
}

public void init(Context context){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.singeritem,this,true);

textView = (TextView)findViewById(R.id.textView);
textView2 = (TextView)findViewById(R.id.textView2);
imageView = (ImageView) findViewById(R.id.imageView);
}

public void setItem(SingerItem singerItem){
textView.setText(singerItem.getName());
textView2.setText(singerItem.getTel());
imageView.setImageResource(singerItem.getImage());
}
}


클래스를 생성하면서 이 클래스는 위에서 생성한 singeritem.xml 레이아웃과 인플레이션하기 위해 LinearLayout을 상속하여 줍니다.


이후에 오버라이드를 통해 생성자 두 개를 생성하고 초기화를 위한 init() 메소드를 정의합니다.


- init() :

 SingerViwer 객체(데이터 아이템 뷰)가 생성되면서 호출되는 초기화를 위한 메소드로 singeritem.xml 레이아웃과 인플레이션을 해줍니다. 또한 뷰에서 사용할 텍스트뷰 2개와 이미지 뷰 2개의 id 값을 찾아줍니다.


- setItem() :

 어댑터에서 선택 위젯에 SingerViwer 객체를 띄우기 위해 호출되는 메소드로 SIngerItem 객체의 데이터를 각 텍스트뷰와 이미지뷰에 띄워주는 역할입니다.  





 ③ 어댑터에서 필요한 아이템을 하나의 객체로 만들어두기 위해 SingerItem 클래스를 정의합니다.


[SingerItem.java]

public class SingerItem {

private String name;
private String tel;
private int image;

public SingerItem(String name, String tel, int image) {
this.name = name;
this.tel = tel;
this.image = image;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTel() {
return tel;
}

public void setTel(String tel) {
this.tel = tel;
}

public int getImage() {
return image;
}

public void setImage(int image) {
this.image = image;
}
}


필요한 정보는 이미지와 전화번호, 그리고 이름이기 때문에 각 타입에 맞는 맴버 변수를 선언하고 생성자를 통해 초기화되도록 설정합니다.

안드로이드에서는 이미지 파일을 상수값으로 바꾸어 구별하기 때문에 int 타입의 변수를 선언합니다.


- get메소드, set메소드 :

 맴버변수는 직접 접근하지 않는 것이 객체지향에서 추구하는 방향이기 때문에 변수의 값을 얻어내는 get 메소드와 값을 설정해줄 수 있는 set 메소드를 정의합니다.

이는 getter and setter 기능을 통해 변수에 대한 메소드를 자동으로 생성할 수 있습니다.





 ④ 이제 만들어진 데이터와 뷰를 사용하여 선택 위젯에 띄울 수 있도록 어댑터를 정의합니다.


[MainActivity.java]

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);



}

class SingerAdapter extends BaseAdapter{
ArrayList<SingerItem> items = new ArrayList<SingerItem>();
@Override
public int getCount() {
return items.size();
}

public void addItem(SingerItem singerItem){
items.add(singerItem);
}

@Override
public SingerItem 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) {
SingerViewer singerViewer = new SingerViewer(getApplicationContext());
singerViewer.setItem(items.get(i));
return singerViewer;
}
}
}


MainActivity에서 내부클래스로 어댑터 클래스를 설계하겠습니다.

어댑터를 기능을 구현하기 위해서는 미리 정의된 BaseAdapter 클래스를 상속하여 정의하는데 이 클래스는 어댑터 클래스를 정의할 때 상속하는 가장 일반적인 클래스입니다. 이때 BaseAdapter 클래스가 추상 클래스이기 때문에 구현해야 할 메소드가 자동으로 정의하라고 선언됩니다.


- ArrayList<SingerItem> :

 우리는 앞서 생성한 SingerItem 클래스에 데이터 객체를 생성할 수 있도록 설계하였기 때문에 SingerItem객체를 ArrayList형태로 여러 개 저장할 수 있도록 items 변수를 생성합니다.

- addItem() :

 전달된 SingerItem 객체를 items 목록에 저장하기 위한 메소드입니다.

- getCount() : 

 어댑터에서 관리하는 아이템의 개수를 리턴해줍니다.

- getItem() :

 전달되는 특정 인덱스의 객체를 반환하기 위한 메소드입니다.

- getItemId() :

 아이템에 id를 세팅해주는 역할로 삭제, 검색 등 여러 가지 이유로 id를 세팅해주어 사용합니다.

- getView() :

 어댑터에서 가장 중요한 메소드로 이 메소드에서 리턴하는 뷰가 선택 위젯에 하나의 목록으로 출력됩니다. 

 즉, SingerViwer객체를 만들고 그 객체에 원하고자 하는 데이터를 전달되는 i(position)값을 통해 SingerItem 객체에서 찾아 SingerViwer 객체에 저장하고 뷰를 뿌려주는 것입니다.





 ⑤ 그리드뷰와 아이템을 추가할 수 있는 추가기능을 위한 메인 XML 레이아웃을 생성합니다.


[activity_main.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">


<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:orientation="horizontal">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="추가" />

<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="이름"
android:inputType="textPersonName" />

<EditText
android:id="@+id/editText2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="전화번호"
android:inputType="phone" />

</LinearLayout>

<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_below="@+id/linearLayout"
android:numColumns="2" />
</RelativeLayout>


그리드뷰를 사용하기 위해서 특별히 어려운 기술을 사용하지 않아도 됩니다. 안드로이드에서 만들어 놓은 그리드뷰를 띄우고 싶은 곳에다가 디자인하면 됩니다.

리스트뷰의 경우에는 상관없지만 그리드뷰의 경우에는 numColumns 속성을 설정해주어야합니다.





 ⑥ 그리드뷰에서 어댑터를 사용해 목록을 생성하고 목록의 아이템을 클릭했을 때의 기능을 구현합니다.


[MainActivity.java]

public class MainActivity extends AppCompatActivity {

GridView gridView;
EditText editText;
EditText editText2;
Button button;
SingerAdapter singerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

gridView = (GridView)findViewById(R.id.gridView);
editText = (EditText)findViewById(R.id.editText);
editText2 = (EditText)findViewById(R.id.editText2);
button = (Button)findViewById(R.id.button);

singerAdapter = new SingerAdapter();
singerAdapter.addItem(new SingerItem("소녀시대","010-1000-1000",R.drawable.singer));
singerAdapter.addItem(new SingerItem("티아라","010-2000-2000",R.drawable.singer2));
singerAdapter.addItem(new SingerItem("레드벨벳","010-3000-3000",R.drawable.singer3));
singerAdapter.addItem(new SingerItem("아이콘","010-4000-4000",R.drawable.singer4));
singerAdapter.addItem(new SingerItem("빅뱅","010-5000-5000",R.drawable.singer5));


gridView.setAdapter(singerAdapter);

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(),"이름 : "+ singerAdapter.getItem(i).getName().toString() + " , Tel : "+singerAdapter.getItem(i).getTel().toString(),Toast.LENGTH_LONG).show();

}
});

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = editText.getText().toString().trim();
String tel = editText2.getText().toString().trim();
singerAdapter.addItem(new SingerItem(name,tel,R.drawable.singer));

}
});



}

class SingerAdapter extends BaseAdapter{


...


}
}


다른 뷰와 마찬가지로 그리드뷰도 똑같이 id 값을 찾아주면 됩니다.

그리고 일반 클래스와 마찬가지로 내부에 정의한 SingerAdapter 객체를 new 연산자를 통해 생성해주면 됩니다.


목록에 띄울 아이템 정보는 미리 어댑터에 정의한 addItem() 메소드를 통해 객체를 바로 생성하여 추가해줍니다.


- setAdapter() :

선택 위젯에 적용할 어댑터를 설정해주는 역할입니다. 


- onItemClick() : 

선택위젯의 아이템 클릭 시 호출될 메소드입니다. 오버라이드 된 메소드이기 때문에 재정의를 통해 클릭 시 기능 구현이 가능합니다.


이제 마지막으로 아이템을 추가하기 위한 기능은 생성해둔 추가버튼에 기능을 addItem 메소드를 이용해 구현하면 됩니다.





 ⑦ 화면 출력해봅시다.



저는 그리드뷰의 numColumns 속성을 2로 했기 때문에 2열의 뷰를 생성했습니다.

왼쪽 사진과 같이 미리 추가해둔 아이템 목록이 2열로 출력됩니다.

그리고 MainActivity에 구현한 추가 기능을 통해 가운데 사진처럼 아이템을 추가할 수 있습니다.

마지막으로 아이템을 선택하면 토스트 메시지가 뜨는 것까지 확인 가능합니다!


=========================================================================================================


##예제는 Do it! 안드로이드 앱 프로그래밍의 예제를 토대로 작성했습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함