Niestandardowe widoki i rysowanie w rozwoju mobilnym: istota, jakie API i jak działa

Autor: IT Sectr Opublikowano: 2026-08-01 Czas czytania: 11 min

Niestandardowe widoki są podstawą unikalnego interfejsu każdej aplikacji mobilnej. Niestandardowe widoki w aplikacjach mobilnych pozwalają tworzyć własną grafikę, animacje i elementy niedostępne w standardowych komponentach. Według Apple Developer, 2025, drawRect pozostaje główną metodą niestandardowego rysowania w mobilnym rozwoju iOS. Na Androidzie tę samą rolę pełni onDraw z Canvas, a we Flutter — CustomPainter.

Najważniejsze

  • Niestandardowe widoki — komponenty zdefiniowane przez użytkownika z własną logiką rysowania, rozmiaru i zachowania w aplikacjach mobilnych.
  • drawRect — metoda UIView na iOS do niestandardowego rysowania przez Core Graphics i CGContext.
  • onDraw — metoda View na Androidzie do rysowania przez Canvas i Paint z systemem pomiaru onMeasure.
  • CustomPainter — klasa Flutter do rysowania na Canvas z metodami paint i shouldRepaint.
  • Pomiar — proces określania wymiarów widoku przez sizeThatFits na iOS, onMeasure na Androidzie i computeDryLayout we Flutter.

Czym są niestandardowe widoki i dlaczego są potrzebne w aplikacjach mobilnych

Niestandardowe widoki to komponenty interfejsu zdefiniowane przez użytkownika, które nadpisują standardowe metody rysowania i pomiaru w celu tworzenia unikalnej grafiki. Wykresy, animacje, diagramy, niestandardowe elementy czatu i maski AR — to typowe scenariusze użycia niestandardowych widoków w aplikacjach mobilnych. Standardowe komponenty UI (Button, TextView, Label) pokrywają 80% zadań, ale pozostałe 20% wymaga pełnej kontroli nad rysowaniem w rozwoju mobilnym. Rysowanie w rozwoju mobilnym to umiejętność, która odróżnia programistę juniora od seniora.

Kiedy niestandardowe widoki są uzasadnione

Niestandardowe widoki w aplikacjach mobilnych są potrzebne do unikalnej grafiki 2D, złożonych animacji, wykresów i wizualizacji danych. Jeśli standardowy UIKit nie zapewnia wymaganego elementu — tworzony jest niestandardowy widok. W aplikacjach mobilnych niestandardowe widoki są używane do pasków postępu, niestandardowych przycisków, wypełnień gradientowych, animowanych ikon i kanw do rysowania palcem. Ważne jest, aby nie nadużywać — do prostych stylów wystarczy skonfigurować standardowe komponenty przez API wyglądu.

Niestandardowe widoki na iOS: drawRect i Core Graphics

Na iOS niestandardowe widoki są tworzone przez dziedziczenie po UIView i nadpisanie metody drawRect. drawRect jest wywoływany przy pierwszym renderowaniu i po każdym wywołaniu setNeedsDisplay(). Wewnątrz drawRect programista otrzymuje CGContext przez UIGraphicsGetCurrentContext() — płótno dla linii, kształtów, gradientów i tekstu. Core Graphics (Quartz 2D) to niskopoziomowy silnik renderowania na CPU, który daje pełną kontrolę nad każdym pikselem. UIBezierPath to wygodna nakładka do tworzenia ścieżek ze zwięzłą składnią.

swift
class CircleView: UIView {
    private var fillColor: UIColor = .systemBlue

    override func drawRect(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.setFillColor(fillColor.cgColor)
        ctx.addEllipse(in: bounds.insetBy(dx: 4, dy: 4))
        ctx.drawPath(using: .fill)
    }

    func updateColor(_ newColor: UIColor) {
        fillColor = newColor
        setNeedsDisplay()
    }
}

Core Graphics: CGContext, CGGradient i transformacje

Core Graphics udostępnia CGContext — płótno dla wszystkich operacji rysowania. CGGradient tworzy gradienty liniowe i radialne z obsługą CGColorSpace (sRGB, Display P3). Transformacje są wykonywane przez CGAffineTransform — macierz 3x3 do obrotu, skalowania i przesunięcia. CGContextTranslateCTM, CGContextRotateCTM i CGContextScaleCTM modyfikują układ współrzędnych. Core Graphics działa na CPU, więc złożona grafika może obciążać procesor — użyj Metal do akceleracji GPU.

UIBezierPath do tworzenia kształtów

