본문 바로가기
수업내용

20230720 Android CustomAdapter

by titlejjk 2023. 7. 20.

각 국가이미지를 클릭했을 때 클릭한 국가에대한 정보가 출력되보도록 하는 작업을 해보겠다.

 

이렇게 ListView를 만들어 준후에 margin값을 제거해주었다.

 

그 다음으로 ListView에 연결할 Adapter Class를 만들어준다.

 

 

package com.example.step03customadapter;

/*
*   ListView에 연결한 adapter 클래스를 정의하고
*
*
*/

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class CountryAdapter extends BaseAdapter {

    //모델의 갯수를 리턴하는 메서드
    @Override
    public int getCount() {
        return 0;
    }
    //i번째 index에 해당하는 모델을 리턴
    @Override
    public Object getItem(int i) {
        return null;
    }

    //i번째 index에 해당하는 모델의 아이디(프라이머리키)가 있다면 리턴 없으면 index를 리턴하여 리턴한 index값을 아이디로사용
    @Override
    public long getItemId(int i) {
        return 0;
    }

    //i번째 index에 해당하는 cell view를 리턴
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        return null;
    }
}

다음으로 국가하나하나의 정보를 담기 위해 DTO를 만들어준다.

 

 

 

 

 

 

그리고 필드와 생성자, Getter,Setter를 만들어준다.

package com.example.step03customadapter;

public class CountryDto {

    //필드
    private int resId; //출력할 이미지 리소스 아이디 R.id.austria 등등
    private String name; //나라의 이름
    private String content; //나라에 대한 자세한 설명

    //생성자
    public CountryDto(){}

    public CountryDto(int resId, String name, String content) {
        this.resId = resId;
        this.name = name;
        this.content = content;
    }

    public int getResId() {
        return resId;
    }

    public void setResId(int resId) {
        this.resId = resId;
    }

    public String getName() {
        return name;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

 

그러고 난 다음 CountryAdapter에 생성자의 인자로 전달된 값을 필드에 저장할 생성자와 필드를 추가해 준다.

 

 //필드
    
    Context context;
    
    int layoutRes;
    
    List<CountryDto> list;
    
    //생성자 생성 (첫번째 인자로는 Context, 두번째 인자로는 cell의 Layout resource id, 세번째는 모델)
    public CountryAdapter(Context context, int layoutRes, List<CountryDto> list){
        
    }

 

그런다음 MainActivity.java에서 adapter에 연결할 모델 객체 생성과 ListView에 연결할 adapter객체를 생성해준다.

이 때 cell의 Layout resource id는 아직 만들지 않아 기본값인 0을 사용한다.

 

package com.example.step03customadapter;

import android.os.Bundle;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


    //필드
    List<CountryDto> countries;

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

        //adapter에 연결할 모델 객체를 생성
        countries = new ArrayList<>();
        //ListView에 연결할 adapter 객체 생성
       CountryAdapter adapter = new CountryAdapter(this, 0, countries);

        //ListView의 참조값을 얻어와서
        ListView listView = findViewById(R.id.listView);
        //adapter 연결
        listView.setAdapter(adapter);
    }
}

 

다음으로 custom으로 사용할 listview_cell.xml 파일을 만들어준다.

 

만들어진 xml코드는 아래와 같다.

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</androidx.constraintlayout.widget.ConstraintLayout>

 

대충 구상은 아래와 같다

 

왼쪽 부터 이미지의 거리는 50dp 위아래는 10dp의 거기를 두게 할 것이다.

위처럼 설정해 준다음에 코드를 다시보면 아래와 같다.

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="120dp">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="50dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/belgium" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

직접 손으로 코드를 짠다면 굉장히 험난 할 것 같다..

 

그리고 국기 오른쪽에 TextView를 배치해보겠다.

Textview는 오른쪽으로 부터 50dp

 

 

ui의 크기는 dp단위 글자의 크기는 sp를 사용한다 dp를 사용하면 해상도와 상관없이 사용가능하다.

 

코드에서 폰트크기를 30sp로 설정도 해주었다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="120dp">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_marginStart="50dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="101dp"
        android:layout_marginBottom="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/textView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/germany" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="50dp"
        android:text="TextView"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

이렇게 다 만들어 준 후에 CountryAdapter의 두번째 인자인 cell의 layout resource id를 바꿔준다.

 

 //ListView에 연결할 adapter 객체 생성
       CountryAdapter adapter = new CountryAdapter(this, R.layout.listview_cell, countries);

 

이전 예제를 비교해보겠다.

 

//step02listview에 있는 adapter 객체 생성코드


