title: DSL-like OnClick-listener for a custom view using kotlin in Android
body: <p>I'm trying to create an DSL-like OnClick-listener (in kotlin) for a custom view that I'm using several places in the Android project I'm currently working on. The view has an ImageView, a primary textview and a secondary textview. I'm trying to create a listener-helper that allows you to only override specific methods of an interface instead of all of them (inspired by <a href="https://antonioleiva.com/listeners-several-functions-kotlin/?utm_source=twitter.com&amp;utm_medium=social&amp;utm_campaign=listeners-with-several-functions-in-kotl&amp;utm_content=14003943" rel="nofollow noreferrer">this article</a>). But I can't get it working. Actually it doesn't even work using regular OnClick listeners.</p>
  
  <p>Here's my ErrorMessageView:</p>
  
  <pre><code>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.() -&gt; 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()
      }
  
  }
  </code></pre>
  
  <p>And here's my helper class:</p>
  
  <pre><code>private typealias ErrorViewClickListener = () -&gt; 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()
      }
  }
  </code></pre>
  
  <p>My layout:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;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"&gt;
  
      &lt;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" /&gt;
  
      &lt;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" /&gt;
  
      &lt;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" /&gt;
  &lt;/android.support.constraint.ConstraintLayout&gt;
  </code></pre>
  
  <p>I'm using the helper in my code like this, but nothing gets logged (It's almost as if no clicklistener can be attached):</p>
  
  <pre><code>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)
          }
      }
  }
  </code></pre>
  
  <p>Does anyone have a suggestion to what is wrong with my code?</p>
  
  <p>Btw. the above code is used in a DialogFragment - that is why you might notice the mView?. as a bit awkward. But that is the way to get a handle on the views in a dialog.</p>