Shadow (сенка) — визуелни ефекат у мобилним интерфејсима који ствара илузију дубине и хијерархије између елемената. Сенке показују који елемент се налази више у Z-равни и, самим тим, важнији је или интерактивнији. Према Material Design Guidelines (Google, 2026), системске сенке користе пет кључних висина (elevation): 0 dp (равно), 1–4 dp (дугмад), 6–12 dp (картице), 16–24 dp (дијалози), 24+ dp (модални прозори). Више о висини елемената прочитајте у чланку о Elevation.
Главно
Сенка (shadow) у корисничким интерфејсима — визуелни ефекат који имитира осветљење и дубину. Сенка се ствара цртањем тамне замућене копије елемента померене у односу на оригинал. У мобилном дизајну сенке обављају три функције: показују хијерархију (виши елемент — дужа сенка), сигнализирају интерактивност (дугмад са сенком изгледају кликабилно), одвајају садржај од позадине (картице са сенком се читају као засебни блокови).
У Google-овом Material Design-у сенке су нераскидиво повезане са концептом elevation (висине). Сваки елемент заузима одређену висину у Z-координати, а сенка је пројекција осветљења одозго. Apple-ове Human Interface Guidelines не прописују строги систем висина, али препоручују коришћење сенки за стварање визуелне хијерархије и дубине у интерфејсима.
Према истраживању Nielsen Norman Group (2024), правилно постављене сенке смањују време проналажења интерактивног елемента за 24%. Сенке такође помажу корисницима са оштећењем вида да разликују границе елемената. Међутим, прекомерна употреба сенки (3+ нивоа на екрану) повећава когнитивно оптерећење и погоршава перцепцију.
На iOS-у сенке се реализују кроз својства CALayer-а: shadowColor поставља боју сенке, shadowOffset — померај у CGSize (x, y), shadowRadius — радијус замућења, shadowOpacity — непрозирност од 0 до 1. За перформансе се препоручује и постављање shadowPath — UIBezierPath који описује облик сенке, како Core Animation не би рачунала аутоматски.
// UIKit: подешавање сенке кроз CALayer
import UIKit
let cardView = UIView()
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 12
// Подешавање сенке
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.15
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
cardView.layer.shadowRadius = 8
"> Optimзация: явный shadowPath
cardView.layer.shadowPath = UIBezierPath(
roundedRect: cardView.bounds,
cornerRadius: 12
).cgPath
У SwiftUI сенке се постављају кроз модификатор .shadow() са параметрима color, radius, x, y. SwiftUI аутоматски примењује shadowPath и управља перформансама рендеровања. За напредне сенке (унутрашње сенке, вишеструке сенке) користите overlay() са LinearGradient.
// SwiftUI: сенка кроз модификатор shadow
import SwiftUI
VStack {
Text("Картица са сенком")
.padding()
.background(Color.white)
.cornerRadius(16)
.shadow(
color: .black.opacity(0.15),
radius: 10,
x: 0,
y: 4
)
}
Перформансе сенки на iOS-у: ако shadowPath није постављен, Core Animation рачуна сенку на основу облика слоја сваки кадар, што може изазвати успоравање током анимације. За статичне елементе увек постављајте shadowPath. За анимиране елементе користите shouldRasterize = true на CALayer-у да бисте кеширали сенку у засебан слој. У SwiftUI-ју растеретизација се управља кроз .drawingGroup().
У Android-у сенке у Material Design-у се реализују кроз elevation — својство View-а које поставља висину елемента у Z-координати. Систем аутоматски црта сенку на основу elevation и outlineProvider-а (контуре елемента). Што је elevation веће, то је сенка већа и замућенија. За View-ове који не наслеђују Material Design (нпр. AppCompat), сенке раде само уз укључено хардверско убрзање.
<!-- XML: elevation кроз атрибуте -->
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp"
app:cardElevation="6dp">
<!-- Садржај картице -->
</androidx.cardview.widget.CardView>
За прилагођене сенке у Android View систему користи се OutlineProvider. ViewOutlineProvider омогућава постављање произвољног облика кроз outline.setRoundRect() или outline.setPath(). Без OutlineProvider-а сенка се црта по правоугаоном облику View-а, што не узима у обзир заобљење углова.
// Kotlin: прилагођени OutlineProvider за сенку
import android.graphics.Outline
import android.view.View
import android.view.ViewOutlineProvider
val myView: View = findViewById(R.id.myView)
myView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(
0, 0, view.width, view.height,
12f // радијус угла
)
}
}
myView.elevation = 8f // висина сенке у px
myView.translationZ = 4f // додатна висина при притиску
У Jetpack Compose-у сенке се управљају кроз Modifier.shadow() и elevation у компонентама Card и Surface. Modifier.shadow() прима elevation и shape. За разлику од View система, Compose црта сенке у сопственом рендер-пајплајну, што даје предвидљивије понашање на свим верзијама Android-а.
// Jetpack Compose: сенка кроз Modifier.shadow
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Card(
modifier = Modifier.shadow(
elevation = 6.dp,
shape = RoundedCornerShape(12.dp),
clip = false
),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Text("Card са прилагођеном сенком")
}
Правилно коришћење сенки побољшава перцепцију интерфејса, неправилно — ствара визуелни шум и погоршава перформансе. Material Design дефинише пет нивоа elevation: 0 dp (без сенке), 1–4 dp (дугмад, чипови), 6–12 dp (картице, менији), 16–24 dp (дијалози, доњи панели), 24+ dp (модални прозори, FAB).
| Ниво | Elevation | Елементи | Карактеристика сенке |
|---|---|---|---|
| 0 | 0 dp | Текст, иконе, позадина | Без сенке, равни слој |
| 1 | 1–4 dp | Дугмад, поља за унос | Лагана сенка, мали померај |
| 2 | 6–12 dp | Картице, Snackbar | Умерена сенка, приметно замућење |
| 3 | 16–24 dp | Дијалози, менији | Дубока сенка, велико замућење |
| 4 | 24+ dp | Модални прозори | Максимална сенка, елемент лебди |
Правила доброг тона: (1) не користите сенке за елементе који не треба да привлаче пажњу (позадине, разделници), (2) висина сенке треба да одговара важности елемента — што важније, то више, (3) при притиску на дугме смањујте elevation анимирано за тактилну повратну информацију, (4) избегавајте сенке на тамним позадинама — користите overlay (осветљење/затамњење) уместо сенке. У Material You (Android 12+) сенке се прилагођавају теми: на тамној позадини elevation се замењује слојем боје (surface tint).
У Flutter-у сенке се реализују кроз BoxShadow унутар BoxDecoration. BoxShadow прима color, offset, blurRadius и spreadRadius. Flutter подржава вишеструке сенке: прослеђивање листе BoxShadow омогућава стварање сложених ефеката — на пример, спољашња сенка + унутрашње осветљење. PhysicalModel — алтернатива која симулира физичку сенку на основу облика (BeveledRectangleBorder, CircleBorder).
// Flutter: сенка кроз BoxDecoration + BoxShadow
import 'package:flutter/material.dart';
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
offset: Offset(0, 4),
blurRadius: 8.0,
spreadRadius: 0,
),
],
),
child: Text('Контејнер са сенком'),
)
// PhysicalModel за физичку сенку
PhysicalModel(
color: Colors.white,
elevation: 6.0,
shadowColor: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.0),
child: Text('Физички модел са сенком'),
)
Перформансе: BoxShadow са вишеструким сенкама може изазвати прецртавање при свакој промени (repaint). За статичне елементе користите PhysicalModel — он кешира сенку у засебан слој (RepaintBoundary). У Flutter-у 3.16+ додата је подршка за Material 3 elevation са адаптивним сенкама које мењају боју и замућење у зависности од теме (light/dark).
Често постављана питања
Elevation — нумеричка висина елемента у Z-координати, а shadow (сенка) — визуелни ефекат створен том висином. У Android-у elevation — својство View-а које аутоматски генерише сенку. У дизајну, elevation и shadow се често користе као заменљиви термини, али технички elevation је узрок, а shadow — последица.
Проверите: (1) да View има elevation веће од 0, (2) да је постављен outlineProvider (ако View није из Material библиотеке), (3) да је укључено хардверско убрзање (android:hardwareAccelerated="true" у манифесту). CardView аутоматски управља outlineProvider-ом. За прилагођене View-ове позовите view.outlineProvider = ViewOutlineProvider.BACKGROUND.
CALayer директно не подржава унутрашње сенке. Користите комбинацију: CAGradientLayer са црном бојом и провидношћу унутар маске (mask), или поставите UIImageView са растерском унутрашњом сенком. У SwiftUI-ју унутрашња сенка се реализује кроз overlay са LinearGradient и blendMode(.multiply).
У Android-у користите translationZ за анимацију: у мировању elevation = 2 dp, при притиску translationZ = 4 dp (укупна висина 6 dp). На iOS-у анимирајте shadowOffset и shadowRadius истовремено са трансформацијом дугмета. У SwiftUI-ју користите withAnimation са променом elevation кроз Modifier.shadow(). У Flutter-у — AnimatedContainer са променом BoxShadow.
Material Design препоручује не више од три нивоа elevation на једном екрану. Ако има више елемената са сенком — обједините их у групе са истом висином. Прекомеран број сенки ствара визуелни шум и смањује перформансе рендеровања на уређајима средњег и буџетског сегмента.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође