기본적으로 여러 Android 버전에서 알림이 잘 보이도록 하려면 표준으로 제공하는 Notification 템플릿을 사용하는게 가장 좋다.
하지만 요구사항에 의해 기본 템플릿 말고 직접 커스텀한 레이아웃으로 Notification을 구현할 수 있다.
중요한 점은 직접 커스텀한 레이아웃을 적용하기 위해 Notification style 속성에 NotificationCompat.DecoratedCustomViewStyle을 적용해주어야 한다.
이제 순서대로 커스텀 Notification을 적용하는 방법을 알아보자.
- NotificationCompat.Builder로 기본 Notification을 생성한다.
- 생성한 Notification 객체의 setStyle()을 호출하여 NotificationCompat.DecoratedCustomViewStyle을 적용한다.
- 커스텀한 레이아웃을 RemoteViews의 인스턴스로 확장시킨다.
- setCustomContentView()를 통해 접힌 상태의 알림 레이아웃을, setCustomBigContentView()를 통해 펼처진 상태의 알림 레이아웃을 설정한다.
※ 여기서 주의해야 할 점은 일부 버전에서는 축소된 뷰 레이아웃이 48dp, 헤드업 뷰 레이아웃이 88dp, 확장된 뷰 레이아웃이 252dp로 제한되므로 가급적이면 제한된 높이에 맞게 레이아웃을 꾸미는게 좋다. 그렇지 않으면 정상적으로 레이아웃이 안보일 수 있다. |
이제 코드를 통해 알아보자.
strings.xml
<resources>
<string name="noti_expanded_content">
확장 내용 테스트 확장 내용 테스트 확장 내용 테스트
확장 내용 테스트 확장 내용 테스트 확장 내용 테스트
확장 내용 테스트 확장 내용 테스트 확장 내용 테스트
확장 내용 테스트 확장 내용 테스트 확장 내용 테스트
확장 내용 테스트 확장 내용 테스트 확장 내용 테스트
</string>
</resources>
notification_small.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="vertical"
android:gravity="center"
tools:ignore="HardcodedText">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="알림 요약 제목"
style="@style/TextAppearance.Compat.Notification.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="알림 요약 내용"
style="@style/TextAppearance.Compat.Notification.Info"/>
</LinearLayout>
notification_large.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="252dp"
android:orientation="vertical"
android:gravity="center|top"
tools:ignore="HardcodedText">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="알림 확장 제목"
style="@style/TextAppearance.Compat.Notification.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/noti_expanded_content"
style="@style/TextAppearance.Compat.Notification.Info"/>
</LinearLayout>
Notification 커스텀 레이아웃을 꾸밀때는 호환을 위해 AndroidX.Appcompat 위젯들을 사용할 수 없다.
또한 Notification의 배경 색상은 기기 및 버전에 따라 다를 수 있기때문에 각 위젯들의 용도에 알맞는 style들을 적용해주어야 한다.
style의 종류는 아래와 같다.
- TextAppearance.Compat.Notification.Title
- TextAppearance.Compat.Notification.Info
- TextAppearance.Compat.Notification.Line2
- TextAppearance.Compat.Notification.Time
또한 RemoteViews의 인스턴스로 확장 되기 때문에 레이아웃과, 위젯 사용에도 제한이 있다.
자세한 제한 스펙은 이곳을 참조하면 된다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
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"
tools:ignore="HardcodedText">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_noti"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="알림 실행"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
companion object {
private const val CHANNEL_ID = "my_channel"
private const val NOTI_ID = 101
}
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.btnNoti.setOnClickListener {
showNotification()
}
}
private fun showNotification() {
createNotiChannel()
val customContentView = RemoteViews(packageName, R.layout.notification_small)
val customBigContentView = RemoteViews(packageName, R.layout.notification_large)
val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
setSmallIcon(R.mipmap.ic_launcher)
priority = NotificationManagerCompat.IMPORTANCE_DEFAULT
setStyle(NotificationCompat.DecoratedCustomViewStyle())
setCustomContentView(customContentView)
setCustomBigContentView(customBigContentView)
}
with(NotificationManagerCompat.from(this)) {
notify(NOTI_ID, builder.build())
}
}
private fun createNotiChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID, "테스트 채널", NotificationManager.IMPORTANCE_DEFAULT).apply {
description = "테스트 채널 입니다"
}
val notiManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notiManager.createNotificationChannel(channel)
}
}
}
적용 결과
'Android' 카테고리의 다른 글
[Android] DiffUtil과 Payload를 활용한 RecyclerView 성능 최적화 (0) | 2024.06.18 |
---|---|
[Android] RecyclerView 성능 최적화를 위한 ListAdapter 살펴보기 (0) | 2022.12.22 |
[Android] Activity와 Fragment (0) | 2022.12.15 |
[Android] URI, URL (0) | 2022.11.24 |
[Android] Vector 이미지 (0) | 2022.11.24 |