У меня есть действие, которое содержит 2 группы представлений, которые НЕ МОЖЕТ находиться в той же группе LAYOUT, но принадлежать к той же группе LOGIC, что означает, что они должны быть показаны или скрыты и привязаны к событию щелчка одновременно. Дело в том, что мне ужасно неприятно писать что-то вроде этого:
fun hide() {
view1.visibility = View.GONE
view2.visibility = View.GONE
view3.visibility = View.GONE
// ...
view9.visibility = View.GONE
}
fun show() {
view1.visibility = View.VISIBLE
view2.visibility = View.VISIBLE
view3.visibility = View.VISIBLE
// ...
view9.visibility = View.VISIBLE
view1.setOnClickListener{ run() }
view2.setOnClickListener{ run() }
view3.setOnClickListener{ run() }
// ...
view9.setOnClickListener{ run() }
}
Я прочитал сообщение, в котором описывается котлин умение, чтобы упростить этот беспорядок, каким-то образом группируя эти представления, а затем просто обрабатывая группы, но, к сожалению, я больше не могу найти этот пост ..
Помощь будет признательна!
========= Обновление 2019-07-31 =========
Я нашел решение, но забыл обновить этот вопрос, `` группировка '', которую я искал, на самом деле не является специфической функцией Kotlin, а просто использует варарг, и мы можем использовать расширение Kotlin (которое УДИВИТЕЛЬНО), чтобы немного упростить:
// assume we have a base activity or fragment, then put below functions in there
fun View.show() {
visibility = View.VISIBLE
}
fun show(vararg views: View) {
views.forEach { it.show() }
}
fun View.hide() {
visibility = View.GONE
}
fun hide(vararg views: View) {
views.forEach { it.hide() }
}
// then in any activity or fragment
show(v1, v2, v3, v4)
v9.hide()
============= обновлено 07.03.2020 ================
Именно для этого предназначен androidx.constraintlayout.widget.Group, который может логически группировать кучу представлений из любого места и управлять их видимостью, только изменяя видимость группы.
@AmitJangid Я бы хотел, чтобы это было так просто, но эти представления, принадлежащие одной логической группе, не могут быть просто добавлены в одну группу макетов .. они все смешаны вместе ..
В зависимости от того, как структурирован ваш макет, вы можете сгруппировать эти представления в ViewGroup, например LinearLayout, RelativeLayout, FrameLayout или ConstraintLayout.
Затем вы можете изменить видимость только на ViewGroup, и все его дочерние элементы тоже это изменят.
Редактировать:
Без ViewGroup единственное решение для устранения этого шаблона - включить привязку данных в вашем проекте и установить ее следующим образом:
В вашей деятельности / фрагменте:
val groupVisible = ObservableBoolean()
fun changeVisibility(show: Boolean) {
groupVisible.set(show)
}
В вашем xml:
<layout>
<data>
<variable name = "groupVisible" type = "Boolean"/>
</data>
<View
android:visibility = "@{groupVisible ? View.VISIBLE : View.GONE}"/>
</layout>
извините, приятель, я не ясно выразился, теперь вопрос обновлен, эти представления принадлежат одной логической группе, не могут быть расположены в той же группе макета.
Если ваши представления не входят в группу представлений вы можете использовать функция расширения. Вы можете создать один для переключения видимости представлений:
fun View.toggleVisibility() {
if (visibility == View.VISIBLE) {
visibility = View.GONE
} else {
visibility = View.VISIBLE
}
}
И вы можете использовать это так:
view.toggleVisibility()
спасибо, что эти представления действительно находятся не в той же группе макетов, но с вашим предложением мне все равно нужно написать десяток строк xxxx.toggleVisibility (), чего я бы хотел избежать.
Почему бы вам не создать массив:
val views = arrayOf(view1, view2, view3, view4, view5, view6, view7, view8, view9)
затем:
fun show() {
views.forEach {
it.visibility = View.VISIBLE
it.setOnClickListener{ }
}
}
fun hide() {
views.forEach { it.visibility = View.INVISIBLE }
}
Или без массива, если имена представлений наверняка похожи на view1, view2, ...
for (i in 1..9) {
val id = resources.getIdentifier("view$i", "id", context.getPackageName())
val view = findViewById<View>(id)
view.visibility = View.VISIBLE
view.setOnClickListener{ }
}
Это точно может, спасибо! однако это не то, что я видел в том посте, а это что-то ... эээ. скажем, котлин-волшебство ..
зачем вам создавать ненужные циклы, если это можно сделать через группы
Вы можете определить функцию с тремя параметрами и использовать vararg, как в следующем коде:
fun changeVisiblityAndAddClickListeners(visibility: Int,
listener: View.OnClickListener,
vararg views: View) {
for (view: View in views) {
view.visibility = visibility
if (visibility == View.VISIBLE) {
view.setOnClickListener(listener)
}
}
}
Конечно, если у вас слишком много просмотров, это не эффективное решение. Я просто добавил этот фрагмент кода для альтернативного способа, особенно для проблем с набором динамических представлений.
Сначала в макете xml сгруппируйте представления по атрибуту android:tag = "group_1".
Затем внутри вашей деятельности используйте цикл for для реализации любой необходимой вам логики:
val root: ViewGroup = TODO("find your root layout")
for (i in 0 until root.childCount) {
val v = root.getChildAt(i)
when (v.tag) {
"group_1" -> {
TODO()
}
"group_2" -> {
TODO()
}
else -> {
TODO()
}
}
}
Создайте список представлений и зацикливайтесь на нем
val views = listOf<View>(view1, view2, ...)
views.forEach {
it.visibility = View.GONE
}
Вы также можете создать функция расширенияIterable<View>, чтобы упростить любые действия в перечисленных представлениях.
fun Iterable<View>.visibility(visibility: Int) = this.forEach {
it.visibility = visibility
}
//usage
views.visibility(View.GONE)
Возможно, вы хотите найти все представления из тегов в XML. Взгляните на этот ответ
Начиная с ConstraintLayout 1.1, вы можете использовать Group вместо LayoutGroup.
Вы можете просто добавить этот код в свой XML-макет
<android.support.constraint.Group
android:id = "@+id/profile"
app:constraint_referenced_ids = "profile_name,profile_image" />
А затем вы можете вызвать его из кода, чтобы добиться нужного вам поведения.
profile.visibility = GONE
profile.visibility = VISIBLE
Подробнее читайте в статье https://medium.com/androiddevelopers/introduction-constraint-layout-1-1-d07fc02406bc
Если вы используете androidx, используйте androidx.constraintlayout.widget.Group вместо
Вам необходимо создать функции расширения.
Например:
fun View.showGroupViews(vararg view: View) {
view.forEach {
it.show()
}
}
fun View.hideGroupViews(vararg view: View) {
view.forEach {
it.hide()
}
}
Спасибо! Это тот, который наиболее близок к тому, что я искал и использую в настоящее время. Я обновил решение, которое использую в своем вопросе. Ваше здоровье.
Вы можете создать LinearLayout или любой другой ViewGroup, содержащий вашего дочернего Views, и дать ему идентификатор в XML-файле, а затем в вашем классе Activity или Fragment определить следующие функции:
fun disableViewGroup(viewGroup: ViewGroup) {
viewGroup.children.iterator().forEach {
it.isEnabled = false
}
}
fun enableViewGroup(viewGroup: ViewGroup) {
viewGroup.children.iterator().forEach {
it.isEnabled = true
}
}
А затем в onCreate() или onStart() назовите его следующим образом:
disableViewGroup(idOfViewGroup)
Метод children возвращает Sequence дочерних View в ViewGroup, который вы можете перебрать с помощью forEach и применить любую операцию, применимую к View.
Надеюсь, это поможет!
добавьте их в один макет, например линейный макет ...