반응형

▶ Fragment(프래그먼트) 정의

 프래그먼트는 태블릿과 같은 대화면에서 효율적으로 화면을 구성하기 위해 생긴 구성요소입니다. 하지만 스마트폰과 같은 작은 화면에서도 효율적인 자원 활용과 메뉴 구성을 위해 종종 사용됩니다.

액티비티를 분할하여 화면의 한 부분을 정의하며 액티비티와 같이 레이아웃, 동작 처리, 생명주기를 가지는 독립적인 모듈인데요, 다른 액티비티에서도 사용할 수 있어 재사용성이 뛰어나며 액티비티 실행 중에 추가, 제거가 가능합니다.

프레그먼트는 액티비티의 일부분에만 배치되는 화면 및 동작을 조작하기 위한 객체입니다.  프레그먼트 매니저를 통해서 여러개의 프레그먼트를 조작할 수 있습니다. 레이아웃 xml 파일에서 다른 뷰들과 함께 배치될 수 있습니다.

▶ 프래그먼트 실습 :  버튼을 클릭하면 해당 프래그먼트 화면을 보여주기!

→  3개의 버튼과 3개의 프래그먼트 화면을 각각 만들고 각 버튼들을 클릭하면 각각의 프래그먼트 화면이 로딩 되도록 합니다. 이때 메인 레이아웃(activity_main.xml) 화면에는 FrameLayout을 이용하여 화면을 fragment를 로딩할 View 영역과 버튼을 클릭할 영역으로 구분해서 만들어 봅니다.

 

→ 각각의 프래그먼트 화면을 아래처럼 단순하게 배경색을 변경하여 구성하고, 추후에 이미지를 넣거나 다양하게 응용하면 됩니다.

 

▶  실행 결과 

→ 1번, 2번, 3번 버튼을 클릭하면 아래와 같이 main_activity.xml 레이아웃 화면에 각각의 프래그먼트 화면이 로딩되도록 합니다.

 

▶ 코드 구성

① 먼저 gradle에 있는 build.gradle.kts(Module :app) 파일에 아래처럼 뷰바인딩 사용 선언을 해주세요.


② 아래 이미지를 참고하여 res 》 layout 》 New 》 Fragment 》 Fragment(Blank) 를 클릭하고 타이틀은 frag1으로 입력하여 만들면 fragment_frag1.xml 파일과 함께 frg1.kt 파일이 세트로 만들어집니다. (layout에서 마우스 우클릭하면 New 메뉴가 나타납니다)

같은 방법으로 아래 이미지처럼  fragment_frag2.xml , fragment_frag3.xml ( frg2.kt , frag3.kt)을 만들어 주세요. 

 

→ frag 1의 xml 코드는 아래와 같습니다. (단순하게 배경색 지정하고 TextView를 하나 넣었습니다)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#2233aa"
    tools:context=".frag1">

    <TextView
        android:id="@+id/txtview_frag1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text= "Frag 1 page"
        android:textSize="20dp"
        android:textStyle="bold"
        android:textColor="@color/white"/>

</FrameLayout>

 

frag1.xml의 뷰화면

→ frag2의 xml 코드 또한 동일하며 배경색과 id 그리고 text 내용만 각각 바꾸어 주세요.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#A51EB4"
    tools:context=".frag2">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text= "Frag 2 page"
        android:textSize="20dp"
        android:textStyle="bold"
        android:textColor="@color/white"/>

</FrameLayout>

frag2.xml의 뷰화면

 

→  frag3의 xml 코드 또한 동일하며 배경색과 id 그리고 text 내용만 각각 바꾸어 주세요.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF9800"
    tools:context=".frag3">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text= "Frag 3 page"
        android:textSize="20dp"
        android:textStyle="bold"
        android:textColor="@color/white"/>

</FrameLayout>

frag3.xml의 뷰화면

④ 자동으로 생성된 frag1.kt 프래그먼트의 클래스 함수 코드는 아래와 같습니다.

