← Назад к вопросам
Как зарезервировать пространство для объекта и сделать его невидимым в XML
1.0 Junior🔥 141 комментариев
#Android компоненты#UI и вёрстка
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как зарезервировать пространство для объекта и сделать его невидимым в XML
Это частая задача: нужно, чтобы View занимал место на экране, но был невидим. Есть несколько способов, и каждый имеет своё применение.
1. Различие между visibility состояниями
| Значение | Видимость | Место | Использование |
|---|---|---|---|
| visible | Видно | Занимает | Обычное состояние |
| invisible | Скрыто | Занимает | Placeholder, нужно место |
| gone | Скрыто | Не занимает | Убрать из layout |
2. invisible — скрыть, но оставить место
Этот способ ЗАРЕЗЕРВИРУЕТ пространство:
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="Я займу место, но не буду видна"
android:visibility="invisible" />
Результат:
- TextView скрыта
- Место зарезервировано (100dp высоты)
- Другие View'ы не сдвигаются
3. gone — убрать, не оставляя места
Этот способ НЕ зарезервирует пространство:
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="Я буду убрана из layout"
android:visibility="gone" />
Результат:
- TextView убрана полностью
- Место НЕ зарезервировано
- Другие View'ы подвинут вверх
4. Практический пример: placeholder при загрузке
Сценарий: загружаем изображение, а пока оно загружается, нужно зарезервировать место для него.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="300dp">
<!-- Placeholder (зарезервирует место) -->
<ImageView
android:id="@+id/placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:src="@drawable/placeholder"
android:visibility="invisible" />
<!-- Реальное изображение (когда загрузится, покажется) -->
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<!-- Loading spinner (видно во время загрузки) -->
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
Код:
Glide.with(this)
.load(imageUrl)
.addListener(object : RequestListener<Drawable> {
override fun onLoadFailed(...): Boolean {
loadingSpinner.gone()
return false
}
override fun onResourceReady(...): Boolean {
loadingSpinner.gone()
placeholder.gone() // Убираем placeholder
return false
}
})
.into(imageView)
5. Программное управление visibility
// Скрыть, оставив место
view.visibility = View.INVISIBLE
// Убрать совсем
view.visibility = View.GONE
// Показать
view.visibility = View.VISIBLE
// Переключить с transition
TransitionManager.beginDelayedTransition(container)
view.visibility = View.INVISIBLE
6. Аниимированное переключение visibility
С использованием ObjectAnimator:
// Плавная скрытие (invisible)
ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0f).apply {
duration = 300
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
view.visibility = View.INVISIBLE // Скрываем после animation
}
})
start()
}
// Плавное показание
ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f).apply {
duration = 300
start()
}
view.visibility = View.VISIBLE // Показываем сразу
7. View.INVISIBLE vs View.GONE — различие в layout
Визуально:
VIEW = [████████]
Gone: invisible:
[Label] [Label]
[View] [ ] ← место зарезервировано
[Next] [Next] ← без смещения
vs
Gone:
[Label]
[Next] ← сдвинуто вверх
8. Практический пример: видимость в зависимости от данных
class UserProfileActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
val bioTextView = findViewById<TextView>(R.id.bio)
val bioLabelView = findViewById<TextView>(R.id.bio_label)
viewModel.userData.observe(this) { user ->
if (user.bio.isNotEmpty()) {
// Показываем био
bioLabelView.visibility = View.VISIBLE
bioTextView.text = user.bio
bioTextView.visibility = View.VISIBLE
} else {
// Скрываем, но оставляем место (invisible)
// Это избежит скачков в layout
bioLabelView.visibility = View.INVISIBLE
bioTextView.visibility = View.INVISIBLE
}
}
}
}
9. Использование ViewStub для отложенной загрузки
Если элемент редко используется, используй ViewStub:
<ViewStub
android:id="@+id/stub_advanced_settings"
android:layout="@layout/layout_advanced_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Код (загрузить при необходимости):
val stub = findViewById<ViewStub>(R.id.stub_advanced_settings)
if (needAdvancedSettings) {
val advancedSettings = stub.inflate() // Загружает layout только сейчас
// Теперь можем использовать advancedSettings
}
10. Полезные extension функции
// Extension для упрощения
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE // Зарезервирует место
}
fun View.gone() {
visibility = View.GONE // Уберёт совсем
}
fun View.toggleVisibility() {
visibility = if (visibility == View.VISIBLE) View.GONE else View.VISIBLE
}
// Использование
view.invisible() // Вместо view.visibility = View.INVISIBLE
view.gone()
view.visible()
11. Проблемы и решения
Проблема: скачки при переключении visibility
<!-- Может быть мерцание -->
<ImageView
android:id="@+id/loading"
android:layout_width="50dp"
android:layout_height="50dp"
android:visibility="invisible" />
Решение: использовать placeholder с одинаковым размером
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/light_gray" />
<ImageView
android:id="@+id/loading"
android:layout_width="50dp"
android:layout_height="50dp"
android:visibility="gone" />
12. Рекомендации
- invisible — когда нужно оставить место (loading, placeholder)
- gone — когда элемент не нужен вообще (условный контент)
- visible — нормальное состояние
- Не переключай часто — это может привести к лагам
- Используй TransitionManager для плавных переходов
- ViewStub — для редко используемых элементов
Итог
- invisible → скрыт, но место зарезервировано
- gone → скрыт, место не зарезервировано
- Используй invisible для placeholder'ов при загрузке
- Используй gone для условного контента
- Комбинируй с animation для гладких переходов