HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
장지원 페이지/
몰입 캠프
몰입 캠프
/
#02. Making Tab!

#02. Making Tab!

URL
날짜
Jun 28, 2024
Project
project1
To Do(1): 기본 탭 구현 → Project1에 저장해 두었다…
자세히…
참고 링크
TISTORYTISTORY[Android, Kotlin] BottomNavigation
[Android, Kotlin] BottomNavigation

[Android, Kotlin] BottomNavigation

1. 기능 구현 화면 하단에 BottomNavigation 를 만들어보자. (like. Instagram) Navigation 메뉴에 따라 화면(Fragment)를 변경해보자. 2. Android Studio에서 기본 프로젝트(with empty activity) 생성하자! 생성시 'Empty Activity'로 기본 생성 3. ViewBinding 사용을 위한 build.gradle 설정 android { // 뷰 바인딩 옵션 활성화 viewBinding { enabled = true } } 4. BottomNavigation 아이콘 만들기 (Vertor Asset-기본 제공) res -> drawable 우클릭 -> New -> Vector Asset Clip Art -> Select ..

TISTORYTISTORY
결과
notion image
수정 해야 하는 부분
drawable: icon → 원한다면 사진으로 수정 가능함
kotlin: main 및 frag 수정
layout: main 및 frag 수정
menu: menu xml 수정
grandle: dependency 수정
참고 사항
menu, layout 같은 여러 속성 추가 가능!
주석 달려 있는 부분 + <> 이런 부분은 유연하게 수정하기!
앞으로 해야 할 것
fragment 부분 수정하기
 
To Do(2): 사진첩 구현
자세히…
  1. 핸드폰 권한 설정
    1. (핸드폰에서도 권한 설정 해주기…)
  1. xml, kt 구현
Code1 : 기본 사진 접근 코드
  • AndroidManifest에서 추가해야 할 것
    • <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
  • Main xml
    • package com.example.photo_book import android.app.Activity import android.content.Intent import android.os.Bundle import android.widget.Button import android.widget.ImageView class MainActivity : Activity() { private val PICK_IMAGE = 1 private lateinit var imageView: ImageView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) imageView = findViewById(R.id.imageView) val pickImageButton: Button = findViewById(R.id.pick_image_button) pickImageButton.setOnClickListener { val intent = Intent(Intent.ACTION_PICK) intent.type = "image/*" startActivityForResult(intent, PICK_IMAGE) } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE && resultCode == RESULT_OK) { data?.data?.let { imageUri -> imageView.setImageURI(imageUri) } } } }
  • Main kt
    • <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/pick_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pick Image" android:layout_centerInParent="true"/> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/pick_image_button" android:layout_marginTop="16dp" android:src="@drawable/ic_launcher_foreground" android:layout_centerHorizontal="true"/> </RelativeLayout>