package com.example.fragment

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [frag1.newInstance] factory method to
 * create an instance of this fragment.
 */
class frag1 : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_frag1, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment frag1.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            frag1().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

위 코드처럼 기본 생성된 코드 그대로 사용해도 실행에 문제는 없는데요,  필요 없는 내용 다 지우고 아래만 남겨 놓으면  됩니다.

package com.example.fragment

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

class frag1 : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_frag1, container, false)
    }
}

frag2.kt  와 frag3.kt 코드도 마찬가지로 정리해 보세요.

 

⑤ 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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/main_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/linearLayout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"></FrameLayout>

    <LinearLayout
        android:id="@+id/btn_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/main_view">

        <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_weight="1"
            android:text="1번"
            android:textSize="20dp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_weight="1"
            android:text="2번"
            android:textSize="20dp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_weight="1"
            android:text="3번"
            android:textSize="20dp"
            android:textStyle="bold" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

⑥  뷰 바인딩을 적용한  MainActivity.kt의 코드는 아래처럼 해주세요. 

package com.example.fragment

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.fragment.databinding.ActivityMainBinding
import com.example.fragment.databinding.FragmentFrag1Binding

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)        
        setContentView(binding.root)
        binding.btn1.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.main_view, frag1()).commit()
        }
        binding.btn2.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.main_view, frag2()).commit()
        }
        binding.btn3.setOnClickListener {
            supportFragmentManager.beginTransaction().replace(R.id.main_view, frag3()).commit()
        }
    }
}

 

위 코드에서 supportFragmentManager 코드에도 바인딩 기능을 적용하면 아래와 같이 하면 됩니다. 
그리고, 각 버튼을 클릭할 때 마다 LinearLayout의 배경색도 따라 바뀌도록 아래처럼 코드를 추가해 줄 수 있어요.
"binding.linearBtnbox.setBackgroundColor(Color.parseColor("#2233aa"))"

package com.example.fragment

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.fragment.databinding.ActivityMainBinding
import com.example.fragment.databinding.FragmentFrag1Binding

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)        
        setContentView(binding.root)
        binding.btn1.setOnClickListener {
            binding.linearBtnbox.setBackgroundColor(Color.parseColor("#2233aa"))
            supportFragmentManager.beginTransaction().replace(binding.frameLayout.id, frag1()).commit()
        }
        binding.btn2.setOnClickListener {
            binding.linearBtnbox.setBackgroundColor(Color.parseColor("#A51EB4"))
            supportFragmentManager.beginTransaction().replace(binding.frameLayout.id, frag2()).commit()
        }
        binding.btn3.setOnClickListener {
            binding.linearBtnbox.setBackgroundColor(Color.parseColor("#FF9800"))
            supportFragmentManager.beginTransaction().replace(binding.frameLayout.id, frag3()).commit()
        }
    }
}

 

이렇게 까지만 하면 작성이 완료되고 실행해 보면 아래와 같이 실행이 되는 것을 볼 수 있습니다.

 

마지막으로, 살짝 응용해서 TextView 대신 이미지 뷰(ImageView)를 넣어 사진을 보여주는 것으로 바꾸어 볼게요.

그럼, 변경할 곳은 fragment_frag1.xml  파일에서 TextView 대신 아래와 같이 ImageView 를 대체해서 넣어 주면 됩니다.   나머지 fragment_frag2.xml 과 fragment_frag3.xml 파일도 동일하게 바꾸어주세요.

<fragment_frag1.xml 파일 코드>

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffaaff"
    tools:context=".frag1">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/lake1"
        android:background="#22aabb" />

</FrameLayout>

이때, 보여줄 사진으로 호수(lake)사진을 넣었는데요, 첨부해 드릴테니 연습으로 해보세요.

호수(jpg).zip
1.53MB


