오늘이라도
[Android] 21. 리스트 뷰(List View) ③ : 이미지 클릭 시 팝업창 띄우기, 팝업창에 클릭한 이미지 넣기 / 그리드 뷰(Grid View) : 프로젝트 복사, 이름 바꾸기, 라이브러리 추가 본문
취업성공패키지 SW 개발자 교육/Android
[Android] 21. 리스트 뷰(List View) ③ : 이미지 클릭 시 팝업창 띄우기, 팝업창에 클릭한 이미지 넣기 / 그리드 뷰(Grid View) : 프로젝트 복사, 이름 바꾸기, 라이브러리 추가
upcake_ 2020. 6. 3. 10:58반응형
https://github.com/upcake/Class_Examples
교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다.
gif 파일은 클릭해서 보는 것이 정확합니다.
- 리스트 뷰 ③ : 이미지 클릭 시 팝업창 띄우기, 팝업창에 클릭한 이미지 넣기 -
▼activity_main.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:orientation="vertical">
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="추가"
android:textSize="24sp" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/holo_blue_bright"/>
</LinearLayout>
▼MainActivity.java
package com.example.my27_listview2;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
/*
1. DB를 만든다
2. DB의 테이블과 똑같은 DTO를 만든다
3. DTO에서 표현하고자 하는 부분을 xml로 만든다
4. 어댑터를 만든다
5. 어댑터에 3에서 만든 xml을 표시할 ViewHolder Class를 만든다
5 - 1 : ViewHolder 작성
5 - 2 : xml 찾기
5 - 3 : getItem > Data 넣기
5 - 4 : 필요한 메서드 만든다.
메인 액티비티 - 리스트 뷰(껍데기)
껍데기에 내용물을 만들어서 보여주는 것이 어댑터
*/
public class MainActivity extends AppCompatActivity {
//객체 선언
Button button1;
ListView listView;
ArrayList<SingerDTO> list;
SingerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//디바이스 사이즈 구하기
Point size = getDeviceSize();
//객체 초기화
button1 = findViewById(R.id.button1);
listView = findViewById(R.id.listView);
list = new ArrayList<>();
//어댑터의 list에 데이터 추가
adapter = new SingerAdapter(MainActivity.this, list, size);
adapter.addDTO(new SingerDTO("가수1", "010-1111-1111", 30, R.drawable.singer1));
adapter.addDTO(new SingerDTO("가수2", "010-2222-2222", 21, R.drawable.singer2));
adapter.addDTO(new SingerDTO("가수3", "010-3333-3333", 25, R.drawable.singer3));
adapter.addDTO(new SingerDTO("가수4", "010-4444-4444", 33, R.drawable.singer4));
adapter.addDTO(new SingerDTO("가수5", "010-5555-5555", 38, R.drawable.singer5));
//리스트뷰에 어댑터를 붙여준다
listView.setAdapter(adapter);
//리스트뷰의 아이템 클릭했을때 이벤트 추가
//AdapterView<?> parent : 클릭이 발생한 어댑터뷰
//View view : 어댑터뷰 내부의, 클릭이 된 바로 그 뷰
//int position : 어댑터 내부의 그 뷰의 위치(position)
//long id : 클릭된 아이템의 row id
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SingerDTO dto = (SingerDTO) adapter.getItem(position);
Toast.makeText(MainActivity.this, "선택 : " + position + "\n이름 : " + dto.getName()
+ "\n전화번호 : " + dto.getPhoneNum() +"\n나이 : " + dto.getAge() + "\n이미지 : " +dto.getResId(), Toast.LENGTH_SHORT).show();
}
});
//버튼1(추가 버튼)에 기능 추가
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = "가수6";
String phoneNum = "010-6666-6666";
int age = 35;
int resId = R.drawable.image01;
SingerDTO dto = new SingerDTO(name, phoneNum, age, resId);
adapter.addDTO(dto);
//adapter.addDTO = (new SingerDTO(name, phoneNum, age, resId));
//adapter.addDTO = (new SingerDTO("가수6", "010-6666-6666", 35, R.mipmap.ic_launcher);
//리스트뷰 데이터 갱신
adapter.notifyDataSetChanged();
}
});
}
// 디바이스 가로 세로 사이즈 구하기
// getRealSize()는 status bar 등 system insets을
// 포함한 스크린 사이즈를 가져오는 방법이고,
// getSize()는 status bar 등 insets를
// 제외한 부분에 대한 사이즈만 가져오는 함수이다.
// 단위는 픽셀
public Point getDeviceSize() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
//현재 프로젝트에서는 쓰지 않지만 가로와 세로 길이를 이렇게 빼서 사용한다
int width = size.x;
int height = size.y;
return size;
}
}
▼SingerAdapter.java
package com.example.my27_listview2;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class SingerAdapter extends BaseAdapter {
//어댑터에 데이터를 받기위해 생성자 만든다.
// 컨텍스트와 리스트는 받아오지만 인플레이터는 안받아온다.
Context context;
ArrayList<SingerDTO> list;
Point size;
LayoutInflater inflater;
AlertDialog dialog;
public SingerAdapter(Context context, ArrayList<SingerDTO> list, Point size) {
this.context = context;
this.list = list;
this.size = size;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//인플레이터는 시스템에서 가져온다.
}
//리스트(list)에 항목을 추가해 줄 메서드 작성
public void addDTO(SingerDTO dto) {
list.add(dto);
}
//리스트의 항목을 삭제할 메서드 작성
public void delDTO(int position) {
list.remove(position);
}
//리스트의 항목을 모두 삭제할 메서드 작성
public void removeDTOs() {
list.clear();
}
//getCount() : 리스트에서 항목을 몇개나 가져와서 몇개의 화면을 만들 것인지 정하는 메서드
@Override
public int getCount() {
return list.size();
}
//getItem() : 리스트에서 해당하는 인덱스의 데이터(사진, 이름, 전번)를 모두 가져오는 메서드
//Object를 알아서 캐스팅해서 사용하라는 의미로 반환 타입이 Object
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
SingerViewHolder viewHolder;
//화면 구성
if(convertView == null) {
convertView = inflater.inflate(R.layout.singerview, parent, false);
viewHolder = new SingerViewHolder();
viewHolder.tvName = convertView.findViewById(R.id.tvName);
viewHolder.tvPhoneNum = convertView.findViewById(R.id.tvPhoneNum);
viewHolder.imageView = convertView.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else {
viewHolder = (SingerViewHolder) convertView.getTag();
}
//DTO에서 데이터를 찾음
SingerDTO dto = list.get(position);
String name = dto.getName();
String phoneNum = dto.getPhoneNum();
int resId = dto.getResId();
//XML의 화면에 찾은 데이터 표시
viewHolder.tvName.setText(name);
//viewHolder.tvName.setText(dto.getName()); // 이렇게 써도 같음
viewHolder.tvPhoneNum.setText(phoneNum);
viewHolder.imageView.setImageResource(resId);
//이미지만 클릭했을때 기능 추가
viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "선택 : " + position
+ ", 이름 : " + list.get(position).getName(), Toast.LENGTH_SHORT).show();
//방법 ① : 이미지뷰 추가하여 직접 붙임
//popUpImg(list.get(position).getResId());
//방법 ② : 미리 만들어둔 XML과 팝업창을 연결해서 보여줌
popupImgXml(list.get(position).getResId(), list.get(position).getName());
}
});
return convertView;
}
//따로 새 자바 파일을 만들지 않고 XML의 내용을 볼 수 있게끔 만든 클래스
public class SingerViewHolder {
public ImageView imageView;
public TextView tvName, tvPhoneNum;
}
//방법 ① : 이미지 뷰를 만들어서 직접 이미지 넣기
public void popUpImg(int resId) {
ImageView image = new ImageView(context);
image.setImageResource(resId);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("이미지 띄우기");
builder.setView(image);
builder.setNegativeButton("종료", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(dialog != null) {
dialog.dismiss();
}
}
});
dialog = builder.create();
dialog.show();
}
//방법 ② : XML 불러오기
public void popupImgXml(int resId, String name) {
//일단 res에 popupimg.xml 만든다
//그 다음 화면을 inflate 시켜 setView 한다
//팝업창에 xml 붙이기///////////////
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.popupimg, null);
ImageView imageView = view.findViewById(R.id.imageView);
TextView textView = view.findViewById(R.id.textView);
imageView.setImageResource(resId);
textView.setTextSize(35);
textView.setText(name + "\n");
textView.append(name + "\n" + name + "\n" + name + "\n" + name + "\n" + name + "\n" + name + "\n" + name + "\n" + name + "\n");
/////////////////////////
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("이미지 띄우기")
.setView(view);
builder.setNegativeButton("종료", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(dialog != null) {
dialog.dismiss();
}
}
});
dialog = builder.create();
dialog.show();
//디바이스 사이즈를 받아 팝업 크기창을 조절한다.
int sizeX = size.x;
int sizeY = size.y;
//AlertDialog에서 위치 크기 수정
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.x = (int) Math.round(sizeX * 0.005); // X위치
params.y = (int) Math.round(sizeY * 0.01); // Y위치
params.width = (int) Math.round(sizeX * 0.9);
params.height = (int) Math.round(sizeY * 0.8);
dialog.getWindow().setAttributes(params);
}
}
▼SingerDTO.java
package com.example.my27_listview2;
public class SingerDTO {
String name;
String phoneNum;
int age;
int resId;
public SingerDTO() {}
public SingerDTO(String name, String phoneNum, int age, int resId) {
this.name = name;
this.phoneNum = phoneNum;
this.age = age;
this.resId = resId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getResId() {
return resId;
}
public void setResId(int resId) {
this.resId = resId;
}
}
▼singerview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/singer1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="vertical">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center_vertical"
android:text="Name"
android:textColor="@android:color/holo_green_light"
android:textSize="35sp" />
<TextView
android:id="@+id/tvPhoneNum"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center_vertical"
android:text="PhoneNum"
android:textColor="@android:color/holo_orange_light"
android:textSize="25sp" />
</LinearLayout>
</LinearLayout>
▼popupimg.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:orientation="vertical"
android:weightSum="3">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
- 그리드 뷰(Grid View) : 프로젝트 복사, 이름 바꾸기 / 라이브러리 추가 -
□ 프로젝트 복사, 이름 바꾸기
- My27_ListView2 프로젝트 폴더의 사본을 만들고 이름을 My28_GridView로 바꾼다.
- app - java - com.example.my27_listview2 우클릭 - Refactor - Rename - Rename Package
- build.gradle의 applicationId를 패키지 이름에 맞게 변경한다.
- res - values - strings.xml 에서 어플리케이션 실행 화면 상단의 표시 이름을 변경한다.
□ 라이브러리 추가
- 상단 메뉴바 File - Project Structure - Dependencies - +버튼 - Library Dependencies - design 검색 - com.android.support 추가
- 버전을 28.0.0에서 29.0.0으로 바꾼다.
□ 작동 화면 및 코드
※ 위의 ListView2 프로젝트에서 변경된 부분만 코드를 작성했습니다.
▼activity_main.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:orientation="vertical">
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="추가"
android:textSize="24sp" />
<GridView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/holo_blue_bright"
android:numColumns="2"
android:horizontalSpacing="8dp"
android:verticalSpacing="8dp"
android:layout_margin="8dp"/>
</LinearLayout>
▼MainActivity.java
package com.example.my28_gridview;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
/*
1. DB를 만든다
2. DB의 테이블과 똑같은 DTO를 만든다
3. DTO에서 표현하고자 하는 부분을 xml로 만든다
4. 어댑터를 만든다
5. 어댑터에 3에서 만든 xml을 표시할 ViewHolder Class를 만든다
5 - 1 : ViewHolder 작성
5 - 2 : xml 찾기
5 - 3 : getItem > Data 넣기
5 - 4 : 필요한 메서드 만든다.
메인 액티비티 - 리스트 뷰(껍데기)
껍데기에 내용물을 만들어서 보여주는 것이 어댑터
*/
public class MainActivity extends AppCompatActivity {
//객체 선언
Button button1;
GridView gridView;
ArrayList<SingerDTO> list;
SingerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//디바이스 사이즈 구하기
Point size = getDeviceSize();
//객체 초기화
button1 = findViewById(R.id.button1);
gridView = findViewById(R.id.listView);
list = new ArrayList<>();
//어댑터의 list에 데이터 추가
adapter = new SingerAdapter(MainActivity.this, list, size);
adapter.addDTO(new SingerDTO("가수1", "010-1111-1111", 30, R.drawable.singer1));
adapter.addDTO(new SingerDTO("가수2", "010-2222-2222", 21, R.drawable.singer2));
adapter.addDTO(new SingerDTO("가수3", "010-3333-3333", 25, R.drawable.singer3));
adapter.addDTO(new SingerDTO("가수4", "010-4444-4444", 33, R.drawable.singer4));
adapter.addDTO(new SingerDTO("가수5", "010-5555-5555", 38, R.drawable.singer5));
//리스트뷰에 어댑터를 붙여준다
gridView.setAdapter(adapter);
//리스트뷰의 아이템 클릭했을때 이벤트 추가
//AdapterView<?> parent : 클릭이 발생한 어댑터뷰
//View view : 어댑터뷰 내부의, 클릭이 된 바로 그 뷰
//int position : 어댑터 내부의 그 뷰의 위치(position)
//long id : 클릭된 아이템의 row id
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SingerDTO dto = (SingerDTO) adapter.getItem(position);
Toast.makeText(MainActivity.this, "선택 : " + position + "\n이름 : " + dto.getName()
+ "\n전화번호 : " + dto.getPhoneNum() +"\n나이 : " + dto.getAge() + "\n이미지 : " +dto.getResId(), Toast.LENGTH_SHORT).show();
}
});
//버튼1(추가 버튼)에 기능 추가
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = "가수6";
String phoneNum = "010-6666-6666";
int age = 35;
int resId = R.drawable.image01;
SingerDTO dto = new SingerDTO(name, phoneNum, age, resId);
adapter.addDTO(dto);
//adapter.addDTO = (new SingerDTO(name, phoneNum, age, resId));
//adapter.addDTO = (new SingerDTO("가수6", "010-6666-6666", 35, R.mipmap.ic_launcher);
//리스트뷰 데이터 갱신
adapter.notifyDataSetChanged();
}
});
}
// 디바이스 가로 세로 사이즈 구하기
// getRealSize()는 status bar 등 system insets을
// 포함한 스크린 사이즈를 가져오는 방법이고,
// getSize()는 status bar 등 insets를
// 제외한 부분에 대한 사이즈만 가져오는 함수이다.
// 단위는 픽셀
public Point getDeviceSize() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
//현재 프로젝트에서는 쓰지 않지만 가로와 세로 길이를 이렇게 빼서 사용한다
int width = size.x;
int height = size.y;
return size;
}
}
▼singerview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/singer1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="vertical"
android:layout_marginLeft="5dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:gravity="center_vertical"
android:text="Name"
android:textColor="@android:color/holo_green_light"
android:textSize="16sp" />
<TextView
android:id="@+id/tvPhoneNum"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:gravity="center_vertical"
android:text="PhoneNum"
android:textColor="@android:color/holo_orange_light"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
반응형