← Назад к вопросам

Как зарезервировать пространство для объекта и сделать его невидимым в 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 для гладких переходов
Как зарезервировать пространство для объекта и сделать его невидимым в XML | PrepBro