본문 바로가기
안드로이드 자바

[Java][Android] 안드로이드 - 프래그먼트에 카드뷰, 리사이클러뷰만들기

by teamnova 2021. 7. 15.

프래그먼트에 카드뷰(CardView)와 리사이클러뷰(RecyclerView)를 사용하여 리스트를 만들어 보겠습니다.

 

- build.gradle(Module :app) 파일에 카드뷰와 리사이클러뷰를 추가해 줍니다.

dependencies {
    //리사이클러뷰
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
   // 카드뷰
    implementation "androidx.cardview:cardview:1.0.0"
}

- 프래그먼트 xml에 리사이클러뷰를 넣어줍니다.

- 아이템으로 넣을 xml을 구성합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:id="@+id/cardView"
        card_view:cardCornerRadius="1dp"
        card_view:cardElevation="15dp"
        >

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

            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="#eee">


                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:paddingLeft="16dp"
                    android:paddingRight="16dp"
                    android:background="#fff"
                    android:layout_marginBottom="1dp">


                    <!--   <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_alignParentStart="true"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="1dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginRight="10dp"
                        android:orientation="vertical">-->

                    <TextView
                        android:id="@+id/tvCategoryCV"
                        android:layout_width="92dp"
                        android:layout_height="21dp"
                        android:layout_alignParentStart="true"
                        android:layout_alignParentEnd="true"
                        android:layout_marginStart="1dp"
                        android:layout_marginTop="15dp"
                        android:layout_marginEnd="262dp"
                        android:shadowColor="#0B0A0A"
                        android:text="카테고리"
                        android:gravity="center_vertical"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:textColor="#050404"
                        android:textSize="10dp" />

                    <TextView
                        android:id="@+id/tvTitleCV"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/tvCategoryCV"
                        android:layout_alignParentStart="true"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentBottom="true"
                        android:layout_marginStart="1dp"
                        android:layout_marginTop="10dp"
                        android:layout_marginBottom="5dp"
                        android:shadowColor="#0B0A0A"
                        android:text="제목"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:textColor="#050404"
                        android:gravity="center_vertical"
                        android:textSize="17dp"
                        />
                    <!--
                                        </LinearLayout>
                    -->

                </RelativeLayout>
            </LinearLayout>

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

                <!--Contents-->
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="#fff"
                    android:padding="16dp">

                    <TextView
                        android:id="@+id/tvContentsCV"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentStart="true"
                        android:layout_marginStart="1dp"
                        android:text="글 내용..."
                        android:textSize="16sp" />
                </RelativeLayout>

                <!--이부분이 이미지 들어가는 부분-->
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:id="@+id/rl_image"
                    android:background="@color/white">
                    <!--
                                    <ImageView
                                        android:id="@+id/ivImageCV"
                                        android:layout_width="fill_parent"
                                        android:layout_height="wrap_content"
                                        android:adjustViewBounds="true"
                                        />-->
                    <!--        android:adjustViewBounds="true" 뷰 사이즈로 이미지를 키워줌, 그리고 이미지 비율을 유지하며 맞춤-->
                    <!--        android:maxHeight="600dp 는 adjustViewBounds 써야 유효하다. -->
                    <ImageView
                        android:id="@+id/ivImageCV"
                        android:foregroundGravity="right"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:maxHeight="100dp"
                        android:maxWidth="100dp"
                        android:adjustViewBounds="true"
                        android:background="#00ff0000"
                        />
                </RelativeLayout>

                <!--닉네임-->
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="#fff"
                    android:paddingLeft="16dp">

                    <TextView
                        android:id="@+id/tvNickNameCV"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentStart="true"
                        android:layout_marginStart="1dp"
                        android:text="닉네임"
                        android:textAppearance="?android:attr/textAppearanceSmall"
                        android:textSize="13sp" />
                </RelativeLayout>

            </LinearLayout>

            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#ddd">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:background="#fff"
                    android:layout_marginBottom="1dp"
                    android:paddingLeft="16dp"
                    android:paddingRight="16dp">

                    <ImageView
                        android:id="@+id/imageView3"
                        android:layout_width="28dp"
                        android:layout_height="27dp"
                        android:layout_alignParentStart="true"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="1dp"
                        android:src="@drawable/eye_icon" />

                    <TextView
                        android:id="@+id/tvHitCV"
                        android:textAlignment="center"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentTop="true"
                        android:layout_alignParentBottom="true"
                        android:layout_marginLeft="5dp"
                        android:layout_marginTop="15dp"
                        android:layout_marginBottom="15dp"
                        android:layout_toRightOf="@+id/imageView3"
                        android:text="6"
                        android:textAppearance="?android:attr/textAppearanceSmall" />

                   <!-- <CheckBox
                        android:id="@+id/ckBoxContentsLike"
                        android:layout_width="28dp"
                        android:layout_height="27dp"
                        android:layout_toRightOf="@+id/tvHitCV"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="15dp"
                        android:button="@drawable/chk_like"
                        android:background="@drawable/border_00ff0000"/>-->

                    <ImageButton
                        android:id="@+id/ibLike"
                        android:layout_width="28dp"
                        android:layout_height="27dp"
                        android:layout_toRightOf="@+id/tvHitCV"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="15dp"
                        android:src ="@drawable/ic_baseline_thumb_up_off_alt_24"
                        android:background="@drawable/border_00ff0000"/>



                    <TextView
                        android:id="@+id/tvContents_like"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentTop="true"
                        android:layout_alignParentBottom="true"
                        android:layout_marginLeft="5dp"
                        android:layout_marginTop="10dp"
                        android:layout_marginBottom="10dp"
                        android:layout_toRightOf="@+id/ibLike"
                        android:gravity="center_vertical"
                        android:hint="좋아요"
                        android:textAppearance="?android:attr/textAppearanceSmall" />

                    <ImageView
                        android:id="@+id/imageView4"
                        android:layout_width="28dp"
                        android:layout_height="27dp"
                        android:layout_alignParentTop="true"
                        android:layout_alignParentBottom="true"
                        android:layout_marginLeft="15dp"
                        android:layout_marginTop="15dp"
                        android:layout_marginBottom="15dp"
                        android:layout_toRightOf="@id/tvContents_like"
                        android:src="@drawable/comment_icon" />

                    <TextView
                        android:id="@+id/tvCommentCount"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentTop="true"
                        android:layout_alignParentBottom="true"
                        android:layout_marginLeft="5dp"
                        android:layout_marginTop="15dp"
                        android:layout_marginBottom="15dp"
                        android:layout_toRightOf="@+id/imageView4"
                        android:text="댓글수"
                        android:textAlignment="center"
                        android:textAppearance="?android:attr/textAppearanceSmall" />

                    <!--날짜-->

                    <TextView
                        android:id="@+id/tvDateCV"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentTop="true"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentBottom="true"
                        android:layout_gravity="end"
                        android:layout_marginTop="15dp"
                        android:layout_marginEnd="1dp"
                        android:layout_marginBottom="15dp"
                        android:text="Date"
                        android:textSize="13sp"
                        android:textAppearance="?android:attr/textAppearanceSmall" />



                </RelativeLayout>
            </LinearLayout>

        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

