Custom UIView — زیرکلاسی از کامپوننت UIKit به نام UIView است که در آن توسعهدهنده متدهای چرخه حیات و ترسیم را برای ایجاد عناصر بصری منحصربهفرد بازنویسی میکند. UIViewهای استاندارد (UIButton، UILabel، UIImageView) بیشتر سناریوهای معمول را پوشش میدهند، اما زمانی که گرافیک، انیمیشن یا تعامل غیراستاندارد مورد نیاز است، بدون ایجاد UIView سفارشی نمیتوان کار را پیش برد. طبق Apple Documentation (2025)، UIViewهای سفارشی در 68% برنامههای App Store که راهحلهای غیراستاندارد رابط کاربری دارند استفاده میشوند. این رویکرد کنترل کامل بر ترسیم، پردازش لمس و چیدمان عناصر درون ویو میدهد.
نکات اصلی
Custom UIView — کلاسی سفارشی است که از UIView ارثبری میکند و در آن توسعهدهنده متدهای استاندارد را برای پیادهسازی منطق نمایش و تعامل خود بازنویسی میکند. UIKit شامل کامپوننتهای آماده بسیاری است، اما همه سناریوها را پوشش نمیدهد: نمودارهای متحرک، سوئیچهای غیراستاندارد، بوم نقاشی با انگشت، عناصر بازی یا تجسم دادهها نیاز به پیادهسازی سفارشی دارند.
Apple توصیه میکند زمانی که کامپوننتهای استاندارد نمیتوانند عملکرد مورد نیاز را ارائه دهند یا زمانی که همان عنصر غیراستاندارد در چندین جای برنامه استفاده میشود، Custom UIView ایجاد کنید. طبق WWDC 2024، ویوهای سفارشی به طور میانگین 15-20% از کل UIViewها را در یک پروژه متوسط تشکیل میدهند.
UIView سفارشی برای ساخت نمودارها و دیاگرامها (ترسیم خطوط و اشکال با Core Graphics)، نشانگرهای پیشرفت غیراستاندارد، پسزمینههای متحرک، عناصر نقاشی با انگشت و همچنین تجسم دادهها در زمان واقعی استفاده میشود. در هر یک از این موارد، توسعهدهنده دسترسی کامل به CGContext دارد و میتواند هر هندسهای را ترسیم کند.
اگر میتوان عنصر را از کامپوننتهای استاندارد UIKit (UIButton، UIImageView، UILabel) با استفاده از Auto Layout و تنظیم ویژگیها ساخت — ایجاد زیرکلاس UIView اضافی خواهد بود. Apple توصیه میکند ابتدا ترکیب ویوهای آماده را امتحان کنید و فقط در صورت ناکافی بودن عملکرد به ترسیم سفارشی روی آورید.
ایجاد UIView سفارشی با اعلام کلاسی که از UIView ارثبری میکند و پیادهسازی مقداردهندههای اجباری آغاز میشود. حداقل پیادهسازی شامل init(frame:) برای ایجاد از کد و init(coder:) برای بارگذاری از Storyboard یا XIB است.
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 برای پیشنمایش زنده ارزشمند است.
Custom UIView توسط سیستم از طریق دنبالهای از متدهای چرخه حیات که به ترتیب مشخصی فراخوانی میشوند مدیریت میگردد. درک این چرخه برای پیکربندی و ترسیم صحیح ویو حیاتی است.
| متد | زمان فراخوانی | هدف |
|---|---|---|
| init(frame:) | ایجاد ویو از کد | مقداردهی ویژگیها، افزودن زیرویوها |
| init(coder:) | بارگذاری از Storyboard/XIB | دسریالسازی و پیکربندی اولیه |
| layoutSubviews() | هنگام تغییر فریم | محاسبه مجدد هندسه عناصر زیرمجموعه |
| draw(_:) | در اولین نمایش یا پس از setNeedsDisplay() | ترسیم محتوا از طریق Core Graphics |
| didMoveToSuperview() | پس از افزودن به سلسلهمراتب | پیکربندی نهایی، شروع انیمیشنها |
همه متدها به طور خودکار توسط سیستم فراخوانی میشوند و توسعهدهنده نیازی به فراخوانی دستی آنها ندارد. استثنا — setNeedsDisplay() که به سیستم سیگنال نیاز به فراخوانی مجدد draw(_:) را میدهد.
draw(_:) — متد کلیدی برای ترسیم سفارشی در Custom UIView است. در داخل آن، توسعهدهنده به CGContext (زمینه گرافیکی) دسترسی پیدا میکند و میتواند خطوط، اشکال، متن و تصاویر را با استفاده از Core Graphics ترسیم کند.
سیستم draw(_:) را به طور خودکار در اولین نمایش ویو روی صفحه فراخوانی میکند. فراخوانی مجدد از طریق setNeedsDisplay() انجام میشود که ویو را نیازمند ترسیم مجدد علامتگذاری میکند. مهم: draw(_:) را مستقیماً فراخوانی نکنید — این کار مکانیزم حافظه نهان را خراب کرده و عملکرد را کاهش میدهد.
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 باشد — فراخوانی مکرر با پارامترهای مشابه باید نتیجه یکسانی بدهد.
Apple توصیه میکند کار درون draw(_:) را به حداقل برسانید — UIBezierPath را از قبل ایجاد کنید، تصاویر را حافظه نهان کنید و محاسبات سنگین انجام ندهید. اگر ویو ایستا است، به جای ترسیم مجدد مداوم، از UIImageView با تصویر رندر شده استفاده کنید.
CALayer — لایه زیرینی است که محتوای بصری UIView را مدیریت میکند. بسیاری از وظایف ترسیم سفارشی را میتوان از طریق تنظیم ویژگیهای CALayer بدون بازنویسی draw(_:) حل کرد که این کار بسیار کارآمدتر است.
طبق Apple Engineering (2024)، عملیات در سطح CALayer روی GPU انجام میشود، در حالی که draw(_:) از طریق رندرینگ CPU Core Graphics کار میکند. برای انیمیشنها و انتقالهای روان، استفاده از CALayer و CABasicAnimation ترجیح داده میشود.
| سناریو | رویکرد توصیهشده | عملکرد |
|---|---|---|
| گوشههای گرد | layer.cornerRadius | GPU، بالا |
| سایهها و گرادینتها | CAGradientLayer, shadowPath | GPU، بالا |
| اشکال دلخواه | CAShapeLayer با UIBezierPath | GPU، بالا |
| گرافیک پیچیده | draw(_:) با Core Graphics | CPU، متوسط |
| متن با قالببندی سفارشی | CATextLayer یا draw(_:) | بستگی به حجم دارد |
برای ترسیم اشکال برداری با انیمیشن از CAShapeLayer استفاده کنید — این لایه از نظر سختافزاری شتابدهی شده و از انیمیشن path، strokeStart و strokeEnd بدون فراخوانی draw(_:) پشتیبانی میکند.
عملکرد Custom UIView مستقیماً بر روانی انیمیشنها و تجربه کلی کاربر از برنامه تأثیر میگذارد. مشکلات اصلی به دلیل فراخوانیهای اضافی draw(_:)، چیدمان غیربهینه زیرویوها و فقدان حافظه نهان ایجاد میشود.
هر فراخوانی setNeedsDisplay() منجر به ترسیم مجدد کامل ویو میشود. اگر تغییرات فقط بخشی از ویو را تحت تأثیر قرار دادهاند، از setNeedsDisplay(_:) با مشخص کردن مستطیل خاص استفاده کنید. برای ویژگیهای CALayer (backgroundColor، cornerRadius، shadow) ترسیم مجدد لازم نیست — آنها در سطح GPU بهروزرسانی میشوند.
اگر محتوای Custom UIView به ندرت تغییر میکند، آن را یک بار در UIGraphicsImageRenderer رندر کرده و به عنوان UIImage ذخیره کنید. در ترسیم مجدد بعدی، از draw(at:) برای نمایش تصویر ذخیره شده استفاده کنید — این کار دهها برابر سریعتر از ترسیم مجدد از طریق Core Graphics است.
func renderToImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
return renderer.image { ctx in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
ویژگی shouldRasterize در CALayer ذخیرهسازی نمایش شطرنجی لایه را فعال میکند. آن را برای ویوهای ایستا با شفافیت و سایه روشن کنید — این کار بار compositing را کاهش میدهد. برای ویوهای متحرک آن را غیرفعال کنید: با هر تغییر حافظه نهان بازنشانی میشود و شطرنجیسازی فقط عملکرد را بدتر میکند.
سؤالات متداول
خیر، draw(_:) فقط هنگام ترسیم سفارشی از طریق Core Graphics لازم است. اگر ویو از زیرویوهای استاندارد (UILabel، UIImageView) تشکیل شده و از CALayer استفاده میکند، بازنویسی draw(_:) لازم نیست — این حتی عملکرد را بهبود میبخشد.
یک UIView معمولی روی بوم قرار دهید، در Identity Inspector کلاس خود را در فیلد Class مشخص کنید. اگر کلاس با @IBDesignable علامتگذاری شده باشد، تغییرات در زمان واقعی مستقیماً در Storyboard نمایش داده میشوند.
init(frame:) هنگام ایجاد برنامهنویسی ویو فراخوانی میشود — شما CGRect با موقعیت و اندازه ارسال میکنید. init(coder:) هنگام دسریالسازی از Storyboard یا XIB فراخوانی میشود. برای عملکرد صحیح، هر دو باید پیادهسازی شوند، در غیر این صورت ویو هنگام بارگذاری از Interface Builder خراب میشود.
شایعترین علت — ویو دارای فریم صفر است (عرض یا ارتفاع برابر صفر). سیستم برای ویوهای با اندازه صفر draw(_:) را فراخوانی نمیکند. فریم را در layoutSubviews() بررسی کنید و مطمئن شوید ویو با محدودیتهای صحیح به سلسلهمراتب اضافه شده است.
برای ویژگیهایی که انیمیشن روی GPU را پشتیبانی میکنند (position، opacity، transform) از CALayer استفاده کنید. برای بهروزرسانی جزئی draw(_:) از setNeedsDisplay(_:) با CGRect ناحیه تغییر استفاده کنید — سیستم فقط ناحیه مشخصشده را دوباره ترسیم میکند، نه کل ویو را.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید