[kotlin]프래그먼트(Fragment),다이얼로그(Dialog),알림보내기

남윤희·2023년 8월 23일
1

kotlin

목록 보기
2/25

프래그먼트(Fragment)

  • 하나의 액티비티에 여러개의 프래그먼트를 넣을 수 있고 액티비티간 전환이 아니다보니 속도도 빠르고 데이터도 적다 우리가 흔히 사용하는 기능이다.

    탭으로 화면만 전환하는.

프래그먼트 만들기

액티비티를 만들 때처럼 kt파일과 layout로 만든다.
파일 생성 또한 액티비티 밑에 Fragment파일이 존재한다.
gradle에
implementation("androidx.fragment:fragment-ktx:1.6.1")를 추가 해야 한다.

package com.example.fragmentprac

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 [FirstFragment.newInstance] factory method to
 * create an instance of this fragment.
 */
class FirstFragment : 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_first, 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 FirstFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            FirstFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

생성만 하면 이런 코드들이 자동생성되며,
액티비티처럼 레이아웃도 자동생성 할 수 있다.

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

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

처음엔 FrameLayout으로 지정이 되며, 원하는대로 레이아웃 지정.

보여줄 2개의 Fragment layout을 작성하고

//첫번째 Fragment layout
<?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"
    android:layout_width="match_parent"
    android:background="#F19B9B"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="프래그먼트 1"
        android:textSize="40sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
//두번 째 layout
<?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"
    android:layout_width="match_parent"
    android:background="#C785D3"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="프래그먼트 2"
        android:textAllCaps="false"
        android:textSize="40sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

메인화면에서 버튼과 FrameLayout으로 프래그먼트 영역을 지정한다.

<?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">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        app:layout_constraintBottom_toTopOf="@+id/fragment1_btn"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>

    <Button
        android:id="@+id/fragment1_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Frag1"
        android:textAllCaps="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/fragment2_btn"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/frameLayout" />

    <Button
        android:id="@+id/fragment2_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Frag2"
        android:textAllCaps="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/fragment1_btn"
        app:layout_constraintTop_toBottomOf="@+id/frameLayout" />

</androidx.constraintlayout.widget.ConstraintLayout>

메인Activity에서 적용하면

package com.example.fragmentprac

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import com.example.fragmentprac.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.apply {
            fragment1Btn.setOnClickListener {
                setFragment(FirstFragment())
            }
            fragment2Btn.setOnClickListener {
                setFragment(SecondFragment())
            }
        }
        setFragment(FirstFragment())
    }

    //setFragment 함수를 지정해준다.
    private fun setFragment(frag : Fragment) {
        supportFragmentManager.commit {
            replace(R.id.frameLayout, frag)
            setReorderingAllowed(true)
            addToBackStack("")
        }
    }
}


액티비티 간 이동이 아닌 같은 액티비티 안에서 가운데만 바뀌는 걸 확인 할 수 있다.

다이얼로그

  • 결정을 내리거나 추가정보를 입력하라는 메시지를 표시하는 작은창
  • 팝업 형태를 가지고 있으며 다음으로 계속 진행하기 전에 조치를 취해야 하는 이벤트에 사용

다이얼로그는 세가지 영역이 있다.

종류
1). 기본 다이얼로그(AlertDialog)

        binding.button3.setOnClickListener {
            //무슨말을 쓰며, 아이콘은 뭘 쓸건지
            var builder = AlertDialog.Builder(this)
            builder.setTitle("기본 다이얼로그 타이틀입니다")
            builder.setMessage("기본 다일로그 메세지")
            builder.setIcon(R.mipmap.ic_launcher)

            //어떤 버튼을 누를거고 버튼 눌렀을 때 어떤 작업을 할지
            val listener = object : DialogInterface.OnClickListener{
                override fun onClick(p0: DialogInterface?, p1: Int){
                    when(p1) {
                        DialogInterface.BUTTON_POSITIVE ->
                            binding.textView5.text = "Positive"
                        DialogInterface.BUTTON_NEUTRAL ->
                            binding.textView5.text = "Neutral"
                        DialogInterface.BUTTON_NEGATIVE ->
                            binding.textView5.text = "Negative"
                    }
                }
            }

            builder.setPositiveButton("Positive",listener)
            builder.setNegativeButton("Negative",listener)
            builder.setNeutralButton("Neutral",listener)

            builder.show()
        }
    }
}

2). 커스텀 다이얼로그(CustomDialog)

  • 다이얼로그를 커스텀 하기 위해서는 해당 xml파일이 필요하다.
//dialog.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">


    <LinearLayout
        android:layout_width="406dp"
        android:layout_height="161dp"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">


        <EditText
            android:id="@+id/editTextText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="text"
            android:text="Name" />

        <EditText
            android:id="@+id/editTextText2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="text"
            android:text="gd" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
binding.button4.setOnClickListener {
            val builder = AlertDialog.Builder(this)
            builder.setTitle("커스텀 다이얼로그")
            builder.setIcon(R.mipmap.ic_launcher)

            val v1 = layoutInflater.inflate(R.layout.dialog, null)
            builder.setView(v1)
        
        // p0에 해당 AlertDialog가 들어온다. findViewById를 통해 view를 가져와서 사용
            val listner = DialogInterface.OnClickListener { p0,p1 ->
                val alert = p0 as AlertDialog
                val edit1: EditText? = alert.findViewById(R.id.editTextText)
                val edit2: EditText? = alert.findViewById(R.id.editTextText2)
            }

            builder.setPositiveButton("ㅇㅋ",listner)
            builder.setNegativeButton("ㄴㄴ",null)

            builder.show()

        }