//ListView 에 연결할 아답타 객체 생성하기
        // new ArrayAdapter<>( Context , layout resource , 모델 )
        adapter=new ArrayAdapter<>(
                this,
                android.R.layout.simple_list_item_1,
                names
        );

 

최대한 비슷하게 만들어보았다.

 

그런 다음 MainAcitivity.java 클래스에 샘플데이터를 넣어준다.

 

package com.example.step03customadapter;

import android.os.Bundle;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


    //필드
    List<CountryDto> countries;

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

        //adapter에 연결할 모델 객체를 생성
        countries = new ArrayList<>();

        //셈플데이터
        countries.add(new CountryDto(R.drawable.austria,
                "오스트리아", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.belgium,
                "벨기에", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.brazil,
                "브라질", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.france,
                "프랑스", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.germany,
                "독일", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.greece,
                "그리스", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.israel,
                "이스라엘", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.italy,
                "이탈리아", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.japan,
                "일본", "🤮"));
        countries.add(new CountryDto(R.drawable.korea,
                "대한민국", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.poland,
                "폴란드", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.spain,
                "스페인", "어쩌구.. 저쩌구.."));
        countries.add(new CountryDto(R.drawable.usa,
                "미국", "어쩌구.. 저쩌구.."));
        //ListView에 연결할 adapter 객체 생성
       CountryAdapter adapter = new CountryAdapter(this, R.layout.listview_cell, countries);

        //ListView의 참조값을 얻어와서
        ListView listView = findViewById(R.id.listView);
        //adapter 연결
        listView.setAdapter(adapter);
    }
}

 

 

 

package com.example.step03customadapter;

/*
    ListView 에 연결할 아답타 클래스 정의하기
    - BaseAdapter 추상 클래스를 상속 받아서 만든다.
*/

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class CountryAdapter extends BaseAdapter {
    //필드
    Context context;
    int layoutRes;
    List<CountryDto> list;

    //생성자  (컨텍스트, cell 의 layout 리소스 아이디, 모델)
    public CountryAdapter(Context context, int layoutRes, List<CountryDto> list){
        //생성자의 인자로 전달된 값을 필드에 저장한다.
        this.context=context;
        this.layoutRes=layoutRes;
        this.list=list;
    }

    //모델의 갯수를 리턴 하는 메소드
    @Override
    public int getCount() {

        return list.size();
    }
    // i 번째 인덱스에 해당하는 모델을 리턴
    @Override
    public Object getItem(int i) {
        return list.get(i);
    }
    // i 번째 인덱스에 해당하는 모델의 아이디(pk)가 있다면 리턴
    @Override
    public long getItemId(int i) {
        //없으면 인덱스를 리턴
        return i;
    }
    // i 번째 인덱스에 해당하는 cell view 를 리턴하기
    /*
         인자로 전달되는 i 번째  cell view 를 만들어서 리턴해야 한다.
         cell view 는  레이아웃 xml 문서를 전개해서 만들어야 한다.
         전개해서 만든 View 의 ImageView 와 TextView 에 적절한 데이터를 출력한다음
         View 객체를 리턴해 준다.
         cell view 는 모델의 갯수만큼 다 만드는것이 아니라 최소한의 갯수만 만들어서
         기존에 만들었던 View 객체를 재사용해야 한다.
     */
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        //만일 null 이면
        if(view == null){
            //레이아웃 xml 문서를 전개해서 View 객체를 새로 만든다.
            LayoutInflater inflater=LayoutInflater.from(context);
            view = inflater.inflate(layoutRes, viewGroup, false);
        }
        // i 에 해당하는 CountryDto 객체
        CountryDto dto=list.get(i);
        // View 객체 안에 있는 ImageView, TextView 의 참조값을 얻어온다.
        ImageView imageView=view.findViewById(R.id.imageView);
        TextView textView=view.findViewById(R.id.textView);
        // ImageView, TextView 에 정보를 출력한다.
        imageView.setImageResource(dto.getResId());
        textView.setText(dto.getName());
        // i 번째 인덱스에 해당하는 View 를 리턴해 준다.
        return view;
    }
}

 

새로 객체를 생성하는지 확인하기 위해 Log를 활용해 보았다 다음사진은 처음 디바이스를 실행했을 때 몇개가 출력되는지 확인해보는 사진이다.

총7개가 출력되었는데 한번 끝까지 내려보면 아래와 같다.

 

 

 

'수업내용' 카테고리의 다른 글

20230721 Android CustomAdapter 2  (0) 2023.07.21
20230721 CSS3 Flex  (0) 2023.07.21
20230720 CSS3 flex2  (0) 2023.07.20
20230719 Andoroid  (0) 2023.07.19
20230719 flex  (0) 2023.07.19

댓글