사진 파일들은  안드로이드 스튜디오의 프로젝트 탐색창에서 ,  res 》 drawable 폴더로 복사해 넣어주세요. 
(아래 참고)  직접 끌어다 넣기하거나 , 복붙해도 됩니다.

아래는, 이미지로 대체해서 실행한 모습입니다. 
사진이 없는 배경의 공간은 기본값인 흰색인데, background 배경의 색을 사진과 잘 어울리게 넣어서 채워봤습니다.

 

그럼, 지금까지 안드로이드 스튜디오에서  kotlin으로 프래그먼트(fragment)를 사용하는 방법과 실제 예시를 설명해 드렸습니다.  몇 번 반복적으로 연습해 보면 금방 응용할 수 있을 거예요. 

감사합니다.

반응형
반응형

▶ 기존 방식 →  findViewById

 안드로이드 스튜디오를 이용한 안드로이드 네이티브 앱개발에서 findViewById 메서드는 리소스 id를 통해서 레이아웃에 있는 뷰 객체들 중 일치하는 뷰를 가져오는 메서드입니다.  그리고 setContentView와 같은 메서드로 xml에 있는 리소스들을 지정한 속성에 맞게 인스턴스를 생성하여 메모리에 로드하는 인플레이션 과정이 필요합니다.  이때 사용하는 메서드가 findViewById인데요, 문제는 가져와야 할 요소가 적을 때는 별문제가 없지만 아무리 간단한 앱이라고 하더라도 페이지 화면과 구성요소들이 증가하게 되면, 이 메서드로 일일이 뷰 객체를 하나씩 지정해서 가져오는 작업이 아주 번거로워집니다.  이에 따라, 성능상으로도 좋지 않기에 kotlin extension, Data Binding, View Binding과 같은 대체 방법들이 추가되었고, 이를 이용해서 앱을 개발하는 것이 좋습니다.

 

▶ viewBinding의 장점

1. findViewById 보다 속도가 상대적으로 빠르다.
2. Binding 지정만 해주면 정확한 view의 타입을 찾아 알아서 맵핑해준다.
3. NullPointerException을 방지 해준다.

 

viewBinding 사용법

① build.gradle.kts (Module:app) 파일을 클릭하여 android {  ...  }  항목 속에 아래코드를 추가해 주세요.

viewBinding.isEnabled = true

android {
    namespace = "com.example.resourcetest"
    compileSdk = 34
    viewBinding.isEnabled = true
    defaultConfig {
        applicationId = "com.example.resourcetest"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

코드 추가 후 상단에 보이는 Sync Now를 클릭하여 적용시켜 주세요.(아래)

 

그리고 바인딩을 참조하려는 layout의 이름 규칙에 따라 binding 객체를 생성해 주세요.  

이름 생성 규칙  ↓ ↓
예시 1) activity_main.xml 을 참조한다면(바인딩)  ActivityMainBinding 으로 이름 지어집니다.
(언더바는 생략하고 단어 첫 글자를 대문자로 한 다음 Binding글자와 함께 모두 이어 붙입니다.

예시 2) page_one.xml 을 참조한다면(바인딩)  PageOneBinding 으로 이름 지어집니다.

따라서 예시 1과 같이 activity_main.xml을 바인딩한다면  MainActivity.kt 파일의 코드를  아래와 같이 구성해 주면 됩니다.

val binding = ActivityMainBinding.inflate(layoutInflater)

그리고 변경하고자 하는 xml 파일의 text 값이 있다면 아래처럼 구성합니다.
만약, activity_main.xml의 textView 객체의 id가 txtview 라면,

binding.txtview.setText("클릭했음")

그러면 textView의 내용이 "클릭했음"으로 변경 되게 됩니다.

아래는 변경한 코드 포함 전체 MainActivity.kt의 코드입니다.  (버튼 1을 눌렀을 때 textView의 내용이 변하는 코드)

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)        
        setContentView(binding.root)
        binding.btn1.setOnClickListener {
        	binding.txtview.setText("클릭했음")
        }

 

