6

我知道我可以使用idAnko 的属性来识别视图:

class MainActivityUI : AnkoComponent<MainActivity> {

    override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
        frameLayout {
            textView {
                id = R.id.text
            }
        }
    }

}

然后在Activity使用find()函数(或使用 Kotlin Android Extensions)中获取它:

class MainActivity : AppCompatActivity() {

    private val textView by lazy {
        find<TextView>(R.id.text)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        MainActivityUI().setContentView(this)

        textView.text = "Hello World"
    }

}

但我觉得我错过了什么;自述文件中唯一提到该find功能或 Kotlin Android 扩展的地方是标题为Supporting Existing Code的部分:

你不必用 Anko 重写你所有的 UI。您可以保留用 Java 编写的旧类。此外,如果您出于某种原因仍想(或必须)编写 Kotlin 活动类并扩展 XML 布局,则可以使用 View 属性,这会使事情变得更容易:

// Same as findViewById(), simpler to use
val name = find<TextView>(R.id.name)
name.hint = "Enter your name"
name.onClick { /*do something*/ }

您可以使用 Kotlin Android Extensions 使您的代码更加紧凑。

这使得该函数看起来find仅用于支持“旧”XML 代码。

所以我的问题是这样的;使用 anidfind函数是ViewActivity使用 Anko 访问 a 的正确方法吗?有没有更“Anko”的方式来处理这个问题?还是我错过了 Anko 的其他一些好处,使ViewActivity无关紧要的访问?


第二个相关问题;如果这从中访问 a 的正确方法,有没有办法ViewActivitya 中创建id资源(即"@+id/"AnkoComponent?而不是idids.xml文件中创建每个。

4

4 回答 4

9

那么,为什么还要使用XML id定位视图呢?因为我们已经使用 Anko 而不是 XML。

在我看来,我们可以将视图元素存储在id 方法中,AnkoComponent而不是find viewid 方法中。检查代码打击:

class MainActivityUI : AnkoComponent<MainActivity> {

    lateinit var txtView: TextView

    override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
        frameLayout {
            txtView = textView {
                id = R.id.text // the id here is useless, we can delete this line.
            }
        }
    }

}

class MainActivity : AppCompatActivity() {

    lateinit var mainUI : MainActivityUI

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mainUI = MainActivityUI()
        mainUI.setContentView(this)

        mainUI.txtView.text = "Hello World"
    }

}
于 2016-12-07T15:47:26.543 回答
3

不要使用id来识别 Anko DSL 的视图!这是不必要和无用的,因为 Anko 旨在摆脱 XML 布局。而是使用这种模式:

class ActivityMain : AppCompatActivity() {

    var mTextView: TextView  // put it here to be accessible everywhere

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityMainUI().setContentView(this)
    }

    fun yourClassMethod() {
        // So this is am example how to get the textView 
        // defined in your Anko DSL class (not by id!):
        mTextView.text = "bla-bla-bla"  
    }

}

class ActivityMainUI : AnkoComponent<ActivityMain> {

    override fun createView(ui: AnkoContext<ActivityMain>) = with(ui) {

        // your fancy interface with Anko DSL:
        verticalLayout {
            owner.mTextView = textView
        }
    }
}

请注意 UI 类定义:

class ActivityMainUI : AnkoComponent<ActivityMain> {

如果你把你的活动类名放在括号中,那么它的所有公共变量都可以通过UI 类主体中的所有者访问,这样你就可以在那里分配它们。
但是您可以轻松放置AppCompatActivity并制作一些可能被克隆的通用类。在这种情况下,请在 UI 类的主体中使用lateinit var mTextView : TextView,如 Jacob's answer here 中所述。

于 2017-10-13T10:33:30.427 回答
1

稍微概括一下这个问题:如何制作一个封装的 AnkoComponent,可以从 DSL 中使用,并且可以在创建后以编程方式设置其数据?

这是我使用 View.tag 的方法:

class MyComponent: AnkoComponent<Context> {
    lateinit var innerds: TextView
    override fun createView(ui: AnkoContext<Context>): View {
        val field = with(ui) {
            linearLayout {
                innerds = complexView("hi")
            }
        }
        field.setTag(this) // store the component in the View
        return field
    }

    fun setData(o:SomeObject) { innerds.setStuff(o.getStuff()) }
}

inline fun ViewManager.myComponent(theme: Int = 0) = myComponent(theme) {}
inline fun ViewManager.myComponent(theme: Int = 0, init: MyComponent.() -> Unit) = 
    ankoView({ MyComponent(it) }, theme, init)

// And then you can use it anywhere the Anko DSL is used.
class SomeUser : AnkoComponent<Context>
{
    lateinit var instance:View 
    override fun createView(ui: AnkoContext<Context>): View {
        linearLayout {
            instance = myComponent {}
        }
    }
    fun onDataChange(o:SomeObject) {
        (instance.Tag as MyComponent).setData(o)
    }
}

}

于 2018-07-05T18:21:57.400 回答
1

我相信,由于您可以向 Anko 文件添加行为,因此您根本不必在活动中实例化您的视图。

这真的很酷,因为您可以进一步分离视图层。在您的视图中起作用的所有代码都可以插入到 Anko 文件中。所以你所要做的就是从 Anko 调用你的活动方法而不是实例化任何视图。

但是如果您需要实例化任何视图......您可以在您的活动中使用 Kotlin Android 扩展。

示例:

您活动中的代码:

seekBar.setOnSeekBarChangeListener(object: OnSeekBarChangeListener {
    override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
        // Something
    }
    override fun onStartTrackingTouch(seekBar: SeekBar?) {
        // Just an empty method
    }
    override fun onStopTrackingTouch(seekBar: SeekBar) {
        // Another empty method
    }
})

Anko 中的代码:

seekBar {
    onSeekBarChangeListener {
        onProgressChanged { seekBar, progress, fromUser ->
            // Something
        }
    }
}

现在代码在 AnkoComponent 中。无需实例化视图。

结论:

如果您将所有视图逻辑放在 AnkoComponents 中,而不是在您的活动中,这是一种更“Anko”的编程方式。

编辑:

作为不必实例化视图的代码示例:

在您的 Anko 中:

var networkFeedback : TextView = null

    override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
            frameLayout {
                textView {
                    id = R.id.text2
                    networkFeedback = this
                    onClick {
                        ui.owner.doSomething(2, this)
                    }
                }
            }
        }

fun networkFeedback(text: String){
       networkFeedback.text = text
}

在您的活动中:

class MainActivity : AppCompatActivity() {

    overriding fun onCreate{
            [...]
            val mainUi = AnkoUi()
            // some dynamic task...
            mainUi.networkFeedback("lalala")
     }

    fun doSomething(number: Int, callback: TextView){
            //Some network or database task goes here!

            //And then, if the operation was successful

            callback.text = "Something has changed..."
        }

这是一种非常不同的方法。我不确定我是否喜欢它,但这是一个完全不同的讨论......

于 2016-12-07T16:57:56.630 回答