DSL-like OnClick-listener para una vista personalizada usando kotlin en Android
Intento crear un OnClick-listener tipo DSL (en kotlin) para una vista personalizada que estoy usando en varios lugares del proyecto Android en el que estoy trabajando actualmente. La vista tiene un ImageView, una vista de text primaria y una vista de text secundaria. Estoy intentando crear un listener-helper que te permita anular solo los methods específicos de una interfaz en lugar de todos (inspirados en este artículo ). Pero no puedo hacer que funcione. En realidad, ni siquiera funciona con oyentes regulares de OnClick.
Aquí está mi ErrorMessageView:
- Kotlin: llame a una function para actualizar la interfaz de usuario de BroadcastReceiver onReceive
- Métodos de Kotlin con Vararg como primer parámetro
- Firebase Android: crea usuarios con correo electrónico y contraseña en Kotlin
- ¿Qué significa "con" en Kotlin?
- Cómo pasar funciones para funcionar en Kotlin
class ErrorMessageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0, defStyleRes: Int = 0 ) : FrameLayout(context, attrs, defStyle, defStyleRes) { private var mOnClickListener: OnErrorMessageViewClickListener? = null init { LayoutInflater.from(context).inflate( R.layout.custom_errorview, this, true) ButterKnife.bind(this) } interface OnErrorMessageViewClickListener { fun onImageClick() fun onPrimaryTextClick() fun onSecondaryTextClick() } ... left out for brevity ... fun setOnErrorMessageViewClickListener( onViewClickListener: OnErrorMessageViewClickListener?) { this.mOnClickListener = onViewClickListener } fun setOnErrorMessageViewClickListener(init: ErrorMessageViewClickListenerHelper.() -> Unit) { val listener = ErrorMessageViewClickListenerHelper() listener.init() mOnClickListener = listener } @OnClick(R.id.image_container) internal fun onImageViewClick() { Timber.d("Clicked image view") mOnClickListener?.onImageClick() } @OnClick(R.id.primary_text_container) internal fun onPrimaryTextViewClick() { Timber.d("Clicked primary textview") mOnClickListener?.onPrimaryTextClick() } @OnClick(R.id.secondary_text_container) internal fun onSecondaryTextViewClick() { Timber.d("Clicked secondary textview") mOnClickListener?.onSecondaryTextClick() } }
Y aquí está mi class de ayuda:
private typealias ErrorViewClickListener = () -> Unit open class ErrorMessageViewClickListenerHelper : ErrorMessageView.OnErrorMessageViewClickListener { private var mImageClick: ErrorViewClickListener? = null fun onImageClick(onImageClick: ErrorViewClickListener?) { mImageClick = onImageClick } override fun onImageClick() { mImageClick?..invoke() } private var mPrimaryTextClick: ErrorViewClickListener? = null fun onPrimaryTextClick(onPrimaryTextClick: ErrorViewClickListener?) { mPrimaryTextClick = onPrimaryTextClick } override fun onPrimaryTextClick() { mPrimaryTextClick?.invoke() } private var mSecondaryTextClick: ErrorViewClickListener? = null fun onSecondaryTextClick(onSecondaryTextClick: ErrorViewClickListener?) { mSecondaryTextClick = onSecondaryTextClick } override fun onSecondaryTextClick() { mSecondaryTextClick?.invoke() } }
Mi layout:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.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="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginEnd="24dp"> <android.support.v7.widget.AppCompatImageView android:id="@+id/image_container" android:layout_width="@dimen/dialog_worklist_image_size" android:layout_height="@dimen/dialog_worklist_image_size" android:layout_centerVertical="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" tools:ignore="ContentDescription" /> <TextView android:id="@+id/primary_text_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginEnd="24dp" android:layout_marginStart="24dp" android:layout_marginTop="8dp" android:textSize="16sp" android:clickable="true" android:focusable="true" app:layout_constraintEnd_toEndOf="@+id/image_container" app:layout_constraintStart_toStartOf="@+id/image_container" app:layout_constraintTop_toBottomOf="@id/image_container" /> <TextView android:id="@+id/secondary_text_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginEnd="24dp" android:layout_marginStart="24dp" android:textSize="16sp" android:clickable="true" android:focusable="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/primary_text_container" /> </android.support.constraint.ConstraintLayout>
Estoy usando el helper en mi código de esta manera, pero no se registra nada (es casi como si no se pudiera conectar un clicklistener):
override fun setWorklistNotEnabledMessage(showMessage: Boolean) { if (showMessage) { mView?.dialog_worklist_recyclerview?.visibility = View.GONE mView?.dialog_worklist_errorview?.apply { visibility = View.VISIBLE setSecondaryTextClickListener(View.OnClickListener { Timber.d("Test secondary click") }) setErrorDrawable(R.drawable.ic_worklist_disabled_black_24dp) setPrimaryText(R.string.global_worklist_disabled_error) setSecondaryText(R.string.dialog_worklist_worklist_disabled_error_secondary_text) setOnErrorMessageViewClickListener { onSecondaryTextClick { Timber.d("Test secondary click") } onPrimaryTextClick { Timber.d("Test primary click") } onImageClick { Timber.d("Test image click") } // . this@WorklistDialog } } } else { mView?.dialog_worklist_errorview?.apply { visibility = View.GONE setErrorDrawable(null) setPrimaryText("") setSecondaryText("") setOnErrorMessageViewClickListener(null) } } }
¿Alguien tiene alguna sugerencia sobre qué está mal con mi código?
Por cierto. el código anterior se utiliza en un DialogFragment, ¿por eso es posible que notes el mView ?. como un poco incomodo Pero esa es la forma de manejar las vistas en un dialog.
- Cómo colocar el dialog en la parte inferior
- ¿Cómo habilitar la authentication de portador en la aplicación Spring Boot?
- No se puede configurar el Reino en el proyecto usando Kotlin
- Propiedades de extensión de Kotlin no reconocidas en V1.0.1
- Comparando las lists de comparables en Kotlin
- Copie el map inmutable al map mutable en Kotlin
- lanzar si el operador en Kotlin
- ¿Cómo arreglar mi código para eliminar la advertencia de lanzamiento?
Estaba a punto de comenzar a llorar cuando finalmente encontré la solución – OMG.
El problema fue SwipeRefreshLayout en el file de layout para el fragment de dialog, que se puede ver aquí:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/dialog_worklist_toolbar" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="@color/colorPrimary" android:elevation="4dp" android:minHeight="?android:attr/actionBarSize" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> <com.conhea.smartgfr.ui.examination.layouts.ErrorMessageView android:id="@+id/dialog_worklist_errorview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/dialog_worklist_toolbar" /> <ProgressBar android:id="@+id/dialog_worklist_progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/dialog_worklist_toolbar" /> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/dialog_worklist_swiperefreshlayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" app:layout_constraintTop_toBottomOf="@id/dialog_worklist_toolbar"> <android.support.v7.widget.RecyclerView android:id="@+id/dialog_worklist_recyclerview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" /> </android.support.v4.widget.SwipeRefreshLayout> </android.support.constraint.ConstraintLayout>
El SwipeRefreshLayout estaba bloqueando la posibilidad de hacer clic en ErrorMessageView personalizado.
Después de agregar mView?.dialog_worklist_swiperefreshlayout?.isEnabled = false
al siguiente en mi DialogFragment todo comenzó a funcionar:
override fun setWorklistNotEnabledMessage(showMessage: Boolean) { if (showMessage) { mView?.dialog_worklist_recyclerview?.visibility = View.GONE mView?.dialog_worklist_swiperefreshlayout?.isEnabled = false mView?.dialog_worklist_errorview?.apply { visibility = View.VISIBLE setErrorDrawable(R.drawable.ic_worklist_disabled_black_24dp) setPrimaryText(R.string.global_worklist_disabled_error) setSecondaryText(R.string.dialog_worklist_worklist_disabled_error_secondary_text) setOnErrorMessageViewClickListener { onSecondaryTextClick { Timber.d("Test secondary click") } onPrimaryTextClick { Timber.d("Test primary click") } onImageClick { Timber.d("Test image click") } } } } else { mView?.dialog_worklist_errorview?.apply { visibility = View.GONE setErrorDrawable(null) setPrimaryText("") setSecondaryText("") setOnErrorMessageViewClickListener(null) } } }
- Android (Kotlin): sobrescribe el nombre para la input del logging de llamadas
- Cómo señalar un observable para producir más datos