Yow guys, pada artikel kali ini kita akan membahas mengenai TOAST. Dimana, kita akan melakukan beberapa perubahaan pada toast mulai dari
- Design
- Listener ketika Toast Menghilang
- Background
- Disable interaksi User ketika Toast muncul
Lumayan banyak ya? Ya begitulah, namanya juga keinginan customer dan kita wajib melaksanakanya. Jika mentok, ya baru kita negosiasi lagi kan huhu
Ini adalah code untuk menampilkan Toast kita
CustomToast.showToast(
context = requireActivity(),
typeToast = Constant.TOAST_SUCCESS_DEFAULT,
messageTitle = "Successfully $type",
messageDesc = "08:42 Wed, 03 January 2024",
listener = {
if (it) {
if (viewModel.getAttendanceTypeCheckin() == ATTENDANCE_START_SHIFT) {
gotoHome()
} else {
requireActivity().finish()
}
}
},
window = requireActivity().window
)
Pada pemanggilan ini, teman – teman bisa melihat bahwa kita memiliki beberapa parameter di antaranya :
- typeToast = ini akan mengarahkan style yang akan digunakan
- listener = merupakan listener ketika ingin melakukan pengecekan, apakah toast sudah hilang atau belum
- window, untuk memblokir interaksi user ketika toast muncul.
Gimana? Sudah paham ya, untuk cara mainnya. Nah sekarang ini adalah code lengkap dari class CustomToast yang telah saya buat :
package com.core.core.widget
import android.app.Activity
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.text.SpannedString
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Window
import android.view.WindowManager
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import com.core.core.R
import com.core.core.extension.visible
import com.core.core.utils.Constant
import com.google.android.material.card.MaterialCardView
object CustomToast {
fun showToast(
context: Context,
typeToast: String,
messageTitle: String? = null,
messageSpannedTitle: SpannedString? = null,
messageDesc: String? = null,
messageSpannedDesc: SpannedString? = null,
listener: (hidden : Boolean) -> Unit = {},
window: Window ?= null
) {
if (!messageTitle.isNullOrEmpty() || !messageSpannedTitle.isNullOrEmpty()|| !messageDesc.isNullOrEmpty()|| !messageSpannedDesc.isNullOrEmpty()) {
val toast = Toast(context)
toast.apply {
val inflater =
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val layout = inflater.inflate(
R.layout.toast_custom, (context as Activity).findViewById(R.id.constraint_toast)
)
val mcvCardView = layout.findViewById<MaterialCardView>(R.id.mcv_card)
val ivIcon = layout.findViewById<ImageView>(R.id.iv_icon)
val tvTitle = layout.findViewById<TextView>(R.id.tv_title)
val tvDesc = layout.findViewById<TextView>(R.id.tv_desc)
when (typeToast) {
Constant.TOAST_ERROR_CONNECTION -> {
// todo add if design ready
}
Constant.TOAST_ERROR_DEFAULT -> {
// todo add if design ready
}
Constant.TOAST_SUCCESS_DEFAULT -> {
mcvCardView.setCardBackgroundColor(ContextCompat.getColor(context, R.color.white))
ivIcon.setImageResource(R.drawable.ic_check_green)
tvTitle.setTextColor(ContextCompat.getColor(context, R.color.neutral_grey_900))
}
Constant.TOAST_GENERAL_ERROR -> {
// todo add if design ready
}
}
tvTitle.text = messageTitle ?: messageSpannedTitle
tvDesc.text = messageDesc ?: messageSpannedDesc
tvTitle.visible(!messageTitle.isNullOrEmpty() || !messageSpannedTitle.isNullOrEmpty())
tvDesc.visible(!messageDesc.isNullOrEmpty() || !messageSpannedDesc.isNullOrEmpty())
duration = Toast.LENGTH_LONG
view = layout
setGravity(Gravity.TOP or Gravity.FILL_HORIZONTAL or Gravity.FILL_VERTICAL, 0, 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
addCallback(object : Toast.Callback() {
override fun onToastShown() {
super.onToastShown()
window?.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
}
override fun onToastHidden() {
super.onToastHidden()
window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
listener.invoke(true)
}
})
} else {
window?.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
listener.invoke(true)
}, 3500)
}
show()
}
}
}
}
Bingung ya, banyak sekali codenya wkwk, jangan khawatir mari kita kupas sepotong codenya :
when (typeToast) {
Constant.TOAST_SUCCESS_DEFAULT -> {
mcvCardView.setCardBackgroundColor(ContextCompat.getColor(context, R.color.white))
ivIcon.setImageResource(R.drawable.ic_check_green)
tvTitle.setTextColor(ContextCompat.getColor(context, R.color.neutral_grey_900))
}
Constant.TOAST_ERROR_CONNECTION -> {
// todo add if design ready
}
...
Code diatas adalah aturan style yang bisa kamu gunakan sebagaimana mestinya.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
addCallback(object : Toast.Callback() {
override fun onToastShown() {
super.onToastShown()
window?.setFlags( WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
}
override fun onToastHidden() {
super.onToastHidden()
window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
listener.invoke(true)
}
})
} else {
window?.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
listener.invoke(true)
}, 3500)
}
Untuk bagian code ini, IF dan ELSE adalah pengecekan antara SDK dikarenakan fungsi untuk melakukan pengecekan toast (apakah toast masih muncul atau hilang itu belum ada di bawah OS Android R). Itulah mengapa pada code ELSE kita masih menggunakan handler yang di set 3500. Value 3500 ini disesuaikan dengan duration Toast yang kita pilih yaitu Toast.LENGTH_LONG sedangkan jika teman-teman memilih LENGTH_SHORT, itu waktunya ada di 2000.
Pada code tersebut terdapat juga fungsi window, dimana fungsi ini gunanya untuk menonaktifkan dan mengaktifkan interaksi user. Disini saya menonaktifkan ketika toast muncul dan segera aktif kembali ketika toast menghilang, ini digunakan untuk menghindari prilaku user yang mencoba selalu melakukan interaksi pada sistem.
Gimana, dari sini teman-teman sudah memahami ya? oh ya, untuk XMLnya teman-teman bisa coba gunakan ini :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:animateLayoutChanges="true"
android:id="@+id/constraint_toast"
android:background="#65000000">
<com.google.android.material.card.MaterialCardView
android:id="@+id/mcv_card"
android:layout_width="@dimen/distance_360dp"
android:layout_height="wrap_content"
app:cardBackgroundColor="#FCEDEC"
android:layout_centerHorizontal="true"
android:layout_margin="@dimen/distance_16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:padding="@dimen/distance_14dp"
android:layout_width="@dimen/distance_360dp"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_icon"
android:layout_width="@dimen/distance_20dp"
android:layout_height="@dimen/distance_20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_check_green"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
style="@style/Satoshi.Bold.NeutralGrey900.14"
android:layout_width="@dimen/distance_0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/distance_20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="Successfully Clock in with photo."
tools:textColor="#000" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_desc"
style="@style/Satoshi.Regular.NeutralGrey800.14"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/distance_20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_icon"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:text="08:42 Wed, 03 January 2024."
tools:textColor="#000"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</RelativeLayout>
Semoga bermanfaat dan terimakasih.
Catatan :
Apabila teman-teman ingin melakukan perubahaan terhadap posisi Toast, bisa gunakan line code ini yah :
when (positionToast) {
TOAST_POSITION_TOP -> setGravity(Gravity.TOP or Gravity.FILL_HORIZONTAL or Gravity.FILL_VERTICAL, 0, 0)
TOAST_POSITION_BOTTOM -> setGravity(Gravity.BOTTOM, 0, 0)
}
Sehingga teman-teman hanya perlu menambahkan parameter positionToast:String ?= “toast_position_bottom” saja pada parameter, tinggal sesuaikan juga value default mau posisi bottom atau top.
Selain itu, apabila teman-teman ingin Toast full lebar, bisa gunakan layout berikut ini :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content"
android:animateLayoutChanges="true"
android:id="@+id/constraint_toast">
<com.google.android.material.card.MaterialCardView
android:id="@+id/mcv_card"
android:layout_width="@dimen/distance_360dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/distance_8dp"
app:cardBackgroundColor="@color/white"
android:layout_centerHorizontal="true"
android:layout_margin="@dimen/distance_16dp"
android:layout_marginVertical="@dimen/distance_16dp"
tools:background="@color/white">
<androidx.constraintlayout.widget.ConstraintLayout
android:paddingHorizontal="@dimen/distance_24dp"
android:paddingHorizontal="@dimen/distance_22dp"
android:paddingVertical="@dimen/distance_8dp"
android:layout_width="@dimen/distance_360dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_icon"
android:layout_width="@dimen/distance_20dp"
android:layout_height="@dimen/distance_20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_success"/>
tools:src="@drawable/ic_toast_success"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:textSize="@dimen/_14sp"
android:lineHeight="@dimen/_20sp"
android:fontFamily="@font/satoshi_bold"
android:textColor="@color/grey_900"
android:layout_width="@dimen/distance_0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/distance_12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="Toast Title"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_desc"
android:textSize="@dimen/_14sp"
android:lineHeight="@dimen/_20sp"
android:fontFamily="@font/satoshi_regular"
android:textColor="@color/grey_900"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/distance_12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_icon"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:text="Toast description"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</RelativeLayout>