UIBezierPath to obiektowa nakładka na CGPath. Metoda addArc(withCenter:radius:startAngle:endAngle:clockwise:) tworzy łuki i okręgi, addCurve tworzy krzywe Béziera. Ścieżki obsługują operacje union, intersection i subtraction przez addClip. UIBezierPath jest wygodny do niestandardowych masek (maskView), ścieżek przycinania i złożonych kształtów — gwiazd, serc, niestandardowych ikon.

Niestandardowe widoki na Androidzie: onDraw i Canvas

Na Androidzie niestandardowy widok rozszerza View z nadpisanym onDraw(Canvas). Canvas zawiera wszystkie metody rysowania w rozwoju mobilnym: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath i drawRoundRect. Paint konfiguruje parametry — kolor, grubość linii, styl (FILL, STROKE, FILL_AND_STROKE), wygładzanie (isAntiAlias) i rozmiar tekstu. onDraw jest wywoływany przy każdym invalidate() i nie powinien zawierać ciężkich operacji — wszystkie obliczenia są buforowane.

kotlin
class CustomCircleView(context: Context, attrs: AttributeSet?)
    : View(context, attrs) {

    private val paint = Paint().apply {
        style = Paint.Style.FILL
        color = Color.BLUE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 4f
        canvas.drawCircle(cx, cy, radius, paint)
    }
}

Path i animacje na Androidzie

Path na Androidzie jest odpowiednikiem UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo i quadTo. PathMeasure oblicza długość ścieżki i współrzędne w dowolnym punkcie — przydatne do animowania ruchu obiektu wzdłuż ścieżki. Do animacji używa się ValueAnimator z invalidate() w callbacku. Animator może zmieniać kolor, promień, pozycję — dowolną właściwość wpływającą na rysowanie. Niestandardowe widoki na Androidzie obsługują również StateListDrawable i animated-vector do animacji przez XML.

Shader i gradienty w Canvas

Gradienty na Androidzie są ustawiane przez Shader — LinearGradient, RadialGradient i SweepGradient. Shader jest przypisywany do Paint przez paint.setShader(shader). LinearGradient generuje gradient liniowy między dwoma punktami z opcjonalnymi pozycjami kolorów. RadialGradient — radialny od środka do krawędzi. SweepGradient — stożkowy wokół punktu środkowego. Shader.TileMode (CLAMP, REPEAT, MIRROR) określa zachowanie poza granicami obszaru.

CustomPainter we Flutter: rysowanie na Canvas

Flutter używa CustomPainter — klasy z metodami paint(Canvas canvas, Size size) i shouldRepaint. Canvas we Flutter zapewnia te same metody co w Androidzie: drawCircle, drawRect, drawLine, drawPath, drawParagraph i drawImage. Paint we Flutter konfiguruje kolor, grubość, styl i wygładzanie. Flutter nie używa drawRect ani onDraw — całe rysowanie odbywa się przez CustomPainter, osadzony w widgecie CustomPaint.

dart
class CirclePainter extends CustomPainter {
  final Color color;

  CirclePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = size.shortestSide / 2 - 4;
    canvas.drawCircle(size.center(Offset.zero), radius, paint);
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) =>
    oldDelegate.color != color;
}

shouldRepaint i RepaintBoundary

shouldRepaint określa, czy CustomPainter wymaga przerysowania. Zwracaj true tylko wtedy, gdy zmieniają się dane wpływające na renderowanie — kolor, rozmiar, dane wykresu. RepaintBoundary izoluje przerysowanie w oddzielną warstwę — używaj dla widgetów, które rzadko się zmieniają. Flutter nie ma setNeedsDisplay ani invalidate — przerysowanie jest wyzwalane przez setState lub ValueNotifier z nasłuchem zmian.

Gradienty i transformacje we Flutter

Flutter obsługuje LinearGradient, RadialGradient i SweepGradient — te same typy co w Androidzie. Gradient tworzy Shader dla Paint przez createShader(Rect bounds). Transformacje są wykonywane przez canvas.rotate, canvas.scale, canvas.translate i canvas.skew. Flutter używa macierzy transformacji 4x4 (Matrix4) dla widgetu Transform. Animacje rysowania we Flutter są tworzone przez AnimationController w połączeniu z setState do przerysowania CustomPainter.

Pomiar niestandardowych widoków: metody sizeThatFits, onMeasure i computeDryLayout

Prawidłowy pomiar niestandardowych widoków jest podstawą przewidywalnego zachowania interfejsu. Na iOS rozmiar widoku jest określany przez sizeThatFits i intrinsicContentSize. sizeThatFits zwraca optymalny rozmiar dla danych ograniczeń. intrinsicContentSize — naturalny rozmiar treści bez zewnętrznych ograniczeń. Na Androidzie pomiar jest implementowany w onMeasure z parametrami MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). We Flutter rozmiar jest przekazywany do paint(Canvas, Size) i może być obliczony przez computeDryLayout lub LayoutBuilder.

