본문 바로가기
혼공노트

안드로이드 맛집 어플 만들기 (1) RecyclerView, Glide를 이용한 이미지 가져오기

by 김비거 2024. 6. 8.

 

 

* 이 글은 인프런 강의 <[왕초보편] 앱 8개를 만들면서 배우는 안드로이드 코틀린>을 보고 정리한 글입니다.

 


목표

 

맛집 사이트(https://www.siksinhot.com/)에서

가게들의 페이지(url), 이미지, 이름을 RecyclerView를 이용하여 레이아웃을 설정하자.

여기서 Glide와 WebView를 사용하고,

Firebase를 이용하여 이메일과 비번으로 인증을 하도록 한다.

그리고 또, 실시간 데이터베이스를 사용하여 북마크 기능을 만든다.

 

 

세부 목표 (1)

 

Splash 화면이 3초 동안 나오도록 한다.

리사이클러뷰를 위해 아이템들의 모양, 어댑터를 만든다.

가게들의 페이지(url), 이미지, 가게이름을 담는 데이터 클래스를 만든다.

가게 이미지는 Glide를 이용하여 인터넷 이미지 주소를 통해 업로드 하도록 한다.

MainActivity에서 데이터 클래스 자료형으로 item을 만들고

리사이클러뷰와 Glide를 통해 item의 설정한 레이아웃대로 나오는지 확인한다.

 

 

activity_splash.xml

 

먼저 Splash 화면부터 만든다.

처음 화면에 나올 레이아웃을 설정한다.

 

<?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="match_parent"
    tools:context=".SplashActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SIKSIN"
        android:textSize="40dp"
        android:textColor="#ff7f00"
        android:textStyle="bold"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

AndroidManifest.xml

 

SplashActivity부터 실행되도록 <intent-filter>를 ".SplashActivity"의 <activity> 안에 넣는다.

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
...
        <activity
            android:name=".SplashActivity"
            android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">

        </activity>
    </application>

</manifest>

 

 

 

SplashActivity

 

Handler를 사용하여 3초 동안 Splash 화면이 나오도록 한 후

MainActivity 화면으로 넘어가도록 한다.

 

class SplashActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        Handler().postDelayed({
                startActivity(Intent(this, MainActivity::class.java))
            finish()
            }, 3000)

    }
}

 

 

 

activity_main.xml

 

리사이클러뷰를 만든다.

 

<?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="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

radius.xml

 

리사이클러뷰의 item의 모양을 설정하기 위해

drawable 폴더에서 radius.xml을 작성한다.

 

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/white"></solid>
    <corners
        android:bottomRightRadius="15dp"
        android:bottomLeftRadius="15dp"
        android:topRightRadius="15dp"
        android:topLeftRadius="15dp"></corners>
    <stroke
        android:width="1dp"
        android:color="#BDBDBD"/>

</shape>

 

 

 

 

 

rv_item.xml

 

리사이클러뷰에서 사용할 item의 레이아웃을 설정한다.

맛집의 이미지와 맛집 이름(텍스트)를 배치하기로 한다.

 

<?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="150dp"
    android:background="@drawable/radius"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/rvImageArea"
        android:src="@drawable/ic_launcher_background"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="100dp"/>
    <TextView
        android:id="@+id/rvTextArea"
        android:text="text"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

 

 

 

 

AndroidManifest.xml

 

Glide를 사용하려면(이미지 주소로 이미지를 로드하려면) 인터넷이 되도록 해야 한다.

<uses-permission>을 통해 인터넷 허용을 한다.

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    ...
</manifest>

 

 

 

Glide 다운로드

 

'android glide'를 구글에 검색하면 다음과 같은 GitHub 링크가 보인다.

 

https://github.com/bumptech/glide

 

GitHub - bumptech/glide: An image loading and caching library for Android focused on smooth scrolling

An image loading and caching library for Android focused on smooth scrolling - bumptech/glide

github.com

 

 

 

gradle의 dependencies에 추가를 한다.

 

dependencies {
    ...
    implementation("com.github.bumptech.glide:glide:4.16.0")
}

 

 

 

RVAdapter

 

리사이클러뷰를 위한 어댑터를 만들어준다.

Glide를 사용하여 이미지 주소를 통해 이미지뷰에 로드하도록 하였다.

 

// RecyclerView.Adapter를 상속받아 커스텀 어댑터를 구현
class RVAdapter(val context : Context, val List : MutableList<ContentsModel>) : RecyclerView.Adapter<RVAdapter.ViewHolder>() {

    // 새로운 ViewHolder 객체를 생성
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RVAdapter.ViewHolder {
        // LayoutInflater를 사용하여 rv_item 레이아웃을 인플레이트하고 ViewHolder에 전달
        val v = LayoutInflater.from(parent.context).inflate(R.layout.rv_item, parent, false)
        return ViewHolder(v)
    }


    // ViewHolder와 데이터를 바인딩
    override fun onBindViewHolder(holder: RVAdapter.ViewHolder, position: Int) {
        // bindItems 메서드를 호출하여 데이터를 뷰에 바인딩
        holder.bindItems(List[position])
    }

    // RecyclerView의 항목 총 개수를 반환
    override fun getItemCount(): Int {
        return List.size
    }

    // ViewHolder 클래스는 RecyclerView.ViewHolder를 상속받아 각 항목 뷰를 보유
    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
        // bindItems 메서드는 항목 데이터를 뷰에 설정
        fun bindItems(item : ContentsModel) {
            // rv_item 레이아웃의 ImageView와 TextView를 찾아 바인딩
            val rv_img = itemView.findViewById<ImageView>(R.id.rvImageArea)
            val rv_text = itemView.findViewById<TextView>(R.id.rvTextArea)

            // 항목의 제목을 TextView에 설정
            rv_text.text = item.titleText
            // Glide를 사용하여 이미지 URL을 ImageView에 로드
            Glide.with(context)
                .load(item.imageUrl)
                .into(rv_img)
        }
    }
}

 

 

 

ContentsModel

 

콘텐츠 모델 데이터 클래스를 만든다.

맛집 url과 이미지 주소, 맛집 이름을 인자로 갖는다.

 

data class ContentsModel (
    val url : String = "",
    val imageUrl : String = "",
    val titleText : String = ""

)

 

 

 

MainActivity

 

테스트 삼아서 3개의 item을 생성하고 리사이클러뷰에 제대로 구현되는지 확인하였다.

GridLayoutManager를 사용하여 item들이 두 줄로 나뉘도록 하였다.

 

class MainActivity : AppCompatActivity() {

    // items 리스트는 ContentsModel 객체를 담는 가변 리스트로, RecyclerView에 표시할 데이터를 포함
    private val items = mutableListOf<ContentsModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // items 리스트에 ContentsModel 객체를 추가
        items.add(
            ContentsModel(
                "https://www.siksinhot.com/P/349263",
                "https://img.siksinhot.com/place/1462946564336361.png?w=307&h=300&c=Y",
                "미 피아체"
            )
        )
        items.add(
            ContentsModel(
                "https://www.siksinhot.com/P/349263",
                "https://img.siksinhot.com/place/1462946564336361.png?w=307&h=300&c=Y",
                "미 피아체"
            )
        )
        items.add(
            ContentsModel(
                "https://www.siksinhot.com/P/349263",
                "https://img.siksinhot.com/place/1462946564336361.png?w=307&h=300&c=Y",
                "미 피아체"
            )
        )

        // RecyclerView를 XML 레이아웃에서 찾아 recyclerView 변수에 할당
        val recyclerView = findViewById<RecyclerView>(R.id.rv)
        // RVAdapter 객체를 생성하여 rvAdapter 변수에 할당, items 리스트를 어댑터에 전달
        val rvAdapter = RVAdapter(baseContext, items)
        // RecyclerView에 어댑터를 설정
        recyclerView.adapter = rvAdapter

        // RecyclerView의 레이아웃 매니저를 GridLayoutManager로 설정, 2열 그리드로 배치
        recyclerView.layoutManager = GridLayoutManager(this, 2)
    }
}

 

 

Splash 화면

 

 
 

댓글