نمایش‌های سفارشی و ترسیم در توسعه موبایل: ماهیت، چه APIهایی و نحوه کار

نویسنده: IT Sectr منتشر شده: 2026-08-01 زمان مطالعه: 11 دقیقه

نمایش‌های سفارشی اساس رابط کاربری منحصربه‌فرد هر برنامه موبایل هستند. نمایش‌های سفارشی در برنامه‌های موبایل به شما امکان می‌دهند گرافیک، انیمیشن و عناصر خاص خود را که در کامپوننت‌های استاندارد در دسترس نیستند ایجاد کنید. به گزارش Apple Developer، 2025، drawRect روش اصلی ترسیم سفارشی در توسعه موبایل iOS باقی مانده است. در Android، onDraw با Canvas همان نقش را ایفا می‌کند، و در Flutter — CustomPainter.

نکات اصلی

  • نمایش‌های سفارشی — کامپوننت‌های تعریف‌شده توسط کاربر با منطق ترسیم، اندازه و رفتار خاص خود در برنامه‌های موبایل.
  • drawRect — متد UIView در iOS برای ترسیم سفارشی از طریق Core Graphics و CGContext.
  • onDraw — متد View در Android برای ترسیم از طریق Canvas و Paint با سیستم اندازه‌گیری onMeasure.
  • CustomPainter — کلاس Flutter برای ترسیم روی Canvas با متدهای paint و shouldRepaint.
  • اندازه‌گیری — فرآیند تعیین ابعاد نمایش از طریق sizeThatFits در iOS، onMeasure در Android و computeDryLayout در Flutter.

نمایش‌های سفارشی چیست و چرا در برنامه‌های موبایل به آنها نیاز داریم

نمایش‌های سفارشی کامپوننت‌های رابط کاربری تعریف‌شده توسط کاربر هستند که متدهای استاندارد ترسیم و اندازه‌گیری را برای ایجاد گرافیک منحصربه‌فرد بازنویسی می‌کنند. نمودارها، انیمیشن‌ها، دیاگرام‌ها، عناصر چت سفارشی و ماسک‌های AR — اینها سناریوهای معمول استفاده از نمایش‌های سفارشی در برنامه‌های موبایل هستند. کامپوننت‌های استاندارد UI (Button، TextView، Label) 80٪ وظایف را پوشش می‌دهند، اما 20٪ باقی‌مانده نیاز به کنترل کامل بر ترسیم در توسعه موبایل دارند. ترسیم در توسعه موبایل مهارتی است که یک توسعه‌دهنده junior را از senior متمایز می‌کند.

چه زمانی نمایش‌های سفارشی موجه هستند

نمایش‌های سفارشی در برنامه‌های موبایل برای گرافیک 2D منحصربه‌فرد، انیمیشن‌های پیچیده، نمودارها و تجسم داده‌ها مورد نیاز هستند. اگر UIKit استاندارد عنصر مورد نیاز را ارائه نمی‌دهد — یک نمایش سفارشی ایجاد می‌شود. در برنامه‌های موبایل، نمایش‌های سفارشی برای نوارهای پیشرفت، دکمه‌های سفارشی، پرکردن‌های گرادیان، آیکون‌های متحرک و بوم‌های نقاشی با انگشت استفاده می‌شوند. مهم است که زیاده‌روی نکنید — برای سبک‌های ساده، پیکربندی کامپوننت‌های استاندارد از طریق API ظاهر کافی است.

نمایش‌های سفارشی در iOS: drawRect و Core Graphics

در iOS، نمایش‌های سفارشی با ارث‌بری از UIView و بازنویسی متد drawRect ایجاد می‌شوند. drawRect در اولین رندر و پس از هر فراخوانی setNeedsDisplay() فراخوانی می‌شود. درون drawRect، توسعه‌دهنده یک CGContext از طریق UIGraphicsGetCurrentContext() دریافت می‌کند — بوم‌نقاشی برای خطوط، اشکال، گرادیان‌ها و متن. Core Graphics (Quartz 2D) یک موتور رندر سطح پایین مبتنی بر CPU است که کنترل کامل بر هر پیکسل را می‌دهد. UIBezierPath یک لفافه‌بند مناسب برای ایجاد مسیرها با نحو مختصر است.

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 و تبدیل‌ها

Core Graphics CGContext را فراهم می‌کند — بوم‌نقاشی برای تمام عملیات ترسیم. CGGradient گرادیان‌های خطی و شعاعی ایجاد می‌کند با پشتیبانی از CGColorSpace (sRGB، Display P3). تبدیل‌ها از طریق CGAffineTransform انجام می‌شوند — ماتریس 3x3 برای چرخش، مقیاس‌گذاری و جابجایی. CGContextTranslateCTM، CGContextRotateCTM و CGContextScaleCTM سیستم مختصات را تغییر می‌دهند. Core Graphics روی CPU کار می‌کند، بنابراین گرافیک پیچیده می‌تواند پردازنده را بارگذاری کند — برای شتاب GPU از Metal استفاده کنید.

UIBezierPath برای ایجاد اشکال

UIBezierPath یک لفافه‌بند شی‌گرا روی CGPath است. متد addArc(withCenter:radius:startAngle:endAngle:clockwise:) کمان‌ها و دایره‌ها ایجاد می‌کند، addCurve منحنی‌های Bézier ایجاد می‌کند. مسیرها از عملیات اتحاد، اشتراک و تفریق از طریق addClip پشتیبانی می‌کنند. UIBezierPath برای ماسک‌های سفارشی (maskView)، مسیرهای برش و اشکال پیچیده — ستاره‌ها، قلب‌ها، آیکون‌های سفارشی مناسب است.

نمایش‌های سفارشی در Android: onDraw و Canvas

در Android، یک نمایش سفارشی View را با بازنویسی onDraw(Canvas) گسترش می‌دهد. Canvas شامل تمام متدهای ترسیم در توسعه موبایل است: drawCircle، drawRect، drawLine، drawText، drawBitmap، drawPath و drawRoundRect. Paint پارامترها را پیکربندی می‌کند — رنگ، ضخامت خط، سبک (FILL، STROKE، FILL_AND_STROKE)، صاف‌سازی (isAntiAlias) و اندازه متن. onDraw هر بار در invalidate() فراخوانی می‌شود و نباید حاوی عملیات سنگین باشد — تمام محاسبات کش می‌شوند.

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 و انیمیشن‌ها در Android

Path در Android معادل UIBezierPath است: addCircle، addRect، addOval، lineTo، cubicTo و quadTo. PathMeasure طول مسیر و مختصات را در هر نقطه محاسبه می‌کند — برای متحرک‌سازی حرکت یک جسم در طول مسیر مفید است. برای انیمیشن‌ها، از ValueAnimator با invalidate() در فراخوان استفاده می‌شود. انیماتور می‌تواند رنگ، شعاع، موقعیت را تغییر دهد — هر ویژگی که بر ترسیم تأثیر می‌گذارد. نمایش‌های سفارشی در Android همچنین از StateListDrawable و animated-vector برای انیمیشن از طریق XML پشتیبانی می‌کنند.

Shader و گرادیان‌ها در Canvas

گرادیان‌ها در Android از طریق Shader تنظیم می‌شوند — LinearGradient، RadialGradient و SweepGradient. Shader از طریق paint.setShader(shader) به Paint اختصاص داده می‌شود. LinearGradient یک گرادیان خطی بین دو نقطه با موقعیت‌های رنگی اختیاری ایجاد می‌کند. RadialGradient — شعاعی از مرکز به لبه‌ها. SweepGradient — مخروطی حول یک نقطه مرکزی. Shader.TileMode (CLAMP، REPEAT، MIRROR) رفتار فراتر از مرزهای منطقه را تعریف می‌کند.

CustomPainter در Flutter: ترسیم روی Canvas

Flutter از CustomPainter استفاده می‌کند — کلاسی با متدهای paint(Canvas canvas, Size size) و shouldRepaint. Canvas در Flutter همان متدها را ارائه می‌دهد که در Android وجود دارد: drawCircle، drawRect، drawLine، drawPath، drawParagraph و drawImage. Paint در Flutter رنگ، ضخامت، سبک و صاف‌سازی را پیکربندی می‌کند. Flutter از drawRect یا onDraw استفاده نمی‌کند — تمام ترسیم از طریق CustomPainter انجام می‌شود که در ویجت 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 و RepaintBoundary

shouldRepaint تعیین می‌کند که آیا CustomPainter نیاز به ترسیم مجدد دارد یا خیر. فقط زمانی true برگردانید که داده‌های مؤثر بر رندر تغییر کنند — رنگ، اندازه، داده‌های نمودار. RepaintBoundary ترسیم مجدد را در یک لایه جداگانه ایزوله می‌کند — برای ویجت‌هایی که به ندرت تغییر می‌کنند استفاده کنید. Flutter setNeedsDisplay یا invalidate ندارد — ترسیم مجدد از طریق setState یا ValueNotifier با گوش دادن به تغییرات فعال می‌شود.

گرادیان‌ها و تبدیل‌ها در Flutter

Flutter از LinearGradient، RadialGradient و SweepGradient پشتیبانی می‌کند — همان انواعی که در Android وجود دارد. Gradient از طریق createShader(Rect bounds) یک Shader برای Paint ایجاد می‌کند. تبدیل‌ها از طریق canvas.rotate، canvas.scale، canvas.translate و canvas.skew انجام می‌شوند. Flutter از ماتریس تبدیل 4x4 (Matrix4) برای ویجت Transform استفاده می‌کند. انیمیشن‌های ترسیم در Flutter با AnimationController همراه با setState برای ترسیم مجدد CustomPainter ساخته می‌شوند.

اندازه‌گیری نمایش‌های سفارشی: متدهای sizeThatFits، onMeasure و computeDryLayout

اندازه‌گیری صحیح نمایش‌های سفارشی اساس رفتار قابل پیش‌بینی رابط کاربری است. در iOS، اندازه نمایش از طریق sizeThatFits و intrinsicContentSize تعیین می‌شود. sizeThatFits اندازه بهینه را برای محدودیت‌های داده شده برمی‌گرداند. intrinsicContentSize — اندازه طبیعی محتوا بدون محدودیت‌های خارجی. در Android، اندازه‌گیری در onMeasure با پارامترهای MeasureSpec (UNSPECIFIED، EXACTLY، AT_MOST) پیاده‌سازی می‌شود. در Flutter، اندازه به paint(Canvas, Size) منتقل می‌شود و می‌تواند از طریق computeDryLayout یا LayoutBuilder محاسبه شود.

sizeThatFits و intrinsicContentSize در iOS

intrinsicContentSize یک CGSize برمی‌گرداند — اندازه طبیعی نمایش بر اساس محتوای آن. setContentHuggingPriority و setContentCompressionResistancePriority رفتار را در هنگام کشش و فشردگی کنترل می‌کنند. sizeThatFits توسط سیستم برای محاسبه اندازه در Auto Layout فراخوانی می‌شود. برای نمایش‌های سفارشی، اگر کامپوننت شما اندازه طبیعی دارد intrinsicContentSize را بازنویسی کنید — به عنوان مثال، یک دایره همیشه باید 100x100 باشد.

onMeasure و MeasureSpec در Android

onMeasure widthMeasureSpec و heightMeasureSpec را می‌پذیرد. MeasureSpec شامل حالت و اندازه است: UNSPECIFIED (بدون محدودیت، نمایش اندازه خود را انتخاب می‌کند)، EXACTLY (اندازه دقیق از والد)، AT_MOST (حداکثر اندازه). setMeasuredDimension(width, height) نتیجه اندازه‌گیری را ذخیره می‌کند. هنگام تغییر داده‌ها، برای اندازه‌گیری مجدد requestLayout() را فراخوانی کنید. ViewGroup‌های تو در تو نیاز به بازنویسی onLayout برای چیدمان عناصر فرزند دارند.

