Доступ к представлениям из Activity с Anko

Я знаю, что я могу использовать атрибут id с Anko для определения вида:

 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" } } 

Но я чувствую, что чего-то не хватает; единственное место, где README упоминает функцию find или Kotlin Android Extensions, находится в разделе « Поддержка существующего кода :

Вам не нужно переписывать весь пользовательский интерфейс с Anko. Вы можете сохранить старые классы, написанные на Java. Более того, если вы по-прежнему хотите (или имеете) написать класс активности Kotlin и по какой-то причине раздуваете XML-макет, вы можете использовать свойства «Вид», что упростит ситуацию:

 // 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-кода.

Поэтому мой вопрос: использует id вместе с функцией find правильный способ доступа к View из Activity с помощью Anko? Есть ли способ «Анко» справиться с этим? Или я пропустил какую-то другую выгоду от Anko, которая делает доступ к View из Activity нерелевантным?


И второй связанный вопрос; если это правильный способ доступа к View из Activity , существует ли способ создания ресурса id (т.е. "@+id/" ) из AnkoComponent ? Вместо того, чтобы создавать каждый id в файле ids.xml .

Итак, зачем все еще использовать XML id для поиска View? поскольку мы уже используем Anko вместо XML.

На мой взгляд, мы можем хранить элементы представления внутри AnkoComponent вместо метода id id find view . Проверьте удар кода:

 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" } } 

Я считаю, что, поскольку вы можете добавить поведение к своим файлам Anko, вам не нужно создавать свои представления в действии вообще.

Это может быть действительно здорово, потому что вы можете еще больше отделить слой вида. Весь код, который действует в ваших представлениях, может быть вставлен в файлы Anko. Итак, все, что вам нужно сделать, – это вызвать методы вашей активности из Anko и не создавать какие-либо представления.

Но если вам нужно создать экземпляр любого представления … вы можете использовать Kotlin Android Extensions в своей деятельности.

Exemple:

Код в вашей деятельности:

 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 } }) 

Код в Анко:

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

Теперь код находится в AnkoComponent. Нет необходимости создавать экземпляр представления.

Вывод:

Это более «Anko» способ программирования, если вы поместите всю свою логику взглядов в AnkoComponents, а не в свою деятельность.

Редактировать:

В качестве примера кода, в котором вам не нужно создавать экземпляр представления:

В вашем Анко:

 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..." } 

Это совсем другой подход. Я не уверен, нравится мне это или нет, но это совсем другое обсуждение …

Не используйте идентификатор для определения видов с помощью 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 } } } 

Обратите внимание на определение класса пользовательского интерфейса:

 class ActivityMainUI : AnkoComponent<ActivityMain> { 

Если вы разместите там имя класса активности в скобках, тогда все его общедоступные переменные станут доступными через владельца в корпусе класса пользовательского интерфейса, чтобы вы могли их осмыслить.
Но вы можете легко установить AppCompatActivity и создать универсальный класс, который может быть клонирован. В этом случае используйте lateinit var mTextView: TextView в теле интерфейса UI, как описано в ответе Джейкоба.