3). 날짜 다이얼로그(DatePickerDialog)

 //날짜 다이얼로그
        binding.button5.setOnClickListener {
            val calender = Calendar.getInstance()
            val year = calender.get(Calendar.YEAR)
            val month = calender.get(Calendar.MONTH)
            val day = calender.get(Calendar.DAY_OF_MONTH)

            val listener = DatePickerDialog.OnDateSetListener { datePicker, i, i2, i3 ->
                // i년 i2월 i3일
                binding.textView5.text = "${i}년${i2}월${i3}일"
            }

            var picker = DatePickerDialog(this, listener, year, month, day)
            picker.show()
        }
    }
}

4). 시간 다이얼로그(TimePickerDialog)

        //시간 다이얼로그
        binding.button6.setOnClickListener { 
            val calendar =Calendar.getInstance()
            val hour = calendar.get(Calendar.HOUR)
            val minute = calendar.get(Calendar.MINUTE)
            
            val listener = TimePickerDialog.OnTimeSetListener { timePicker, i, i2 ->
                binding.textView5.text = "${i}시 ${i2}분"
            }
            val picker = TimePickerDialog(this, listener,hour,minute, false)
            picker.show()

        }

5). 진행 다이얼로그(ProgressDialog)
커스텀 다이얼로그와 비슷하게 xml파일을 생성한다.

//progressbar.xml
<?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="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="match_parent"
        android:layout_height="76dp"
        android:layout_gravity="center"
        android:layout_marginTop="48dp"
        android:indeterminate="false"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="loading..."
        android:textSize="16sp"
        android:layout_marginTop="16dp"/>
</LinearLayout>

kt파일

        // 5. 프로그레스 다이얼로그
//        binding.button7.setOnClickListener {
//            // 권장하진 않지만 사용은 가능하다.
//            pro = ProgressDialog.show(this, "타이틀입니다.", "메시지입니다.")
//
//            // 핸들러를 통해서 종료 작업을 한다.
//            val handler = Handler()
//            val thread = Runnable { pro?.cancel() }
//            handler.postDelayed(thread, 5000) // 딜레이는 5초
//        }
//

//6. 프로그래스 다이얼로그 다른 방식. (커스텀과 비슷)
        binding.button7.setOnClickListener {
            val builder = AlertDialog.Builder(this)
            builder.setTitle("프로그래스바")
            builder.setIcon(R.mipmap.ic_launcher)

            val v1 = layoutInflater.inflate(R.layout.progressbar, null)
            builder.setView(v1)

            builder.show()
        }

알람(Notification)

package com.example.alam

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.graphics.BitmapFactory
import android.media.AudioAttributes
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.NotificationCompat
import com.example.alam.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.button.setOnClickListener {
            notification()
        }
    }

    fun notification() {
        val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

        val builder: NotificationCompat.Builder
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 26 버전 이상
            val channelID = "one-channel"
            val channerName = "My Channel One"
            val channel = NotificationChannel(
                channelID,
                channerName,
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                //채널에 다양한 정보 설정
                description = "My Channel One Description"
                setShowBadge(true)
                val uri: Uri = RingtoneManager.getDefaultUri((RingtoneManager.TYPE_NOTIFICATION))
                val audioAttributes = AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
                setSound(uri, audioAttributes)
                enableVibration(true)
            }
            //채널을 NotificationManager에 등록
            manager.createNotificationChannel(channel)

            //채널을 이용하여 builder 생성
            builder = NotificationCompat.Builder(this, channelID)

        } else {
            builder = NotificationCompat.Builder(this)
        }

        val bitmap = BitmapFactory.decodeResource(resources, androidx.core.R.drawable.notification_bg)
        val intent = Intent(this, SecondActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        builder.run {
            setSmallIcon(R.mipmap.ic_launcher)
            setWhen(System.currentTimeMillis())
            setContentTitle("새로운 알림입니다.")
            setContentText("알림이 잘 보이나요?")
            setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText(
                        "이것은 긴텍스트 샘플입니다. 아주 긴 텍스트를 쓸때는 여기다 하면 됩니다.이것은 긴텍스트 샘플입니다. \n" +
                                "아주 긴 텍스트를 쓸때는 여기다 하면 됩니다.이것은 긴텍스트 샘플입니다. 아주 긴 텍스트를 쓸때는 여기다 하면 됩니다. "
                    )
            )
            setLargeIcon(bitmap)
            //긴 텍스트 대신 이미지로 할때
//            setStyle(NotificationCompat.BigPictureStyle()
//                .bigPicture(bitmap)
//                .bigLargeIcon(null))
            addAction(R.mipmap.ic_launcher, "Action", pendingIntent)
        }

        manager.notify(11, builder.build())
    }
}
profile
안드로이드 주니어 개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 23일

(/ω\)
오늘 엄청 많이하셨네요!!

답글 달기