پلتفرمروش اندازه‌گیریفراخوانی هنگام تغییربازگشت
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (اندازه را ذخیره می‌کند)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout در Flutter

computeDryLayout یک متد RenderObject برای محاسبه اندازه بدون چرخه چیدمان کامل است. LayoutBuilder.getSize — جایگزینی برای دریافت فضای موجود در متد build. در Flutter، اندازه بوم به عنوان Size به paint منتقل می‌شود و نیاز به اندازه‌گیری جداگانه ندارد — CustomPainter درون مرزهای منتقل شده ترسیم می‌کند. با این حال، برای RenderObject‌های سفارشی، باید performLayout و computeDryLayout را بازنویسی کنید.

سوالات متداول

drawRect در iOS چیست و چه زمانی فراخوانی می‌شود؟

drawRect یک متد UIView برای ترسیم سفارشی از طریق Core Graphics است. در اولین رندر نمایش و پس از هر فراخوانی setNeedsDisplay() فراخوانی می‌شود. برای خطوط، اشکال و متن از CGContext درون drawRect استفاده کنید.

چگونه با Canvas در Android ترسیم کنیم؟

کلاسی ایجاد کنید که View را گسترش می‌دهد، onDraw(Canvas canvas) را بازنویسی کنید و از Canvas API استفاده کنید: drawCircle، drawRect، drawPath. Paint رنگ، ضخامت و سبک را پیکربندی می‌کند. برای به‌روزرسانی، invalidate() را فراخوانی کنید.

CustomPainter در Flutter چیست؟

CustomPainter یک کلاس Flutter برای ترسیم سفارشی روی Canvas است. متدهای paint(Canvas, Size) و shouldRepaint را پیاده‌سازی کنید. از طریق ویجت CustomPaint قرار می‌گیرد. Flutter drawRect ندارد — تمام ترسیم از طریق CustomPainter انجام می‌شود.

چگونه اندازه یک نمایش سفارشی را اندازه‌گیری کنیم؟

در iOS از sizeThatFits و intrinsicContentSize استفاده کنید. در Android — onMeasure با MeasureSpec. در Flutter، اندازه به paint(Canvas, Size) منتقل می‌شود یا از طریق computeDryLayout محاسبه می‌شود. هر پلتفرم از روش اندازه‌گیری خود استفاده می‌کند.

چه زمانی به جای کامپوننت‌های استاندارد از نمایش‌های سفارشی استفاده کنیم؟

نمایش‌های سفارشی برای گرافیک منحصربه‌فرد، انیمیشن‌ها، نمودارها و عناصری که با UIKit یا View استاندارد قابل پیاده‌سازی نیستند مورد نیاز هستند. برای سبک‌های ساده، پیکربندی کامپوننت‌های استاندارد کافی است — معماری را بی‌دلیل پیچیده نکنید.

خلاصه

  • نمایش‌های سفارشی — اساس رابط‌های منحصربه‌فرد برای نمودارها، انیمیشن‌ها و عناصر غیراستاندارد در برنامه‌های موبایل.
  • drawRect — متد iOS برای ترسیم از طریق Core Graphics با CGContext و UIBezierPath.
  • onDraw — متد Android برای ترسیم از طریق Canvas و Paint با پشتیبانی Path و Shader.
  • CustomPainter — کلاس Flutter برای ترسیم روی Canvas با shouldRepaint و RepaintBoundary.
  • اندازه‌گیری — اعتبارسنجی اندازه‌ها از طریق sizeThatFits (iOS)، onMeasure (Android) و computeDryLayout (Flutter).
  • ترسیم در توسعه موبایل در همه پلتفرم‌ها از یک الگوی واحد پیروی می‌کند: دریافت زمینه، پیکربندی سبک‌ها و ترسیم اولیه‌ها.
  • اشیاء ترسیم (Paint, Path) را کش کنید — برای عملکرد پایدار آنها را درون drawRect، onDraw یا paint ایجاد نکنید.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه