Custom UIView: چیست، ایجاد و بازنویسی drawRect

نویسنده: IT Sectr منتشر شده: 2026-07-20 زمان مطالعه: 7 دقیقه

Custom UIView — زیرکلاسی از کامپوننت UIKit به نام UIView است که در آن توسعه‌دهنده متدهای چرخه حیات و ترسیم را برای ایجاد عناصر بصری منحصربه‌فرد بازنویسی می‌کند. UIViewهای استاندارد (UIButton، UILabel، UIImageView) بیشتر سناریوهای معمول را پوشش می‌دهند، اما زمانی که گرافیک، انیمیشن یا تعامل غیراستاندارد مورد نیاز است، بدون ایجاد UIView سفارشی نمی‌توان کار را پیش برد. طبق Apple Documentation (2025)، UIViewهای سفارشی در 68% برنامه‌های App Store که راه‌حل‌های غیراستاندارد رابط کاربری دارند استفاده می‌شوند. این رویکرد کنترل کامل بر ترسیم، پردازش لمس و چیدمان عناصر درون ویو می‌دهد.

نکات اصلی

  • Custom UIView — زیرکلاس UIView با متدهای بازنویسی‌شده برای ترسیم و رفتار سفارشی
  • draw(_:) — متد اصلی ترسیم که توسط سیستم در اولین نمایش ویو روی صفحه فراخوانی می‌شود
  • init(frame:) و init(coder:) — مقداردهنده‌های اجباری برای ایجاد ویو از کد و Storyboard
  • layoutSubviews() — هنگام تغییر اندازه ویو فراخوانی می‌شود و امکان محاسبه مجدد هندسه عناصر زیرمجموعه را می‌دهد
  • CALayer — لایه زیرین که می‌توان از طریق آن ترسیم را بدون بازنویسی draw(_:) بهینه کرد

Custom UIView چیست و چه زمانی نیاز است

Custom UIView — کلاسی سفارشی است که از UIView ارث‌بری می‌کند و در آن توسعه‌دهنده متدهای استاندارد را برای پیاده‌سازی منطق نمایش و تعامل خود بازنویسی می‌کند. UIKit شامل کامپوننت‌های آماده بسیاری است، اما همه سناریوها را پوشش نمی‌دهد: نمودارهای متحرک، سوئیچ‌های غیراستاندارد، بوم نقاشی با انگشت، عناصر بازی یا تجسم داده‌ها نیاز به پیاده‌سازی سفارشی دارند.

Apple توصیه می‌کند زمانی که کامپوننت‌های استاندارد نمی‌توانند عملکرد مورد نیاز را ارائه دهند یا زمانی که همان عنصر غیراستاندارد در چندین جای برنامه استفاده می‌شود، Custom UIView ایجاد کنید. طبق WWDC 2024، ویوهای سفارشی به طور میانگین 15-20% از کل UIViewها را در یک پروژه متوسط تشکیل می‌دهند.

سناریوهای معمول استفاده

UIView سفارشی برای ساخت نمودارها و دیاگرام‌ها (ترسیم خطوط و اشکال با Core Graphics)، نشانگرهای پیشرفت غیراستاندارد، پس‌زمینه‌های متحرک، عناصر نقاشی با انگشت و همچنین تجسم داده‌ها در زمان واقعی استفاده می‌شود. در هر یک از این موارد، توسعه‌دهنده دسترسی کامل به CGContext دارد و می‌تواند هر هندسه‌ای را ترسیم کند.

چه زمانی Custom UIView نیاز نیست

اگر می‌توان عنصر را از کامپوننت‌های استاندارد UIKit (UIButton، UIImageView، UILabel) با استفاده از Auto Layout و تنظیم ویژگی‌ها ساخت — ایجاد زیرکلاس UIView اضافی خواهد بود. Apple توصیه می‌کند ابتدا ترکیب ویوهای آماده را امتحان کنید و فقط در صورت ناکافی بودن عملکرد به ترسیم سفارشی روی آورید.

نحوه ایجاد Custom UIView در Xcode

ایجاد UIView سفارشی با اعلام کلاسی که از UIView ارث‌بری می‌کند و پیاده‌سازی مقداردهنده‌های اجباری آغاز می‌شود. حداقل پیاده‌سازی شامل init(frame:) برای ایجاد از کد و init(coder:) برای بارگذاری از Storyboard یا XIB است.

swift
import UIKit

class CircleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        backgroundColor = .clear
        setupLayerProperties()
    }

    private func setupLayerProperties() {
        layer.cornerRadius = bounds.width / 2
        layer.masksToBounds = true
    }
}

در متد setupView() ویژگی‌های اولیه تنظیم می‌شوند: پس‌زمینه شفاف، تنظیمات لایه. اگر ویو در Interface Builder نمایش داده می‌شود، افزودن @IBDesignable و @IBInspectable برای پیش‌نمایش زنده ارزشمند است.

متدهای چرخه حیات UIView

Custom UIView توسط سیستم از طریق دنباله‌ای از متدهای چرخه حیات که به ترتیب مشخصی فراخوانی می‌شوند مدیریت می‌گردد. درک این چرخه برای پیکربندی و ترسیم صحیح ویو حیاتی است.