- 리사이클러뷰 어댑터를 만들어 줍니다. 스틱코드에 코드를 저장해 놓고 사용하면 편합니다.

스틱코드로 어댑터 만들기

ada 까지만 입력해도 제 Post에 등록해 놓은 코드를 전체 불러와서 사용이 가능합니다.

https://stickode.com/detail.html?no=2208 

 

스틱코드

 

stickode.com

스틱코드 사용해서 개발 편하게 하기 : https://stickode.com/mainlogin.html

 

STICKODE

 

stickode.com

package com.Recyclerview;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.Activity.ContentsActivity;
import com.Listener.OnPostListener;
import com.R;

import java.util.ArrayList;

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {


    private final ArrayList<DataModel> dataModelArrayList;
    private Context context;
    private OnPostListener onPostListener;
    String getContentsNum;
    int pos;

    private final String TAG = "myRecyclerViewAdapter";

    // 생성자: 생성자에서 데이터 리스트 객체를 전달받음.
    public MyRecyclerViewAdapter(ArrayList<DataModel> dataModelArrayList, Context context) {
        this.dataModelArrayList = dataModelArrayList;
        this.context = context;
        // 어댑터에서 액티비티 액션을 가져올 때 context가 필요한데 어댑터에는 context가 없다.
        // 선택한 액티비티에 대한 context를 가져올 때 필요하다.
    }

    // 뷰홀더
    // 이 부분에서 super를 통해 상속을 받았다.
    // 이 RecyclerView 에 뷰 holder 에서 상속을 받아서 거기에 아이템 값을 찾아와야 한다.
    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView tvTitleCV, tvDateCV, tvContentsCV, tvNickNameCV, tvHitCV, tvCommentCount, tvCategoryCV;
        public ImageView ivImageCV;
        public ImageButton ibLike;

        // 뷰홀더
        public MyViewHolder(View view) {
            super(view);
            this.ivImageCV = (ImageView) view.findViewById(R.id.ivImageCV);
            this.tvCategoryCV = (TextView) view.findViewById(R.id.tvCategoryCV);
            this.tvTitleCV = (TextView) view.findViewById(R.id.tvTitleCV);
            this.tvContentsCV = (TextView) view.findViewById(R.id.tvContentsCV);
            this.tvNickNameCV = (TextView) view.findViewById(R.id.tvNickNameCV);
            this.tvHitCV = (TextView) view.findViewById(R.id.tvHitCV);
            this.tvCommentCount = (TextView) view.findViewById(R.id.tvCommentCount);
            this.tvDateCV = (TextView) view.findViewById(R.id.tvDateCV);

            // 리사이클러뷰의 각 아이템을 재사용하는 MyViewHolder 에서 각 아이템에 대한 클릭 리스너를 달 수 있다. : 필요시 사용
            // MyViewHolder 가 리사이클러뷰의 각 뷰 항목을 만드는 역할을 하기 때문에, 여기서 작업을 해야한다.
            view.setClickable(true);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    pos = getAdapterPosition();

                    if (pos != RecyclerView.NO_POSITION) {

                        // 데이터 리스트로부터 아이템 데이터 참조.
                        DataModel item = dataModelArrayList.get(pos);

                        getContentsNum = item.getContentsNum();
                        String getSection = item.getSection();
                        String getCategory = item.getCategory();
                        String getTitle = item.getTitle();
                        String getNickName = item.getNickName();
                        String getContents = item.getContents();
                        Bitmap getImage = item.getImage();
                        String getDate = item.getDate();
                        String getEmail = item.getEmail();

                        // 클릭한 리사이클러뷰의 내용을 인텐트에 담아서 이동할액티비티로 간다.
                        Intent intent = new Intent(context, ContentsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.putExtra("getContentsNum", getContentsNum);
                        intent.putExtra("getSection", getSection);
                        intent.putExtra("getCategory", getCategory);
                        intent.putExtra("getTitle", getTitle);
                        intent.putExtra("getNickName", getNickName);
                        intent.putExtra("getContents", getContents);
                        intent.putExtra("getImage", getImage);
                        intent.putExtra("getDate", getDate);
                        intent.putExtra("getEmail", getEmail);
                        context.startActivity(intent);
                    }
                }
            });
        }
    }

    // 리스트 뷰가 어댑터에 연결된 다음 이쪽에서 뷰 홀더를 최초로 만들어 냄.
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Log.d(TAG, "태그 onCreateViewHolder 들어옴");

        View cardView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cardview, parent, false); //view연결
        MyViewHolder holder = new MyViewHolder(cardView);
        return holder;

        // 각각의 아이템을 위한 뷰를 담고있는 뷰홀더 객체를 반환한다.
        // (각 아이템을 위한 XML 레이아웃을 이용해 뷰 객체를 만들었고 이걸 뷰홀더에서 참조할 수 있도록 위에 만들어 놓음)
    }

    // 각 아이템들에 대한 실제적인 매칭해주는 곳
    // onBindViewHolder() - position 서로 결합되는 경우 해당하는 데이터를 뷰홀더의 아이템뷰에 표시.
    // View 의 내용을 해당 포지션의 데이터로 바꿉니다.
    // 각각의 아이템을 위한 뷰의 xml 레이아웃 호출(즉, 뷰홀더가 각각의 아이템을 위한 뷰를 담아주기 위한 용도인데, 뷰와 아이템이 합쳐질 때 호출)
    // 적절한 데이터를 가져와서 뷰 소유자의 레이아웃을 채우기 위해서 사용(뷰홀더에 각 아이템의 데이터를 설정해 놓았음.)
    @Override
    public void onBindViewHolder(@NonNull MyRecyclerViewAdapter.MyViewHolder holder, int position) {

        // 각 위치에 문자열 세팅
        // 객체가 있는 배열에 담아서 어댑터 쪽으로 쏜다. 그걸 onBindViewHolder 가 받아서 Glide가 load하는 형태이다.
      
        DataModel dataModelPosition = dataModelArrayList.get(position); // 데이터 리스트 객체에서 어떤거 가져올지 위치로 추출
        holder.tvCategoryCV.setText(dataModelPosition.getCategory());
        holder.tvTitleCV.setText(dataModelPosition.getTitle());
        holder.tvContentsCV.setText(dataModelPosition.getContents());
        holder.tvNickNameCV.setText(dataModelPosition.getNickName());
        holder.tvHitCV.setText(dataModelPosition.getHit());
        holder.tvCommentCount.setText(dataModelPosition.getComment());
        holder.tvDateCV.setText(dataModelPosition.getDate());
        holder.tvCommentCount.setText(dataModelPosition.getComment());

        context = holder.itemView.getContext();

        /* 리사이클러뷰의 버튼을 클릭할 때 실행될 것들을 적어준다. */
        holder.ibLike.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "리사이클러뷰의 좋아요 버튼이 눌렸습니다.", Toast.LENGTH_SHORT).show();
            }
        });

 		 // Glide : 작성하면 이미지 load가 가능해진다. holder시 삽입될 것이다.
        // override() : 해당 사이즈로 이미지를 늘리거나 줄이는 것.
        // fitCenter() : 해당 이미지뷰의 크기가 지정되어 있을 경우 이미지 뷰의 크기에 이미지를 맞추는 것
        Glide.with(context).load(dataModelArrayList.get(position).getImage()).fitCenter().into(holder.ivImageCV);
    }

    // 몇개의 데이터를 리스트로 뿌려줘야하는지 반드시 정의해줘야한다
    @Override
    public int getItemCount() {
        //  삼항연산자 arrayList 가 null이면 왼쪽꺼 실행 아니면 오른쪽거 실행
        return (dataModelArrayList != null ? dataModelArrayList.size() : 0);
    }
}

 

