안드로이드 앱 개발

(5) 바디와이짐 커뮤니티 앱 개발 - 메인 화면

vitamin3000 2024. 9. 20. 15:03

지난 회원가입 화면에 이어서 메인 화면 구성이다.

 

초기 메인화면 디자인

 

구현하고자 하는 기능은 다음과 같다.

1. 기구 사용법 글 클릭시 바디와이짐 블로그로 이동

2. 헬스장 내에서 각 기구마다 설명에 대한 QR코드가 붙여져 있는데 이를 활용하기 위해 QR코드 리더 기능

3. 화면 중앙에 사진으로 이벤트 알림

 

화면 구성

<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".HomeFragment">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <!-- 추가된 TextView -->
            <ImageView
                android:id="@+id/imageView_qr"
                android:layout_width="50dp"
                android:layout_height="49dp"
                android:layout_marginTop="16dp"
                android:layout_marginRight="16dp"
                android:src="@drawable/ic_qr_code_scanner_24"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/textView_guide"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="12dp"
                android:layout_marginRight="24dp"
                android:text="기구사용법"
                android:textSize="20sp"
                app:layout_constraintRight_toLeftOf="@+id/imageView_qr"
                app:layout_constraintTop_toTopOf="@+id/imageView_qr" />

            <TextView
                android:id="@+id/textView_nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <com.google.android.gms.ads.AdView
                android:id="@+id/adView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="84dp"
                app:adSize="BANNER"
                app:adUnitId="ca-app-pub-3940256099942544/6300978111"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="1.0"
                app:layout_constraintStart_toStartOf="parent">
            </com.google.android.gms.ads.AdView>

            <ImageView
                android:id="@+id/imageViewCenter"
                android:layout_width="373dp"
                android:layout_height="480dp"
                app:layout_constraintBottom_toTopOf="@+id/adView"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/imageView_qr" />

        </androidx.constraintlayout.widget.ConstraintLayout>
    </RelativeLayout>

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </com.google.android.material.appbar.AppBarLayout>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/bottom_navigation_menu" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

 

화면 아래에 5개의 프레그먼트 구성 

package com.example.bodygym

import SettingFragment
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView

class HomeActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.home)
        val intent = Intent(this, HomeActivity::class.java)
        val post = intent.getSerializableExtra("post") as? ContentModel
        val fragment = BoardFragment()
        val bundle = Bundle()
        bundle.putSerializable("post", post)
        fragment.arguments = bundle

        supportFragmentManager.beginTransaction().replace(R.id.relativeLayout, fragment).commit()

        // BottomNavigationView를 찾습니다.
        val navView: BottomNavigationView = findViewById(R.id.nav_view)

        // BottomNavigationView의 아이템 선택 이벤트를 처리합니다.
        navView.setOnNavigationItemSelectedListener { menuItem ->
            when (menuItem.itemId) {
                R.id.navigation_home -> {
                    replaceFragment(HomeFragment())
                    true
                }
                R.id.navigation_post-> {
                    replaceFragment(BoardFragment())
                    true
                }
                R.id.navigation_chat-> {
                    replaceFragment(ChatListFragment())
                    true
                }
                R.id.navigation_calendar -> {
                    replaceFragment(CalendarFragment())
                    true
                }
                R.id.navigation_settings -> {
                    replaceFragment(SettingFragment())
                    true
                }
                else -> false
            }
        }

        // 앱이 시작될 때 'HomeFragment'를 보여줍니다.
        replaceFragment(HomeFragment())
    }

    // 프래그먼트를 교체하는 메소드입니다.
    fun replaceFragment(fragment: Fragment) {
        val transaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.relativeLayout, fragment)
        transaction.commit()
    }
}

 

HomeFragment.kt

 

5개의 버튼 클릭 기능 구현 및 블로그 이동, QR코드 스캐너 기능 구현

package com.example.bodygym

import SettingFragment
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.databinding.DataBindingUtil.setContentView
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.example.bodygym.databinding.ActivityMainBinding
import com.example.bodygym.databinding.HomeMainBinding
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.MobileAds
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.storage.FirebaseStorage
import com.google.zxing.integration.android.IntentIntegrator
import com.journeyapps.barcodescanner.CaptureActivity

class HomeFragment : Fragment() {
    private lateinit var auth: FirebaseAuth
    private lateinit var db: DatabaseReference
    private var _binding: HomeMainBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = HomeMainBinding.inflate(inflater, container, false)

        // Firebase 인스턴스 초기화
        auth = FirebaseAuth.getInstance()
        db = FirebaseDatabase.getInstance().getReference("Users")

        // Mobile Ads SDK 초기화
        context?.let { MobileAds.initialize(it) }

        // AdView 로드
        loadBannerAd()

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val userId = auth.currentUser?.uid
        userId?.let {
            fetchNickname(it)
            fetchImage(it)
        }

        binding.textViewGuide.setOnClickListener {
            openWebPage("https://m.blog.naver.com/body_y_gym_gogang?tab=1")
        }

        binding.imageViewQr.setOnClickListener {
            val integrator = IntentIntegrator.forSupportFragment(this)
            integrator.setPrompt("QR 코드를 스캔해주세요.")
            integrator.setBeepEnabled(false)
            integrator.setBarcodeImageEnabled(true)
            integrator.captureActivity = CaptureActivity::class.java
            integrator.initiateScan()
        }

        binding.navView.setOnNavigationItemSelectedListener { item ->
            when (item.itemId) {
                R.id.navigation_home -> true
                R.id.navigation_post -> {
                    replaceFragment(BoardFragment())
                    true
                }
                R.id.navigation_chat -> {
                    replaceFragment(ChatListFragment())
                    true
                }
                R.id.navigation_calendar -> {
                    replaceFragment(CalendarFragment())
                    true
                }
                R.id.navigation_settings -> {
                    replaceFragment(SettingFragment())
                    true
                }
                else -> false
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
        if(result != null) {
            if(result.contents == null) {
                Toast.makeText(context, "스캔이 취소되었습니다.", Toast.LENGTH_LONG).show()
            } else {
                openWebPage(result.contents)
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun loadBannerAd() {
        val adRequest = AdRequest.Builder().build()
        binding.adView.loadAd(adRequest)
    }

    private fun fetchNickname(userId: String) {
        db.child(userId).child("nickname").addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                val nickname = dataSnapshot.getValue(String::class.java)
                //binding.textViewNickname.text = nickname
            }

            override fun onCancelled(databaseError: DatabaseError) {
                // 오류 처리
            }
        })
    }

    private fun fetchImage(userId: String) {
        val storageReference = FirebaseStorage.getInstance().getReference("images").child("mainlogo.png")
        storageReference.downloadUrl.addOnSuccessListener { uri ->
            if (isAdded) {
                Glide.with(this).load(uri).into(binding.imageViewCenter)
            }
        }.addOnFailureListener {
            // 오류 처리
        }
    }

    private fun openWebPage(url: String) {
        val webpage: Uri = Uri.parse(url)
        val intent = Intent(Intent.ACTION_VIEW, webpage)
        if (intent.resolveActivity(requireContext().packageManager) != null) {
            startActivity(intent)
        } else {
            Toast.makeText(requireContext(), "웹페이지를 열 수 없습니다.", Toast.LENGTH_LONG).show()
        }
    }

    private fun replaceFragment(fragment: Fragment) {
        parentFragmentManager.beginTransaction().replace(R.id.container, fragment).commit()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

 

 

결과화면