我知道我可以使用Anko的id
属性来识别视图:
class MainActivityUI : AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
frameLayout {
textView {
id = R.id.text
}
}
}
}
然后使用Activity
函数(或使用Kotlin Android Extensions)在find()
中获取它:
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"
}
}
但我觉得我错过了一些东西; README提到find
函数或Kotlin Android Extensions的唯一位置在标题为支持现有代码的部分中:
您不必使用Anko重写所有用户界面。你可以保持旧的 用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可以使代码更加紧凑 扩展。
这使find
函数似乎仅用于支持&#34; old&#34; XML代码。
所以我的问题是这个;正在使用id
和find
函数使用Anko从View
访问Activity
的正确方法?还有更多&#34; Anko&#34;处理这个的方式?或者我错过了Anko的其他一些好处,使View
无法访问Activity
?
第二个相关问题;如果此 是从View
访问Activity
的正确方法,是否有办法创建id
资源(即"@+id/"
)从AnkoComponent
开始?而不是在id
文件中创建每个ids.xml
。
答案 0 :(得分:8)
那么,为什么还要使用XML id
来查找视图?因为我们已经使用Anko而不是XML。
在我看来,我们可以将视图元素存储在AnkoComponent
内,而不是find view
的id方法中。检查代码打击:
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"
}
}
答案 1 :(得分:2)
请勿使用 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 并制作一些可能被克隆的通用类。在这种情况下,使用 lateinit var mTextView:
在Jacob的答案中描述的UI类主体中的TextView 。
答案 2 :(得分:1)
我相信,由于您可以向Anko文件添加行为,因此您根本不必在活动中实例化您的视图。
这可能非常酷,因为您可以更多地分离视图层。您视图中的所有代码都可以插入Anko文件中。因此,您所要做的就是从Anko调用您的活动的方法,而不是实例化任何视图。
但是如果您需要实例化任何视图......您可以在活动中使用Kotlin Android Extensions。
例如:
您活动中的代码:
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..."
}
这是一种非常不同的方法。我不确定我是否喜欢它,但这是一个完全不同的讨论......
答案 3 :(得分: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)
}
}
}