- 리사이클러뷰에 보여줄 데이터를 담을 객체를 만들어 줍니다.

package com.Recyclerview;

import android.graphics.Bitmap;

public class DataModel {
    Bitmap image; // 사진
    String category; // 카테고리
    String title; // 제목
    String contents; // 내용
    String nickName; // 닉네임
    String email; // 이메일
    String hit; // 조회수
    String comment; // 댓글 수
    String date; // 날짜
    String section; //섹션(토픽인지, 직종인지)
    String contentsNum; // 게시글 숫자
    int likeCount; // 좋아요갯수
    boolean userLiked; // 좋아요 눌린 여부

    public DataModel( String contentsNum, String section, Bitmap image, String category, String title, String contents, String nickName, String hit, /*String comment,*/ String date, String email, int likeCount, boolean userLiked) {
        this.image = image;
        this.category = category;
        this.title = title;
        this.contents = contents;
        this.nickName = nickName;
        this.hit = hit;
        this.comment = comment;
        this.date = date;
        this.email = email;
        this.section = section;
        this.contentsNum = contentsNum;
        this.likeCount = likeCount;
        this.userLiked = userLiked;
    }

    public Bitmap getImage() {
        return image;
    }

    public String getCategory() {
        return category;
    }

    public String getTitle() {
        return title;
    }