sizeThatFits i intrinsicContentSize na iOS

intrinsicContentSize zwraca CGSize — naturalny rozmiar widoku na podstawie jego treści. setContentHuggingPriority i setContentCompressionResistancePriority kontrolują zachowanie podczas rozciągania i ściskania. sizeThatFits jest wywoływany przez system do obliczenia rozmiaru w Auto Layout. Dla niestandardowych widoków nadpisz intrinsicContentSize, jeśli twój komponent ma naturalny rozmiar — na przykład okrąg powinien być zawsze 100x100.

onMeasure i MeasureSpec na Androidzie

onMeasure przyjmuje widthMeasureSpec i heightMeasureSpec. MeasureSpec zawiera tryb i rozmiar: UNSPECIFIED (bez ograniczeń, widok sam wybiera rozmiar), EXACTLY (dokładny rozmiar od rodzica), AT_MOST (maksymalny rozmiar). setMeasuredDimension(width, height) zapisuje wynik pomiaru. Przy zmianie danych wywołaj requestLayout() do ponownego pomiaru. Zagnieżdżone ViewGroup wymagają nadpisania onLayout do rozmieszczenia elementów potomnych.

PlatformaMetoda pomiaruWywołanie przy zmianieZwrot
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (zapisuje rozmiar)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout we Flutter

computeDryLayout to metoda RenderObject do obliczania rozmiaru bez pełnego cyklu układu. LayoutBuilder.getSize — alternatywa do uzyskania dostępnej przestrzeni w metodzie build. We Flutter rozmiar płótna jest przekazywany do paint jako Size i nie wymaga oddzielnego pomiaru — CustomPainter rysuje w przekazanych granicach. Jednak dla niestandardowych RenderObject należy nadpisać performLayout i computeDryLayout.

Często zadawane pytania

Czym jest drawRect na iOS i kiedy jest wywoływany?

drawRect to metoda UIView do niestandardowego rysowania przez Core Graphics. Jest wywoływana przy pierwszym renderowaniu widoku i po każdym wywołaniu setNeedsDisplay(). Użyj CGContext wewnątrz drawRect dla linii, kształtów i tekstu.

Jak rysować na Androidzie za pomocą Canvas?

Utwórz klasę rozszerzającą View, nadpisz onDraw(Canvas canvas) i użyj Canvas API: drawCircle, drawRect, drawPath. Paint konfiguruje kolor, grubość i styl. Do aktualizacji wywołaj invalidate().

Czym jest CustomPainter we Flutter?

CustomPainter to klasa Flutter do niestandardowego rysowania na Canvas. Zaimplementuj metody paint(Canvas, Size) i shouldRepaint. Jest umieszczany przez widget CustomPaint. Flutter nie ma drawRect — całe rysowanie odbywa się przez CustomPainter.

Jak zmierzyć rozmiar niestandardowego widoku?

Na iOS użyj sizeThatFits i intrinsicContentSize. Na Androidzie — onMeasure z MeasureSpec. We Flutter rozmiar jest przekazywany do paint(Canvas, Size) lub obliczany przez computeDryLayout. Każda platforma używa własnej metody pomiaru.

Kiedy używać niestandardowych widoków zamiast standardowych komponentów?

Niestandardowe widoki są potrzebne do unikalnej grafiki, animacji, wykresów i elementów, których nie można zaimplementować za pomocą standardowego UIKit lub View. Do prostych stylów wystarczy skonfigurować standardowe komponenty — nie komplikuj architektury bez potrzeby.

Podsumowanie

  • Niestandardowe widoki — podstawa unikalnych interfejsów dla wykresów, animacji i niestandardowych elementów w aplikacjach mobilnych.
  • drawRect — metoda iOS do rysowania przez Core Graphics z CGContext i UIBezierPath.
  • onDraw — metoda Android do rysowania przez Canvas i Paint z obsługą Path i Shader.
  • CustomPainter — klasa Flutter do rysowania na Canvas z shouldRepaint i RepaintBoundary.
  • Pomiar — walidacja rozmiarów przez sizeThatFits (iOS), onMeasure (Android) i computeDryLayout (Flutter).
  • Rysowanie w rozwoju mobilnym na wszystkich platformach podlega jednolitemu wzorcowi: pobierz kontekst, skonfiguruj style i narysuj prymitywy.
  • Buforuj obiekty rysowania (Paint, Path) — nie twórz ich wewnątrz drawRect, onDraw lub paint dla stabilnej wydajności.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt