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) } } } 
  • Crear una matriz 2D genérica en Kotlin
  • Android ViewModelProviderFactory en kotlin
  • El locking del service vinculado con "Context.startForegroundService () no llamó al error Service.startForeground ()"
  • Android se cuelga después de intentar crear una versión de lanzamiento
  • ¿Cómo puedo establecer el JsName para el campo de respaldo de una propiedad en Kotlin?
  • Cómo convertir si expresión a cuando en Kotlin
  • ¿Por qué no podemos marcar la visibilidad de una class como "protegida" en kotlin?
  • Dagger 2 en testings de unidad con Kotlin
  • Iniciación de la class Kotlin Spring con aspecto
  • Una class simple de kotlin con testing de mockito provocó MissingMethodInvocationException
  • No se requiere error al definir una variable local nula y configurarla más tarde en el método