    public String getContents() {
        return contents;
    }

    public String getNickName() {
        return nickName;
    }

    public String getHit() {
        return hit;
    }

    public String getComment() {
        return comment;
    }

    public String getDate() {
        return date;
    }

    public String getEmail() {
        return email;
    }

    public String getSection() {
        return section;
    }

    public String getContentsNum() {
        return contentsNum;
    }

    public int getLikeCount() {
        return likeCount;
    }

    public boolean isUserLiked() {
        return userLiked;
    }



    public void setUserLiked(boolean userLiked) {
        this.userLiked = userLiked;
    }

    public void setLikeCount(int likeCount) {
        this.likeCount = likeCount;
    }

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

    public void setCategory(String category) {
        this.category = category;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setContents(String contents) {
        this.contents = contents;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public void setHit(String hit) {
        this.hit = hit;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setSection(String setcion) {
        this.section = section;
    }
    public void setContentsNum(String contentsNum) {
        this.contentsNum = contentsNum;
    }
}

 

- 프래그먼트의  onCreateView에서 앞서 정의한 xml을 인플레이션하고 그 ViewGroup의 객체로 recyclerView를 가져옵니다.

- 리사이클러뷰 연결, 리사이클러뷰에 어댑터 연결, 리사이클러뷰에 레이아웃 매니저 연결을 해 줍니다. 

 

 

저는 getMysql() 이라는 메소드를 만들어서 데이터를 가지고 왔습니다.

서버를 사용하지 않는다면 이 부분에서 데이터를 추가해 주면 되겠죠? 

 

프래그먼트 위에 이런식으로 카드뷰가 보여지게 됩니다!