Code2 : 사진 접근 + GridView에서 사진 저장하기
  • frag2 kt
    • package com.example.project1 import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.MediaStore import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.Button import android.widget.GridView import android.widget.ImageView @Suppress("DEPRECATION") class Frag2 : Fragment() { // frag2 class 정의 및 Fragment class 상속 private val PICK_IMAGE_REQUEST = 1 // 이미지 선택 알리는 토글 변수 private lateinit var gridView: GridView private lateinit var myGridAdapter: MyGridAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_frag2, container, false) gridView = view.findViewById(R.id.gridView) myGridAdapter = MyGridAdapter(requireContext()) gridView.adapter = myGridAdapter val selectImageButton = view.findViewById<Button>(R.id.select_image_button) selectImageButton.setOnClickListener { openGallery() } return view } private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, PICK_IMAGE_REQUEST) } @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null) { val selectedImageUri = data.data if (selectedImageUri != null) { myGridAdapter.addImage(selectedImageUri) } } } inner class MyGridAdapter(private val context: Context) : BaseAdapter() { private val imageUris = ArrayList<Uri>() override fun getCount(): Int { return imageUris.size } override fun getItem(position: Int): Any { return imageUris[position] } override fun getItemId(position: Int): Long { return position.toLong() } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val imageView = convertView as? ImageView ?: ImageView(context).apply { layoutParams = ViewGroup.LayoutParams(200, 200) scaleType = ImageView.ScaleType.FIT_CENTER setPadding(5, 5, 5, 5) } val imageUri = getItem(position) as Uri imageView.setImageURI(imageUri) return imageView } fun addImage(uri: Uri) { imageUris.add(uri) notifyDataSetChanged() } } }
  • Main xml
    • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center|bottom" android:layout_marginBottom="140dp"> <!-- 버튼을 먼저 정의 --> <Button android:id="@+id/select_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="@string/select_image" /> <!-- 그리드뷰를 버튼 아래에 배치 --> <GridView android:id="@+id/gridView" android:layout_width="match_parent" android:layout_height="40dp" android:layout_below="@id/select_image_button" android:layout_marginTop="-458dp" android:gravity="top" android:numColumns="5" /> <!-- 추가적인 UI 요소들을 정의할 수 있습니다 --> </RelativeLayout>
Code3: 갤러리 advanced (삭제, 취소 등 ..)
package com.example.project1 import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.MediaStore import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.Button import android.widget.GridView import android.widget.ImageView import androidx.appcompat.app.AlertDialog // 각종 위젯 불러오기 @Suppress("DEPRECATION") // 그냥 경고 메세지를 무시하는 annotation이라고 한다. class Frag2 : Fragment() { // frag2 class 이다. fragment를 상속 받는다. private val PICK_IMAGE_REQUEST = 1 // 이미지 클릭을 알리는 toggle number private lateinit var gridView: GridView // GridView를 변수로 지정 private lateinit var myGridAdapter: MyGridAdapter // GridView에 데이터를 전달할 MyGridAdapter class를 변수로 지정 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_frag2, container, false) // inflate는 xml 파일을 view 객체로 바꾸는 과정이다. // onCreatView는 view 개체를 생성하는 과정이라고 생각하면 좋을 것 같다! gridView = view.findViewById(R.id.gridView) myGridAdapter = MyGridAdapter(requireContext()) gridView.adapter = myGridAdapter // gridview를 초기화 한다. val selectImageButton = view.findViewById<Button>(R.id.select_image_button) selectImageButton.setOnClickListener { openGallery() } // 버튼 설정 -> 버튼 리스너 (= 클릭시 갤러리 열기) return view // view 개체를 반환 한다. } private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, PICK_IMAGE_REQUEST) } // intend는 실행할 작업을 생성하는 객체 -> 여기서는 이미지 선택 요청을 보낸다. // 선택 했는지, 안했는지는 PICK_IMAGE_REQUEST 변수로 확인할 수 있다. @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null) { val selectedImageUri = data.data if (selectedImageUri != null) { myGridAdapter.addImage(selectedImageUri) } } } // 이미지가 선택당한 걸 확인하면 Grid에 이미지를 추가한다. // 아~ 이게 MyGridAdapter class이구나..!! inner class MyGridAdapter(private val context: Context) : BaseAdapter() { private val imageUris = ArrayList<Uri>() override fun getCount(): Int { return imageUris.size } override fun getItem(position: Int): Any { return imageUris[position] } override fun getItemId(position: Int): Long { return position.toLong() } // 개수, 아이템, 포지션 가져오는 함수들.. override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { // convertView는 스크롤 관리 val imageView = convertView as? ImageView ?: ImageView(context).apply { layoutParams = ViewGroup.LayoutParams(200, 200) // 정사각형으로 크기 설정 scaleType = ImageView.ScaleType.CENTER_CROP // 이미지를 ImageView에 맞게 자르기 setPadding(0, 0, 0, 0) // padding 제거 혹은 필요에 따라 조정 } val imageUri = getItem(position) as Uri imageView.setImageURI(imageUri) imageView.setOnClickListener { showImageDialog(imageUri) } // view에 있는 이미지가 선택 되었다면 image를 확대해서 보여준다. // 만약에 이미지 확대 말고 다른 action을 취할 거라면 이 부분 수정하면 될 것 같다. return imageView } fun addImage(uri: Uri) { val dialogView = LayoutInflater.from(context).inflate(R.layout.image, null) val dialogImageView = dialogView.findViewById<ImageView>(R.id.ImageView) dialogImageView.setImageURI(uri) val alertDialog = AlertDialog.Builder(context) .setView(dialogView) .setPositiveButton("Select") { dialog, _ -> // Handle Select button click if needed } .setNegativeButton("Cancel") { dialog, _ -> // Handle Cancel button click dialog.dismiss() // Dismiss the dialog } .show() // Add image URI to list only if Select button is clicked alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)?.setOnClickListener { imageUris.add(uri) notifyDataSetChanged() alertDialog.dismiss() // Dismiss the dialog after adding image URI } } // uri는 리소스를 나타내는 고유한 객체 // 다른 flagment에서는 사용할 수 없다. @SuppressLint("MissingInflatedId") private fun showImageDialog(imageUri: Uri) { val dialogView = LayoutInflater.from(context).inflate(R.layout.image, null) val dialogImageView = dialogView.findViewById<ImageView>(R.id.ImageView) dialogImageView.setImageURI(imageUri) val alertDialog = AlertDialog.Builder(context) .setView(dialogView) .setPositiveButton("Close") { dialog, _ -> dialog.dismiss() } .setNegativeButton("Delete") { dialog, _ -> // Handle Delete button click // Remove image from list and update GridView val position = imageUris.indexOf(imageUri) if (position != -1) { imageUris.removeAt(position) notifyDataSetChanged() } dialog.dismiss() } .show() } } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center|bottom" android:layout_marginBottom="140dp"> <!-- 버튼을 먼저 정의 --> <Button android:id="@+id/select_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="@string/select_image" /> <!-- 그리드뷰를 버튼 아래에 배치 --> <GridView android:id="@+id/gridView" android:layout_width="match_parent" android:layout_height="400dp" android:layout_below="@id/select_image_button" android:layout_marginTop="-453dp" android:gravity="top" android:numColumns="5" /> <!-- 추가적인 UI 요소들을 정의할 수 있습니다 --> </RelativeLayout>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ImageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" android:adjustViewBounds="true" android:padding="16dp" android:background="@android:color/black" />
Code4: 글씨 입력, 저장 가능
이 코드는 데이터 클래스에 담아두고, 꺼내 쓰는 형식으로 동작 → 만약 영구 동작하게 하려면 이것들 다 DB내부저장소에 저장해야 할 것 같다!
// Frag2 package com.example.project1 import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.MediaStore import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.Button import android.widget.EditText import android.widget.GridView import android.widget.ImageView import android.widget.TextView import androidx.appcompat.app.AlertDialog // 각종 위젯 불러오기 // @Suppress("DEPRECATION") // 그냥 경고 메세지를 무시하는 annotation이라고 한다. class Frag2 : Fragment() { private val PICK_IMAGE_REQUEST = 1 private lateinit var gridView: GridView private lateinit var myGridAdapter: MyGridAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_frag2, container, false) gridView = view.findViewById(R.id.gridView) myGridAdapter = MyGridAdapter(requireContext()) gridView.adapter = myGridAdapter val selectImageButton = view.findViewById<Button>(R.id.select_image_button) selectImageButton.setOnClickListener { openGallery() } return view } private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, PICK_IMAGE_REQUEST) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null) { val selectedImageUri = data.data if (selectedImageUri != null) { myGridAdapter.addImage(selectedImageUri) } } } data class ImageData(val imageUri: Uri, val description: String) inner class MyGridAdapter(private val context: Context) : BaseAdapter() { private val imageUris = ArrayList<Uri>() private val imageDatas = ArrayList<ImageData>() override fun getCount(): Int { return imageUris.size } override fun getItem(position: Int): Any { return imageUris[position] } override fun getItemId(position: Int): Long { return position.toLong() } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val imageView = convertView as? ImageView ?: ImageView(context).apply { layoutParams = ViewGroup.LayoutParams(200, 200) scaleType = ImageView.ScaleType.CENTER_CROP setPadding(0, 0, 0, 0) } val imageUri = getItem(position) as Uri imageView.setImageURI(imageUri) val description = imageDatas.find { it.imageUri == imageUri }?.description ?: "" imageView.setOnClickListener { showImageDialog(imageUri, description) } return imageView } fun addImage(uri: Uri) { val dialogView = LayoutInflater.from(context).inflate(R.layout.image_text_input_dialog, null) val dialogImageView = dialogView.findViewById<ImageView>(R.id.dialogImageView) val editTextDescription = dialogView.findViewById<EditText>(R.id.editTextDescription) dialogImageView.setImageURI(uri) val alertDialog = AlertDialog.Builder(context) .setView(dialogView) .setPositiveButton("Select") { dialog, _ -> val description = editTextDescription.text.toString() imageDatas.add(ImageData(uri, description)) imageUris.add(uri) notifyDataSetChanged() dialog.dismiss() } .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() } .show() } private fun showImageDialog(imageUri: Uri, description: String) { val dialogView = LayoutInflater.from(context).inflate(R.layout.image_dialog, null) val dialogImageView = dialogView.findViewById<ImageView>(R.id.dialogImageView) val textViewDescription = dialogView.findViewById<TextView>(R.id.textViewDescription) dialogImageView.setImageURI(imageUri) // 이미지 설정 textViewDescription.text = description // 텍스트 설정 AlertDialog.Builder(context) .setView(dialogView) .setPositiveButton("Close") { dialog, _ -> dialog.dismiss() } .setNegativeButton("Delete") { dialog, _ -> val position = imageUris.indexOf(imageUri) if (position != -1) { imageUris.removeAt(position) imageDatas.removeAt(position) notifyDataSetChanged() } dialog.dismiss() } .show() } } }
<!--frag xml--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center|bottom" android:layout_marginBottom="140dp"> <!-- 버튼을 먼저 정의 --> <Button android:id="@+id/select_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="@string/select_image" /> <!-- 그리드뷰를 버튼 아래에 배치 --> <GridView android:id="@+id/gridView" android:layout_width="match_parent" android:layout_height="400dp" android:layout_below="@id/select_image_button" android:layout_marginTop="-453dp" android:gravity="top" android:numColumns="5" /> <!-- 추가적인 UI 요소들을 정의할 수 있습니다 --> </RelativeLayout>
<!-- image_dialog.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <ImageView android:id="@+id/dialogImageView" android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:scaleType="fitCenter" /> <TextView android:id="@+id/textViewDescription" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="115dp" android:textColor="@android:color/black" android:textSize="16sp" /> </LinearLayout>
<!-- image_text_input_dialog.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <ImageView android:id="@+id/dialogImageView" android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:scaleType="fitCenter" /> <EditText android:id="@+id/editTextDescription" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:hint="Enter Description" android:inputType="text" android:maxLines="1" android:paddingTop="115dp" /> </LinearLayout>
Code5: Splash
 
추가로.. GridView에 있는 사진 쓰고 싶으면 어떻게 해야 해? ⇒ DB에 저장해야 해!?

ref.
갤러리에 대한 모든 것!? 위키독스위키독스강의 01 갤러리 이미지 가져오기
강의 01 갤러리 이미지 가져오기

강의 01 갤러리 이미지 가져오기

MainActivity.java ``` package com.cranberryai.test; import androidx.appcompat.app.AppCompatActivit…

위키독스위키독스

Code2 해석
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center|bottom" android:layout_marginBottom="140dp"> <!-- 버튼을 먼저 정의 --> <Button android:id="@+id/select_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="@string/select_image" /> <!-- 그리드뷰를 버튼 아래에 배치 --> <GridView android:id="@+id/gridView" android:layout_width="match_parent" android:layout_height="400dp" android:layout_below="@id/select_image_button" android:layout_marginTop="-453dp" android:gravity="top" android:numColumns="5" /> <!-- 추가적인 UI 요소들을 정의할 수 있습니다 --> </RelativeLayout>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ImageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" android:adjustViewBounds="true" android:padding="16dp" android:background="@android:color/black" />
package com.example.project1 import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.MediaStore import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.Button import android.widget.GridView import android.widget.ImageView import androidx.appcompat.app.AlertDialog // 각종 위젯 불러오기 @Suppress("DEPRECATION") // 그냥 경고 메세지를 무시하는 annotation이라고 한다. class Frag2 : Fragment() { // frag2 class 이다. fragment를 상속 받는다. private val PICK_IMAGE_REQUEST = 1 // 이미지 클릭을 알리는 toggle number private lateinit var gridView: GridView // GridView를 변수로 지정 private lateinit var myGridAdapter: MyGridAdapter // GridView에 데이터를 전달할 MyGridAdapter class를 변수로 지정 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_frag2, container, false) // inflate는 xml 파일을 view 객체로 바꾸는 과정이다. // onCreatView는 view 개체를 생성하는 과정이라고 생각하면 좋을 것 같다! gridView = view.findViewById(R.id.gridView) myGridAdapter = MyGridAdapter(requireContext()) gridView.adapter = myGridAdapter // gridview를 초기화 한다. val selectImageButton = view.findViewById<Button>(R.id.select_image_button) selectImageButton.setOnClickListener { openGallery() } // 버튼 설정 -> 버튼 리스너 (= 클릭시 갤러리 열기) return view // view 개체를 반환 한다. } private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, PICK_IMAGE_REQUEST) } // intend는 실행할 작업을 생성하는 객체 -> 여기서는 이미지 선택 요청을 보낸다. // 선택 했는지, 안했는지는 PICK_IMAGE_REQUEST 변수로 확인할 수 있다. @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null) { val selectedImageUri = data.data if (selectedImageUri != null) { myGridAdapter.addImage(selectedImageUri) } } } // 이미지가 선택당한 걸 확인하면 Grid에 이미지를 추가한다. // 아~ 이게 MyGridAdapter class이구나..!! inner class MyGridAdapter(private val context: Context) : BaseAdapter() { private val imageUris = ArrayList<Uri>() override fun getCount(): Int { return imageUris.size } override fun getItem(position: Int): Any { return imageUris[position] } override fun getItemId(position: Int): Long { return position.toLong() } // 개수, 아이템, 포지션 가져오는 함수들.. override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { // convertView는 스크롤 관리 val imageView = convertView as? ImageView ?: ImageView(context).apply { layoutParams = ViewGroup.LayoutParams(200, 200) // 정사각형으로 크기 설정 scaleType = ImageView.ScaleType.CENTER_CROP // 이미지를 ImageView에 맞게 자르기 setPadding(0, 0, 0, 0) // padding 제거 혹은 필요에 따라 조정 } val imageUri = getItem(position) as Uri imageView.setImageURI(imageUri) imageView.setOnClickListener { showImageDialog(imageUri) } // view에 있는 이미지가 선택 되었다면 image를 확대해서 보여준다. // 만약에 이미지 확대 말고 다른 action을 취할 거라면 이 부분 수정하면 될 것 같다. return imageView } fun addImage(uri: Uri) { imageUris.add(uri) notifyDataSetChanged() } // uri는 리소스를 나타내는 고유한 객체 // 다른 flagment에서는 사용할 수 없다. private fun showImageDialog(imageUri: Uri) { val dialogView = LayoutInflater.from(context).inflate(R.layout.image, null) val dialogImageView = dialogView.findViewById<ImageView>(R.id.ImageView) dialogImageView.setImageURI(imageUri) AlertDialog.Builder(context) .setView(dialogView) .setPositiveButton("Close") { dialog, _ -> dialog.dismiss() } .show() } } }
layout은 코드 보다 팔레트를 이용하는 것이 훨씬 좋다.
 
Mini To Do: 핸드폰 연동
참고 링크: TISTORYTISTORY#3.안드로이드 스튜디오 스마트폰 연결하기(개발자모드 설정)
#3.안드로이드 스튜디오 스마트폰 연결하기(개발자모드 설정)

#3.안드로이드 스튜디오 스마트폰 연결하기(개발자모드 설정)

안드로이드 스튜디오 스마트폰 연결하기 안드로이드 스튜디오에서 개발을 하고 개발한 내용을 AVD에서 확인을 해도 되지만 AVD는 간단하게 확인하는 용도이고 실제 스마트폰에 구동시켜서 테스트를 해봐야 합니다. 안드로이드 스튜디오와 스마트폰을 연결하려면 PC에 드라이버를 설치해야 합니다. 드라이버는 구글에서 '해당 제조사 드라이버'라고 검색하면 나옵니다. 저는 갤럭시로 테스트를 할 예정이라 삼성 휴대폰 드라이버를 다운로드하여 보겠습니다. 아래 URL에 접속하여 드라이버를 다운받아 설치합니다. https://developer.android.com/studio/run/oem-usb?hl=ko https://developer.samsung.com/android-usb-driver PC에 드라이버를 설치하고 나서 스..

TISTORYTISTORY

디자인 + additional option은 기본 구현 모두 완료한 다음 진행하자!
 

정리노트 !
  • GridView는 자동 스크롤이 된다!
  • Layout → Design → Palette를 이용하면 좀 더 쉬운 레이아웃 디자인이 가능해 진다.
 

To Do
TISTORYTISTORYAndroid PHP MySQL 통신(MySQL을 이용한 회원가입 예제)
Android PHP MySQL 통신(MySQL을 이용한 회원가입 예제)

Android PHP MySQL 통신(MySQL을 이용한 회원가입 예제)

이번에 경험한 것은 안드로이드 앱에서 PHP를 이용하여 MySQL(DB)에 접근해 데이터를 저장하는 방식의 회원가입을 만들어보도록 하겠습니다. [이 글의 체크 포인트] ==> 안드로이드는 바로 MySQL에 접근을 하면 되는데 굳이 왜? PHP를 거쳐서 MySQL에 접근을 할까? ◼️ 1. Android PHP MySQL 통신 방법 ◼️ 보통 안드로이드 앱에서 PHP를 이용하여 MySQL(DB)에 접근해 사용하는 방식들을 사용하고 있습니다. ==> 안드로이드는 바로 MySQL에 접근을 하면 되는데 굳이 왜? PHP를 거쳐서 MySQL에 접근을 할까? 위의 의문점이 드실 수 있습니다. 그 이유는 바로 보안상의 이유(MySQL 서버 접속용 아이디와 패스워드 유출) 때문에 '외부'데이터베이스(MySQL)에 바로..

TISTORYTISTORY
++ 화면 켰을 때 부드럽게 전환되게 해보기
++ 네비게이션 바 말고 다르게 해보기

splash 화면 바꾸기 link
Stack OverflowStack OverflowReact Native Splash Screen on Android 12
React Native Splash Screen on Android 12

React Native Splash Screen on Android 12

I am using react-native-splash-screen library for making my custom splash screen in the app from an image on both iOS and Android. However, Google introduced the new splash screens approach in Andr...

Stack OverflowStack Overflow
merging