리스트뷰와 리싸이클러뷰는 프로젝트를 할때나 간단한걸 만들어볼때나.. 거의 리스트를 보여주기위해
자주 사용하는거라 한번쯤은 정리할 필요가 있는건 같아서 정리한다.
정리한 내용이 부족할지라도 계속 채워넣을 예정이니까 도움이 되었으면 좋겠다!
기록하는 습관은 중요하다고 생각한다. 작년이나 제작년에 한 내용들도 조금은 시간이 지났더라도 다시 차곡 차곡
기록하려고 한다. 그리고 안드로이드 스터디할때 대략적으로 필요한 개념들이라서..
ListView란 무엇일까? -->일단 그림을 먼저보자 난 그림을 보면서 관계에 대해서 파악하는게 좋았다 ㅋㅋ !!
리스트뷰를 알기전에 상위에있는 어댑터뷰에대해서 먼저 알아보자!
1.어댑터뷰(AdapterView)
어댑터뷰는 그림에서도 보이듯이 ViewGroup의 하위 클래스다.
어댑터뷰는 하위에 ListView, GridView, Spinner, Gallery등을 가지고 있다.
이런 어댑터뷰는 표시할 항목데이터(원본 데이터)를 어댑터(Adapter) 객체로부터 공급받는다.
어댑터에도 종류가 있는데 정리하자면..
2.Adapter종류
어댑터는 여러가지 아이템 중에서 하나를 선택하는 기능을 만들 때 많이 사용하는 클래스이고, 세로로 스크롤 되면서 리스트를 보여준다. 이런 위젯을 선택 위젯이라고 하는데 !
선택위젯은 어댑터(객체)를 사용하고 --> 어댑터는 원본 데이터를 읽어서 어댑터뷰에 제공!
--->어댑터뷰는 화면에 데이터를 나타내는 역할을 한다.!
어댑터는 데이터를 관리하고 뷰 객체를 만들어 리턴한다. 그러고나서 어댑터뷰에 항목으로 표시가 된다.
|
Adapter종류 |
ArrayAdapter |
배열에서 데이터를 가져온다. |
CursorAdapter |
데이터베이스(DB)에서 데이터를 가져온다 |
SimpleAdapter |
xml 파일에 있는 데이터를 사용한다. |
어댑터를 사용하기위해서는.. !! 어댑터 객체를 생성해야한다.
어댑터뷰마다 사용하는 파라미터가 있는데
ArrayAdapter는 생성할때 3개의 파라미터를 사용한다. (커서랑 심플어댑터는 나중에 설명하겠음)
ArrayAdapter(Context context , int resourceld, T[] objects);
context는 현재 컨텍스트 objects는 배열자료(원본 데이터)를 말한다.
ArrayAdapter를 이용한 listview를 만드는 순서는 이렇다.
1)원본 데이터를 String(문자열)로 만든다 String[]list = {"이순신","광개토대왕","신사임당", 등등등 } ;
2)어댑터를 생성한다(어댑터 역할: 원본 데이터를 가지고 가공해서, 어떻게 무엇을 보여줄지 정한다)
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
-->여기서 simple_list_item은 한개의 텍스트뷰다!
3)xml에 저장된 리스트뷰를 findViewById 메소드를 이용해서 ListView 객체에 대응시킨다.
ListView listview = (ListView) findViewById(R.id.ListView);
4)리스트뷰 객체 어댑터를 설정한다. 이 작업을 통해서 화면에 데이터가 보여진다.
listview.setAdapter(adapter);
5)항목을 터치했을 때 처리되는 이벤트를 넣는다.
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l){
//처리할 내용 -->하나의 항목을 터치했을 때 처리되는 내용 기입
}
} );
5)같은 경우는 항목을 터치했을 때 처리되는 이벤트를 주기 위해 사용하는 인터페이스다
OnItemClickListener()인터페이스를 사용하는건
버튼에 무명 클래스를 이용해서 리스너를 등록하는 방법과 같다.
OnItemClickListener는 1개의 메소드(onItemClick)을 가지고있다.
onItemCLick메소드는 사용자가 하나의 항목을 터치했을 때 자동으로 실행되는 콜백 메소드이고 4개의 파라미터를 받는다.
- adapterView : 클릭이 발생한 어댑터뷰
- view : view는 사용자가 클릭한 항목에 해당하는 뷰이다.
- i : Listview의 선택된 항목의 위치
- l : 터치한 항목의 줄(row) -->5)설명에 있는 리스너부분 파라미터 설명한거다!
아까 String으로 리스트를 하나 만들었는데 항목을 터치했을대 항목에 대해 설명하는 창이 나오도록 하려면
배열 데이터를 하나 더 만들어야 한다.
String[] list_explain = {
":조건시대의 장군. 임진왜란에서도 삼도수군통제사로 수군을 이끌고": +
"왜군을 물리치는 데 큰 공을 세웠다 " ,
":소수림왕의 정치적 안정을 기반으로 최대의 영토를 확장한" +
"고구려 19대 왕이다" , --> ...이런식으로!
}
사용자가 하나의 항목을 터치했을 때 자동으로 실행되는 onItemClick안에 Toast클래스를 이용해서
list와 list_explain 배열에 있는 데이터가 화면에 제시되도록 만들면 된다.
아까 5)에 있던 내용에
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l){
Toast.makeText(getApplicationContext(), ((TextView view).getText() +list_explain[i] , Toast.LENGTH_LONG).show();
}
// i값은 리스트뷰의 선택된 항목 위치다.
} );
저코드는 토스트창을 띄워주는데 텍스트뷰를 클릭했을시에 텍스트를 가져오는데
i번째에있는 값이 클릭되면 거기에 들어있는 텍스트뷰 이름 예를들어 이순신 을 가져오고
그 i값에 맞는 explain list를 가져오라는거다
그럼 결국엔 getText로 이순신을 가져오고 list_explain으로 :조선시대의 장군~ .... 값을 가져온다 .
근데 꼭 리스트뷰를 텍스트로 만들어서 가져오지않고
체크하는 아이템이라던가 여러개의 항목으로 만들어서 가져와도된다.
이렇게 Array에 넣어서 하는 방법도 있고
XML파일로 데이터에 입력해서 만드는 방법도 있다.
음 XML로 가져오는방법은 일단 생략하겠다 정리하려고 하는부분이 리사이클뷰가 주라서
XML을 데이터로 입력해서 가지고 오려면
getResources를 이용해서 xml로 저장되있는 데이터를 가져와서 list_explain변수에 담아서 사용한다.
final String[] list_explain = getResources.getStringArray(R.array.achievement);
ListActivity를 사용한 리스트뷰를 만드는 방법도 있다.
Activity클래스를 상속하는 대신에 ListActivity 클래스를 상속받아서 리스트뷰를 작성하면
SetContentView를 사용하지 않고도 리스트뷰를 만들 수 있다.
또 리스트뷰 객체를 만들 필요도 없다. setListAdapter를 이용하면 내부 리스트뷰와 원본 데이터를 쉽게 연결할 수 있다. onListItemClick메소드를 사용하면 항목을 클릭했을 때 리스너 등록 없이 쉽게 이벤트 처리를 해결할 수 있다.
onListItemClick메소드는 리스트뷰의 항목이 선택되면 자동으로 호출된다.
explain[]이라는 배열을 만들어 놓고,
people = new ArrayList<String>( );
people.add("이순신");
people.add("강감찬"); -->이런식으로 사람을 붙여버린다!
people.add("세종대왕");
그리고
ArrayAdapter<String> mAdapter;
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, people);
setListAdapter(mAdapter);
이렇게 붙여버리고 나서 아이템을 클릭했을때 처리는 어떻게 해주냐면
public void onListItemClick(ListView l, View v, int position , long id){
String message;
message = people.get(position)+":"+explain[position];
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show( );
}
파라미터값이 position인거지 i 로 이름을 변경해줘도 된다.
String으로 메세지를 선언해서 메세지 변수에 읽어오는 position값에 이름이랑 설명을 가져와서 변수에 넣어주는거다
그럼 결국에는 message변수에는 이름:설명 이렇게 들어가서 토스트로 출력된다.
위에 설명들은 하나의 텍스트뷰로 구성되어있는 항목만 다룬건데
그러면 하나의 항목에 1개의 이미지와 여러개의 텍스트뷰가 들어가게 하려면 어떻게 해야할까?
--> 일반적으로 BaseAdapter를 상속해서 사용한다. 상속을 하게 되면 몇 개의 메소드를 사용할 수 있다!!
BaseAdapter를 상속받으면 4개의 메소드를 오버라이딩 해야하는데
특히 getCount메소드와 getView메소드가 중요하다.
네개는 다음과 같다.
(1) public int getCount( ) (2) public Object getItem( ) (3) public long getItemId( ) (4) public View getView( )
특히 중요한 두개의 메소드에 대해서 설명하겠다 !!
메소드 |
기능 |
getCount( ) |
항목의 개수를 리턴해준다. |
get View( ) 메소드 |
각 항목에서 보여질 뷰를 리턴해준다. 항목의 개수만큼 반복 처리된다. 3개의 파라미터를 받는다! 첫 번째 파라미터는 항목(아이템)의 인덱스이다. 두 번째 파라미터는 현재 인덱스에 해당하는 뷰 객체이다. 세 번째 파라미터는 뷰를 포함하고 있는 부모 컨테이너 객체이다.
즉, getView( )메소드는 Adapter가 가지고 있는 데이터를 어떻게 보여줄지를 정의하는데 사용된다.
|
음 예를들어서
나라그림에 어떤나라이고 나라에 대한 설명을 내가 리스트로 보여주고싶다!
처음에 어떻게 할까? 일단 MainActivity에 ListView를 작성한다.
그리고 메인액티비티 메인코드에서 이미지와 텍스트 데이터를 어댑터에 추가하고 사용자가 항목을 터치했을 때
처리되는 내용을 AdapterView.OnItemClickListener( ) 에 사용하여 처리하면 된다.
총
<java>
IconDataBox.java
IconSetting.java
MainActivity.java
MyBaseAdapter.java
<res>
activity_main.xml
listlayout.xml
string.xml에는 값 미리 넣어주고..
위에서 설명했던 내용처럼 리스트뷰랑 어댑터뷰를 일단 선언한다! 그리고나서?!!!
1. 리스트뷰 객체를 참조한다.
listView = (ListView) findViewById(R.id.listView);
-->내가 메인액티비티 레이어에서 선언해줬던거
2.어댑터 객체를 생성한다(어댑터를 사용하려면 객체를 생성해줘야한다)
adapter = new MyBaseAdapter(this);
Resources res = getResources();
3.Strings.xml 안에 있는 데이터들을 가져와서 String배열에 넣는다.
위에 설명했던 방식처럼
final String[ ] nation = getResources( ).getStringArray(R.array.nation);
이렇게 이런 방식으로.. 가져온다!!
String[ ] explain = getResources( ).getStringArray(R.array.explain); 이렇게 등등등등 선언하면..
Srting[ ] population
final String[ ] capital
위에 그림처럼 항목별 이미지 한개와 택스트 3개를 어댑터(데이터 관리 및 처리)에 넣는다.
adapter.addItem(new IconDataBox(res.getDrawble(R.drawble.nation00),
nation[0], explain[0], population[0]);
nation나라 이미지를 , 나라이름 nation ,explain설명, 인구 population를 어댑터 데이터에 넣어준다.
데이터가 10개라면 [0]~[9] 이런식으로 !! 쭉쭉 넣어준다
getDrawble로 가져오는게 아까 위에 그림의 --> 이미지 고
nation 텍스트 1
population 텍스트2
explain 텍스트 3이다.
그리고 이제 리스트뷰에 어댑터를 설정한다
listView.setAdapter(adapter);
//리스트뷰에서 한 항목이 터치 되면 처리한다.
아까 위에서 설명한 온아이템 클릭리스너!!
listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view , int position, long id){
IconDataBox currentItem = (IconDataBox) adapter.getItem(position);
String[ ] currentData = currentItem.getData( );
//포지션에 있는 값을 가져와서 currentData에 넣어주는거다.
//화면에 터치한 나라 이름과 수도 나타내기
Toast.makeText(getApplicationContext( ) , nation[position] + ":"
+capital[position] , Toast.LENGTH_LONG).show( );
(아까 위에서 선언했던 친구들 다 불러오는거다 )
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater( ).inflate(R.menu.menu_main , menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId( );
if(id == R.id.action_settings){
return true;
}
return super.onOptionsItemSelected(item);
}
이제 메인 액티비티 부분은 끝났다. 이제는 아이템 항목을 위한 레이아웃을 넣어줘야 한다.
저위에 이런 형식이라고 보여준 이미지 부분! 저 레이아웃을 만들건데
listlayout.xml
처음에 리니어레이아웃을 수평으로 하여서
이미지1과 텍스트3개를 수평으로 배치하고
두번째 리니어레이아웃에 텍스트1과 텍스트2를 하나로 묶어서 텍스트3과 수직으로 배치한다.
그다음 두번째 리니어레이아웃 안에 리니어레이아웃을 하나 더만들어서 텍스트1과 텍스트2를 수평으로 배치한다.
listlayout.xml을 다루기 위해선 inflate개념에 대해 이해해야 하는데
xml파일로 레이아웃을 만들었다
그러면이제 리니어 레이아웃을 상속한 ItemView클래스를 만들어서 xml파일을 inflate해서 사용하게 한다.
inflate는 --> xml안에 있는 버튼, 이미지뷰등 여러 위젯들을
LayoutInflater 객체를 이용해서 inflate해서 매모리에 객체화되어 저장시킨다.
Layout Inflater inflater = (LayoutInflater) context.getSystemService
(Context. LAYOUT_INFLATER_SERVICES);
inflater.inflate (R.layout.listlayout, this , true);
getSystemService는 Context 클래스의 메소드다.
파라미터로 어떤 값을 전달하느냐에 다라서 다른 객체를 리턴해주는데
LAYOUT_INFLATER_SERVICES를 파라미터로 전달했으며
레이아웃 리소스를 inflate하는 LayoutInflater 객체를 반환하게 된다.
itemView.java에서는
리니어 레이아웃을 상속받고
이미지뷰와 텍스트뷰를 선언해준다
그리고
public ItemView(Context context, ItemDataBox aItem){
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context. LAYOUT_INFLATER_SERVICE);
inflate.inflate(R.layout.listlayout, this, this , true);
이렇게 가져온다!!
myImage = (ImageView) find~~
myImage = setImageDrawble(aItem.getImage( ) );
이런식으로
MyBaseAdapter 클래스는 ArrayList형태의 ItemDataBox 클래스를 사용했다.
그래서 마이베이스 어댑터클래스에는
어레이 리스트를 이용해서 데이터를 저장하고
ArrayList<ItemDataBox> mItems = new ArrayList<ItemDataBox>( );
public void addItem(ItemDataBox item) {
mItems.add(item); //ArrayList에 데이터를 추가한다.
}
어댑터에 항목을 등록하고 -->이부분이 중요한다
우리가 아까 메인액티비티 클래스에서 총 10개의 항목을 ItemDataBox 객체형태로
만든후에 어댑터 항목으로 추가등록했는데
ArrayList형태인 ItemDataBox에 모든 데이터를 넣도록 한다.
adapter.addItem(new ItemDataBox(res.getDrable(R.drawable.nation 00), nation[0], population[0],explain[0]));
그리고 getView메소드..
MyBaseAdapter 클래스는 BaseAdapter클래스를 상속받아서 겟뷰메소드를 가지고있는데
겟뷰메소드가 아까전에 어댑터에있는 모든 항목들을 화면에 나타나게 하는 역할을 한다고 했는데
getCount메소드를 통해 항목의 개수를 얻을 수 있고, 그 개수만큼 getView 메소드가 자동으로 실행된다
ItemDataBox.java 는
아이템 데이터박스 선언해서 데이터값을 가져온다.
그래서 MyBaseAdapter.java소스는 원본데이터를 가지고와서 관리하고 화면에 보여주는 역할을 한다.
스크롤로 새로운 리스트가 보여질때 그 위치를 알아내서 getView메소드를 호출해서 뷰를 생성하고 화면에 보여주게되는데 이때 스크롤되서 사라진 항목을 다시 스크롤해서 보고자할 때 그 항목을 매번 새로 생성하면 비효율적이니까
안드로이드는 그 뷰에대한 정보를 가지고잇다가 해당 리스트가 보여질때 자동으로 이미 생성되어있는 항목을
getView에 전달해줘서 같은것을 다시 생성하지 않게 해야한다.
이런 역할을 convertView가 한다. --> 컨버트뷰는 안드로이드가 전달해주는 해당 리스트 항목의 뷰다.
convertView가 null 이라는 것은 처음으로 항목이 제시된다는 의미고,
처음으로 리스트가 보여지기 때문에 new 연산자를 사용해서 새로 생성해야한다.
convertView값이 null이 아니라면 생성되었다가 그 후 스크롤 때문에 화면에서 사라졌다가
다시나타나는 경우기 때문에 이미 생성된 객체가 전달되며 이 객체에 필요한 데이터를 넣어서 리턴시키면 된다.
Recycle View에 대해 설명하려고 했는데..
리스트뷰를 쓰다보니까 많아져서.. 리사이클뷰에 대해 다음장에 서술하려고한다!!