4

我想为 Android 创建一个 scala Views 助手

使用 trait 和 class 的这种组合

class ScalaView(view: View) {
  def onClick(action: View => Any) =
    view.setOnClickListener(new OnClickListener {
      def onClick(view: View) {
        action(view)
      }
    })
}

trait ScalaViewTrait {
  implicit def view2ScalaView(view: View) =
    new ScalaView(view)
}

我可以这样写 onClick()

class MainActivity extends Activity with ScalaViewTrait {
//....
val textView = new TextView(this)
textView.onClick(v => v.asInstanceOf[TextView] setText ("asdas"))
}

我担心的是我想避免投射vTextView

v将始终是TextViewif 应用于 a TextView LinearLayoutif 应用于LinearLayout等等。

有什么方法v可以动态转换到应用的任何视图?

刚开始使用 Scala,我需要你的帮助。

更新

解决了请看下面我的回答

4

3 回答 3

3

这里的问题是,鉴于 Android API,您根本不可能拥有完整的类型安全性以及定义仅适用于View.

您的方法牺牲了类型安全,而 drexin 牺牲了(一些)便利性。像你一样,我愿意在这种情况下放弃类型安全,因为期待 Android 库的良好行为是合理的,但我会以不同的方式封装不愉快的内容。

首先,我会为OnClickListener这样定义一个包装器:

case class MyOnClickListener[V <: View](action: V => Any)
  extends OnClickListener {
  def onClick(view: View) = try action(view.asInstanceOf[V]) catch {
    case e: ClassCastException =>
      throw new RuntimeException("This should never happen!", e)
  }
}

然后忘记它的OnClickListener存在(或者至少不要在我的代码中的其他任何地方使用它)。现在所有非类型安全的东西都捆绑在一个地方,我的ScalaView班级很干净,例如:

class ScalaView[T <: View](view: T) {
  def onClick(action: T => Any) =
    view.setOnClickListener(MyOnClickListener(action))
}

您可能会遇到需要这种包装器的其他地方,并且这种方法允许您将所有丑陋的演员表等小心地包含在一个地方,而不是分散在整个代码中。

于 2012-09-02T18:32:45.303 回答
2

我设法做到了。这是如何

trait ScalaViewTrait {
  implicit def view2ScalaView[T <: View](view: T) =
    new ScalaView[T](view)
}

class ScalaView[T <: View](view: T) {
  def onClick(action: T => Any) =
    view.setOnClickListener(new OnClickListener {
      def onClick(view: View) {
        action(view.asInstanceOf[T])
      }
    })
}

现在我可以像这样写 onClick

textView.onClick(v => v.setText("asdsa"))

v实际上是一个TextViewwhenonClick应用于 aTextView

PS。也许我会写一堆助手并将它们发布在 GitHub 上。<3 斯卡拉

于 2012-09-02T15:59:36.790 回答
1

您可以代替对其进行简单的模式匹配而不是对其进行强制转换:

// ...
textView.onClick {
  case v: TextView => v.setText("foobar")
  case v => log.error("Expected TextView got %s.".format(v.getClass))
}
于 2012-09-02T15:34:31.303 回答