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:

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.

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) } } } 
  • Clase de datos de Kotlin que implementa la interfaz de Java
  • Kotlin no puede acceder al método abstracto protegido
  • Contrato de testing DSL comportamiento incorrecto / error
  • Obtener location Android Kotlin
  • Configuración de security de spring de Kotlin
  • Kotlin - Clase de fábrica con problemas de properties
  • Android Studio 3.0: no se ha podido encontrar el método 'com.android.build.gradle.internal.variant.BaseVariantData.getOutputs () Ljava / util / List'
  • ¿Cómo llamar al método Kotlin con más de una firma similar con lambda?
  • ¿Puedo usar kotlin.reflect para get un valor de un campo
  • Kotlin: diferencia en la definición de colección
  • kotlin: algunos problemas con arreglos en annotations