반응형
반응형

- 안드로이드 스튜디오와 같은 개발프로그램에서 스마트폰과 연결하는 방법과
  (개발자 모드 활성화 방법)
- USB디버깅 모드가 비활성화 되어 있는 이유와 활성화 방법에 대해 다루어 볼게요

기본적으로 스마트폰에서는 보안관련 안전을 위해 케이블 연결로 안드로이드 스튜디오와 같은 프로그램에서 앱 직접 설치와 같은 접근을 제한하고 있는데요,  이를 해결하기 위해서는 스마트폰에 숨김처리되어 있는 '개발자 옵션'이라는 것을 활성화해주어야 합니다.   

우선 아래 안드로이드 프로그램에서 가상 디바이스로 먼저 기본화면을 동작시켜 볼게요.

 

픽셀이라는 가상 디바이스로 실행이 잘 되었네요.

 

현재 스마트폰이 PC에 연결되어 있으나 장치 목록에는 인식되지 않은 것으로 보이네요.

 

그럼, 스마트폰에서 설정으로 들어가세요.

그런 다음 제일 아래에 있는 '휴대전화 정보'를 터치해 들어가세요.

다음, '소프트웨어 정보'를 터치해주세요.

다음, '빌드번호'를 7회 이상 터치해 주면, 개발자 메뉴가 활성화됩니다.

그럼, 뒤로 가기를 한 번 눌러 제일 아래로 스크롤해 보면, 아래처럼 '개발자 옵션'이 활성화되어 있는 것을 볼 수 있어요.

USB 디버깅 메뉴를 터치해서 USB디버깅 허용 팝업창의 확인 버튼을 터치하고,

곧이어 뜨는 팝업창에서 '이 컴퓨터에서 항상 허용'을 체크하고 허용을 눌러주세요.

이제 안드로이드 스튜디오에서 PC와 연결된 스마트폰 디바이스가 잡히는 것을 볼 수 있습니다.

 

아래는 연결한 갤럭시 스마트폰에 앱설치와 동시에 바로 실행된 모습입니다.

 

※ USB 디버깅 모드가 활성화 자체가 안 되는 경우가 생기는데요, 즉 ON/OFF 자체를 할 수 없는 상황이 생기는데, 그 이유는 기존 연결해서 사용하던 PC가 아닌 노트북이나 다른 PC로 연결해서 사용할 때 이렇게 됩니다. 
이럴 때는 기존 PC에 연결 승인된 권한을 취소해 주어야 새로 연결하는 PC에 다시 권한을 주면서 USB 디버깅 모드를 활성화시킬 수 있게 됩니다. 

 

그럼 다시 "이 컴퓨터에서 항상 허용"에 체크해 주고 확인을 눌러 주면   USB 디버깅이 활성화된 것을 볼 수 있습니다.

 

자, 이렇게 해도 "USB 디버깅" 메뉴가 활성화 안 되는 경우에는  개발자 옵션을 삭제하고 다시 열어보시고, 그래도 안 될 경우에는,  Usb 디버깅 설정이 폰에 설치된 보안관련 설정 어플리케이션등에 의해 제한될 수 있는 경우이니, 최근 관련 어플 설치나 보안 관련 설정 변경을 한 것이 있는지? 찾아서 삭제하거나 해제해 보세요.  그러면 대부분은 이 문제가 해결 될 거예요. 
아레 폰에 보안 설정을 ON 하면 USB 디버깅 메뉴가 계속 꺼져있게 됩니다.

비록 크게 어려운 부분은 아니지만, 간혹 "USB디버깅" 메뉴 자체가 활성화 안 되어 당황할 수 있기에 이쪽 관련으로 처음 시작하려는 누군가에게는 도움이 되리라 생각하여 게시해 봅니다. 

그럼, 오늘도 좋은 하루 보내세요~ 

https://youtu.be/AWZE7UQLb3Q

 

- YouTube

 

www.youtube.com

 

 

반응형