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) } } } 
  • No se puede build un proyecto con Android Studio 3.0 + DataBinding + Kotlin
  • Kotlin inteligente echó el segundo valor de un par con filter
  • ¿Dónde deberían savese los files de estado?
  • TestScheduler no funciona (Kotlin + RxJava2 + mockito)
  • Daga y cnetworkingenciales de inicio de session
  • ¿Cuál es el propósito de la palabra key `externa` en Kotlin?
  • Kotlin: ambigüedad de resolución de sobrecarga en Eclipse, pero no en IntelliJ
  • Cómo burlarse del repository reactivo que devuelve Observable
  • Kotlin: esperando la statement de un miembro
  • Cómo deserializar a los delegates de Kotlin en GSON
  • Comstack Kotlin a JavaScript