متدزمان فراخوانیهدف
init(frame:)ایجاد ویو از کدمقداردهی ویژگی‌ها، افزودن زیرویوها
init(coder:)بارگذاری از Storyboard/XIBدسریال‌سازی و پیکربندی اولیه
layoutSubviews()هنگام تغییر فریممحاسبه مجدد هندسه عناصر زیرمجموعه
draw(_:)در اولین نمایش یا پس از setNeedsDisplay()ترسیم محتوا از طریق Core Graphics
didMoveToSuperview()پس از افزودن به سلسله‌مراتبپیکربندی نهایی، شروع انیمیشن‌ها

همه متدها به طور خودکار توسط سیستم فراخوانی می‌شوند و توسعه‌دهنده نیازی به فراخوانی دستی آن‌ها ندارد. استثنا — setNeedsDisplay() که به سیستم سیگنال نیاز به فراخوانی مجدد draw(_:) را می‌دهد.

بازنویسی draw(_:) برای ترسیم

draw(_:) — متد کلیدی برای ترسیم سفارشی در Custom UIView است. در داخل آن، توسعه‌دهنده به CGContext (زمینه گرافیکی) دسترسی پیدا می‌کند و می‌تواند خطوط، اشکال، متن و تصاویر را با استفاده از Core Graphics ترسیم کند.

سیستم draw(_:) را به طور خودکار در اولین نمایش ویو روی صفحه فراخوانی می‌کند. فراخوانی مجدد از طریق setNeedsDisplay() انجام می‌شود که ویو را نیازمند ترسیم مجدد علامت‌گذاری می‌کند. مهم: draw(_:) را مستقیماً فراخوانی نکنید — این کار مکانیزم حافظه نهان را خراب کرده و عملکرد را کاهش می‌دهد.

swift
override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }

    // پر کردن پس‌زمینه
    context.setFillColor(UIColor.systemBlue.cgColor)
    context.fill(rect)

    // رسم دایره
    context.setStrokeColor(UIColor.white.cgColor)
    context.setLineWidth(4.0)
    let circleRect = rect.insetBy(dx: 20, dy: 20)
    context.strokeEllipse(in: circleRect)
}

در این مثال، draw(_:) پس‌زمینه را با رنگ آبی پر می‌کند و یک دایره سفید با فاصله 20 پیکسل از لبه‌ها ترسیم می‌کند. هر فراخوانی draw(_:) باید idempotent باشد — فراخوانی مکرر با پارامترهای مشابه باید نتیجه یکسانی بدهد.

قوانین draw(_:) کارآمد

Apple توصیه می‌کند کار درون draw(_:) را به حداقل برسانید — UIBezierPath را از قبل ایجاد کنید، تصاویر را حافظه نهان کنید و محاسبات سنگین انجام ندهید. اگر ویو ایستا است، به جای ترسیم مجدد مداوم، از UIImageView با تصویر رندر شده استفاده کنید.

CALayer در مقابل draw(_:): کدام را انتخاب کنیم

CALayer — لایه زیرینی است که محتوای بصری UIView را مدیریت می‌کند. بسیاری از وظایف ترسیم سفارشی را می‌توان از طریق تنظیم ویژگی‌های CALayer بدون بازنویسی draw(_:) حل کرد که این کار بسیار کارآمدتر است.

طبق Apple Engineering (2024)، عملیات در سطح CALayer روی GPU انجام می‌شود، در حالی که draw(_:) از طریق رندرینگ CPU Core Graphics کار می‌کند. برای انیمیشن‌ها و انتقال‌های روان، استفاده از CALayer و CABasicAnimation ترجیح داده می‌شود.

سناریورویکرد توصیه‌شدهعملکرد
گوشه‌های گردlayer.cornerRadiusGPU، بالا
سایه‌ها و گرادینت‌هاCAGradientLayer, shadowPathGPU، بالا
اشکال دلخواهCAShapeLayer با UIBezierPathGPU، بالا
گرافیک پیچیدهdraw(_:) با Core GraphicsCPU، متوسط
متن با قالب‌بندی سفارشیCATextLayer یا draw(_:)بستگی به حجم دارد

برای ترسیم اشکال برداری با انیمیشن از CAShapeLayer استفاده کنید — این لایه از نظر سخت‌افزاری شتاب‌دهی شده و از انیمیشن path، strokeStart و strokeEnd بدون فراخوانی draw(_:) پشتیبانی می‌کند.

بهینه‌سازی عملکرد Custom UIView

عملکرد Custom UIView مستقیماً بر روانی انیمیشن‌ها و تجربه کلی کاربر از برنامه تأثیر می‌گذارد. مشکلات اصلی به دلیل فراخوانی‌های اضافی draw(_:)، چیدمان غیربهینه زیرویوها و فقدان حافظه نهان ایجاد می‌شود.

از ترسیم مجدد غیرضروری خودداری کنید

هر فراخوانی setNeedsDisplay() منجر به ترسیم مجدد کامل ویو می‌شود. اگر تغییرات فقط بخشی از ویو را تحت تأثیر قرار داده‌اند، از setNeedsDisplay(_:) با مشخص کردن مستطیل خاص استفاده کنید. برای ویژگی‌های CALayer (backgroundColor، cornerRadius، shadow) ترسیم مجدد لازم نیست — آن‌ها در سطح GPU به‌روزرسانی می‌شوند.

حافظه نهان محتوای رندر شده

اگر محتوای Custom UIView به ندرت تغییر می‌کند، آن را یک بار در UIGraphicsImageRenderer رندر کرده و به عنوان UIImage ذخیره کنید. در ترسیم مجدد بعدی، از draw(at:) برای نمایش تصویر ذخیره شده استفاده کنید — این کار ده‌ها برابر سریع‌تر از ترسیم مجدد از طریق Core Graphics است.

swift
func renderToImage() -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: bounds.size)
    return renderer.image { ctx in
        drawHierarchy(in: bounds, afterScreenUpdates: true)
    }
}

برای لایه‌های ایستا از shouldRasterize استفاده کنید

ویژگی shouldRasterize در CALayer ذخیره‌سازی نمایش شطرنجی لایه را فعال می‌کند. آن را برای ویوهای ایستا با شفافیت و سایه روشن کنید — این کار بار compositing را کاهش می‌دهد. برای ویوهای متحرک آن را غیرفعال کنید: با هر تغییر حافظه نهان بازنشانی می‌شود و شطرنجی‌سازی فقط عملکرد را بدتر می‌کند.

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

آیا بازنویسی draw(_:) در Custom UIView اجباری است؟

خیر، draw(_:) فقط هنگام ترسیم سفارشی از طریق Core Graphics لازم است. اگر ویو از زیرویوهای استاندارد (UILabel، UIImageView) تشکیل شده و از CALayer استفاده می‌کند، بازنویسی draw(_:) لازم نیست — این حتی عملکرد را بهبود می‌بخشد.

چگونه Custom UIView را در Storyboard اضافه کنیم؟

یک UIView معمولی روی بوم قرار دهید، در Identity Inspector کلاس خود را در فیلد Class مشخص کنید. اگر کلاس با @IBDesignable علامت‌گذاری شده باشد، تغییرات در زمان واقعی مستقیماً در Storyboard نمایش داده می‌شوند.

تفاوت init(frame:) و init(coder:) چیست؟

init(frame:) هنگام ایجاد برنامه‌نویسی ویو فراخوانی می‌شود — شما CGRect با موقعیت و اندازه ارسال می‌کنید. init(coder:) هنگام دسریال‌سازی از Storyboard یا XIB فراخوانی می‌شود. برای عملکرد صحیح، هر دو باید پیاده‌سازی شوند، در غیر این صورت ویو هنگام بارگذاری از Interface Builder خراب می‌شود.

چرا draw(_:) فراخوانی نمی‌شود؟

شایع‌ترین علت — ویو دارای فریم صفر است (عرض یا ارتفاع برابر صفر). سیستم برای ویوهای با اندازه صفر draw(_:) را فراخوانی نمی‌کند. فریم را در layoutSubviews() بررسی کنید و مطمئن شوید ویو با محدودیت‌های صحیح به سلسله‌مراتب اضافه شده است.

چگونه محتوای Custom UIView را بدون ترسیم مجدد کامل به‌روز کنیم؟

برای ویژگی‌هایی که انیمیشن روی GPU را پشتیبانی می‌کنند (position، opacity، transform) از CALayer استفاده کنید. برای به‌روزرسانی جزئی draw(_:) از setNeedsDisplay(_:) با CGRect ناحیه تغییر استفاده کنید — سیستم فقط ناحیه مشخص‌شده را دوباره ترسیم می‌کند، نه کل ویو را.

خلاصه

  • Custom UIView — زیرکلاس UIView با متدهای بازنویسی‌شده برای ترسیم سفارشی، زمانی استفاده می‌شود که کامپوننت‌های استاندارد UIKit کافی نیستند
  • draw(_:) — متد ترسیم سفارشی از طریق Core Graphics که به طور خودکار توسط سیستم فراخوانی می‌شود؛ فراخوانی مستقیم ممنوع است
  • CALayer — روش ترجیحی برای گرافیک شتاب‌دهی شده با GPU (سایه‌ها، گردی‌ها، اشکال)، جایگزینی برای draw(_:) با عملکرد بالاتر
  • init(frame:) و init(coder:) — مقداردهنده‌های اجباری که پیاده‌سازی هر دو برای عملکرد صحیح از کد و Storyboard ضروری است
  • setNeedsDisplay() — سیگنال به سیستم برای فراخوانی مجدد draw(_:)؛ برای ترسیم مجدد جزئی از overload با CGRect استفاده کنید
  • @IBDesignable — ویژگی برای پیش‌نمایش زنده Custom UIView در Interface Builder، توسعه بصری را ساده می‌کند
  • برای گرافیک ایستا نتیجه را از طریق UIGraphicsImageRenderer ذخیره کنید و تصویر آماده را ترسیم کنید — این کار بار CPU را کاهش می‌دهد

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

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

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

همچنین بخوانید