도전과제 14
격자 형태로 쇼핑 상품을 보여주는 화면을 구성해 보세요. 격자 형태의 뷰에 보이는 각각의 아이템에는 상품의 이미지와 정보가 표시됩니다.
- 쇼핑 상품을 보여주는 화면을 리싸이클러뷰로 만듭니다..
- 리싸이클러뷰의 칼럼은 두 개로 하고 아이템은 가상의 데이터를 사용해 여러 개 입력해둡니다.
- 각각의 아이템에는 상품 이미지, 상품 이름, 가격, 간단한 설명이 보일 수 있도록 합니다.
- 리싸이클러뷰의 한 아이템을 터치했을 때 선택된 상품의 이름과 가격을 토스트로 간단하게 보여줍니다.
참고할 점
상단 버튼은 위쪽과 좌, 우의 연결점을 부모 레이아웃과 연결합니다.
하단 버튼은 아래쪽과 좌, 우의 연결점을 부모 레이아웃과 연결합니다.
가운데 버튼의 위쪽 연결점은 상단 버튼의 아래쪽 연결점과 연결합니다.
가운데 버튼의 아래쪽 연결점은 하단 버튼의 위쪽 연결점과 연결합니다.
풀이
우선 메인 레이아웃은 리사이클러뷰만 구성하였고, 리사이클러뷰에 띄울 아이템 레이아웃을 따로 정의해주었다. 이때 카드뷰의 배경색과 마진을 이용하여 테두리처럼 보이는 효과도 주었다.
도전과제 13번과 마찬가지로, 이름, 가격, 설명 그리고 사진을 속성으로 갖는 product 객체를 선언하였다.
이때 사진은 int형으로 표현하였는데, 그 이유는 이미 drawable에 저장해놓은 사진을 추가하려고 하는데, 이때 R.drawable로 접근하는 사진파일은 결국 int형 숫자 코드로 전달되기 때문이다.
이 Product객체를 리사이클뷰에 등록하고 보여줄 ProductAdapter객체 역시 onCreateViewHolder 메소드와 RecyclerView.ViewHolder를 상속하는 ViewHolder 객체를 정의하여 구현하였다. 이때, 아이템을 클릭했을 때의 동작을 구현하기 위해 itemView에서 onClickListener를 선언해 onItemClick 메소드가 position값과 함께 호출되도록 하였다.
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder> implements OnProductItemClickListener{
ArrayList<Product> items = new ArrayList<Product>();
OnProductItemClickListener listener;
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.product_item, parent, false);
return new ViewHolder(itemView, this);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Product item = items.get(position);
holder.setItem(item);
}
@Override
public int getItemCount() {
return items.size();
}
public void addItem(Product item){
items.add(item);
}
public Product getItem(int position){
return items.get(position);
}
@Override
public void onItemClick(ViewHolder holder, View view, int position) {
if(listener != null){
listener.onItemClick(holder, view, position);
}
}
public void setOnItemClickListener(OnProductItemClickListener listener){
this.listener = listener;
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
TextView textName;
TextView textCost;
TextView textNote;
public ViewHolder(View itemView, final OnProductItemClickListener listener){
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
textName = itemView.findViewById(R.id.textName);
textCost = itemView.findViewById(R.id.textCost);
textNote = itemView.findViewById(R.id.textNoti);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = getAdapterPosition();
if(listener != null){ //onItemClick 호출
listener.onItemClick(ViewHolder.this, view,position);
}
}
});
}
public void setItem(Product item){
textNote.setText(item.getNotification());
textName.setText(item.getName());
textCost.setText(item.getCost());
imageView.setImageResource(item.getPic());
}
}
}
이 동작을 위해서 onItemClick 메소드가 있는 OnProductItemClickListener 인터페이스를 선언하였고, 뷰 홀더에서는 미리 정의한 다른 리스너의 메소드를 호출하게 정의하였다. 또한 Adapter 외부에서 리스너를 설정할 수 있도록 하였다.
public interface OnProductItemClickListener {
public void onItemClick(ProductAdapter.ViewHolder holder, View view, int position);
}
클릭 이벤트는 리싸이클러뷰가 아니라 각 아이템에 발생하게 되므로, 뷰 홀더 안에서 클릭 이벤트를 처리할 수 있도록 만드는 것이 좋다고 한다.
뷰 홀더의 생성자로 뷰 객체가 전달되므로 뷰 객체에 OnClickListener를 설정하고, 클릭했을 때 onClick메소드가 선언되는데, 리스너 안에서 토스트 메시지를 띄우면 클릭했을 때의 기능이 변경될 때마다 어댑터를 수정해야 하기 때문에 객체 밖에서 리스너를 설정하고(OnProductItemClickListener) 설정된 리스너 쪽으로 이벤트를 전달받도록 하는 것이 좋아 이런 방식을 사용하였다.
이제 메인 액티비티에서 리사이클러뷰에 두 줄씩 추가할 것이니 GridLayoutManager를 추가하고 PersonAdapter 역시 추가해준다.
그리고 어댑터의 setOnItemClickListener를 설정해, 아이템 클릭 시 어댑터에서 해당 아이템의 객체를 가져와 원하는 토스트 메시지를 띄울 수 있도록 최종적으로 하였다.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
GridLayoutManager layoutManager = new GridLayoutManager(this,2);
recyclerView.setLayoutManager(layoutManager);
final ProductAdapter adapter = new ProductAdapter();
adapter.addItem(new Product("롱 코트", "90만" , "명절 기획상품", R.drawable.birdmissile1));
//중략...
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new OnProductItemClickListener() {
@Override
public void onItemClick(ProductAdapter.ViewHolder holder, View view, int position) {
Product item = adapter.getItem(position);
Toast.makeText(getApplicationContext(), "이름 : " + item.getName() + "\n 가격 : " + item.getCost() +
"\n 설명 : " + item.getNotification(),Toast.LENGTH_LONG).show();
}
});
}
}
결과
참고할 점은 뭘 원하는 것인지 잘 이해가 되지 않았다.
전체 소스 코드 : https://github.com/howtolivelikehuman/DoitAndroid/tree/master/DoitMission_14
'코딩 > Do it Android [JAVA]' 카테고리의 다른 글
도전과제 16 : 웹브라우저 화면 구성 (Do it 안드로이드 앱 프로그래밍) [JAVA] (0) | 2020.08.28 |
---|---|
도전과제 15 : 입력 화면의 애니메이션 (Do it 안드로이드 앱 프로그래밍) [JAVA] (2) | 2020.08.18 |
도전과제 13 : 리사이클러뷰에 고객 정보 추가하기 (Do it 안드로이드 앱 프로그래밍) [JAVA] (0) | 2020.08.17 |
도전과제 11,12 : 서비스에서 수신자로 메시지 보내기 (Do it 안드로이드 앱 프로그래밍) [JAVA] (0) | 2020.08.16 |
도전과제 10 : 기본 앱 화면 구성 (Do it 안드로이드 앱 프로그래밍) [JAVA] (0) | 2020.08.15 |
Comment