Ang mga custom na View ay ang pundasyon ng natatanging interface ng anumang mobile app. Ang mga custom na View sa mga mobile app ay nagbibigay-daan sa iyo na lumikha ng iyong sariling graphics, animation, at mga elementong hindi available sa mga karaniwang bahagi. Ayon sa Apple Developer, 2025, ang drawRect ay nananatiling pangunahing pamamaraan ng custom na pagguhit sa mobile development sa iOS. Sa Android, ang onDraw na may Canvas ay gumaganap ng parehong papel, at sa Flutter — CustomPainter.
Mga Pangunahing Punto
Ang mga custom na View ay mga bahagi ng interface na tinukoy ng gumagamit na nag-o-override sa mga karaniwang pamamaraan ng pagguhit at pagsukat upang lumikha ng natatanging graphics. Mga graph, animation, diagram, custom na elemento ng chat, at AR mask — ito ay mga tipikal na sitwasyon ng paggamit ng mga custom na View sa mga mobile app. Ang mga karaniwang bahagi ng UI (Button, TextView, Label) ay sumasaklaw sa 80% ng mga gawain, ngunit ang natitirang 20% ay nangangailangan ng buong kontrol sa pagguhit sa mobile development. Ang pagguhit sa mobile development ay isang kasanayang naghihiwalay sa junior developer mula sa senior.
Ang mga custom na View sa mga mobile app ay kinakailangan para sa natatanging 2D graphics, kumplikadong animation, chart, at visualization ng data. Kung ang karaniwang UIKit ay hindi nagbibigay ng kinakailangang elemento — isang custom na View ang nilikha. Sa mga mobile app, ang mga custom na View ay ginagamit para sa mga progress bar, custom na button, gradient fill, animated na icon, at canvas para sa pagguhit gamit ang daliri. Mahalagang huwag abusuhin — para sa mga simpleng istilo, sapat na ang pag-configure ng mga karaniwang bahagi sa pamamagitan ng Appearance API.
Sa iOS, ang mga custom na View ay nilikha sa pamamagitan ng pagmamana mula sa UIView at pag-override sa pamamaraang drawRect. Ang drawRect ay tinatawag sa unang render at pagkatapos ng bawat tawag sa setNeedsDisplay(). Sa loob ng drawRect, ang developer ay makakakuha ng CGContext sa pamamagitan ng UIGraphicsGetCurrentContext() — isang canvas para sa mga linya, hugis, gradient, at teksto. Ang Core Graphics (Quartz 2D) ay isang mababang antas na CPU-based na rendering engine na nagbibigay ng buong kontrol sa bawat pixel. Ang UIBezierPath ay isang maginhawang wrapper para sa paglikha ng mga path na may maigsi na syntax.
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()
}
}
Ang Core Graphics ay nagbibigay ng CGContext — isang canvas para sa lahat ng operasyon ng pagguhit. Ang CGGradient ay lumilikha ng linear at radial gradient na may suporta para sa CGColorSpace (sRGB, Display P3). Ang mga pagbabago ay isinasagawa sa pamamagitan ng CGAffineTransform — isang 3x3 matrix para sa pag-ikot, pag-scale, at pagsasalin. Ang CGContextTranslateCTM, CGContextRotateCTM, at CGContextScaleCTM ay nagbabago sa coordinate system. Ang Core Graphics ay tumatakbo sa CPU, kaya ang kumplikadong graphics ay maaaring mag-load sa processor — gamitin ang Metal para sa GPU acceleration.
Ang UIBezierPath ay isang object-oriented na wrapper sa ibabaw ng CGPath. Ang pamamaraang addArc(withCenter:radius:startAngle:endAngle:clockwise:) ay lumilikha ng mga arko at bilog, ang addCurve ay lumilikha ng mga Bézier curve. Ang mga path ay sumusuporta sa mga operasyon ng union, intersection, at subtraction sa pamamagitan ng addClip. Ang UIBezierPath ay maginhawa para sa custom na mask (maskView), clipping path, at kumplikadong hugis — mga bituin, puso, custom na icon.
Sa Android, ang isang custom na View ay nagpapalawak ng View na may naka-override na onDraw(Canvas). Ang Canvas ay naglalaman ng lahat ng pamamaraan ng pagguhit sa mobile development: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath, at drawRoundRect. Ang Paint ay nag-configure ng mga parameter — kulay, kapal ng linya, estilo (FILL, STROKE, FILL_AND_STROKE), anti-aliasing (isAntiAlias), at laki ng teksto. Ang onDraw ay tinatawag sa bawat invalidate() at hindi dapat maglaman ng mabibigat na operasyon — lahat ng kalkulasyon ay naka-cache.
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)
}
}
Ang Path sa Android ay katumbas ng UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo, at quadTo. Ang PathMeasure ay kinakalkula ang haba ng path at mga coordinate sa anumang punto — kapaki-pakinabang para sa pag-animate ng paggalaw ng isang bagay sa kahabaan ng isang path. Para sa mga animation, ginagamit ang ValueAnimator na may invalidate() sa callback. Ang animator ay maaaring magbago ng kulay, radius, posisyon — anumang pag-aari na nakakaapekto sa pagguhit. Ang mga custom na View sa Android ay sumusuporta rin sa StateListDrawable at animated-vector para sa animation sa pamamagitan ng XML.
Ang mga gradient sa Android ay itinakda sa pamamagitan ng Shader — LinearGradient, RadialGradient, at SweepGradient. Ang Shader ay itinalaga sa Paint sa pamamagitan ng paint.setShader(shader). Ang LinearGradient ay bumubuo ng linear gradient sa pagitan ng dalawang punto na may opsyonal na mga posisyon ng kulay. RadialGradient — radial mula sa gitna hanggang sa mga gilid. SweepGradient — conical sa paligid ng isang gitnang punto. Ang Shader.TileMode (CLAMP, REPEAT, MIRROR) ay tumutukoy sa pag-uugali sa labas ng mga hangganan ng lugar.
Ang Flutter ay gumagamit ng CustomPainter — isang klase na may mga pamamaraang paint(Canvas canvas, Size size) at shouldRepaint. Ang Canvas sa Flutter ay nagbibigay ng parehong mga pamamaraan tulad ng sa Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph, at drawImage. Ang Paint sa Flutter ay nag-configure ng kulay, kapal, estilo, at anti-aliasing. Ang Flutter ay hindi gumagamit ng drawRect o onDraw — lahat ng pagguhit ay sa pamamagitan ng CustomPainter, na naka-embed sa CustomPaint widget.
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;
}
Tinutukoy ng shouldRepaint kung ang CustomPainter ay kailangang muling iguhit. Magbalik lamang ng true kapag nagbago ang data na nakakaapekto sa rendering — kulay, laki, data ng chart. Inihihiwalay ng RepaintBoundary ang muling pagguhit sa isang hiwalay na layer — gamitin para sa mga widget na bihirang magbago. Ang Flutter ay walang setNeedsDisplay o invalidate — ang muling pagguhit ay na-trigger sa pamamagitan ng setState o ValueNotifier na may pakikinig sa mga pagbabago.
Sinusuportahan ng Flutter ang LinearGradient, RadialGradient, at SweepGradient — parehong mga uri tulad ng sa Android. Ang Gradient ay lumilikha ng Shader para sa Paint sa pamamagitan ng createShader(Rect bounds). Ang mga pagbabago ay isinasagawa sa pamamagitan ng canvas.rotate, canvas.scale, canvas.translate, at canvas.skew. Ang Flutter ay gumagamit ng 4x4 transformation matrix (Matrix4) para sa Transform widget. Ang mga animation ng pagguhit sa Flutter ay ginawa gamit ang AnimationController na pinagsama sa setState upang muling iguhit ang CustomPainter.
Ang tamang pagsukat ng mga custom na View ay ang pundasyon ng mahuhulaan na pag-uugali ng interface. Sa iOS, ang sukat ng View ay tinutukoy sa pamamagitan ng sizeThatFits at intrinsicContentSize. Ang sizeThatFits ay nagbabalik ng pinakamainam na sukat para sa ibinigay na mga hadlang. intrinsicContentSize — ang natural na sukat ng nilalaman nang walang panlabas na mga hadlang. Sa Android, ang pagsukat ay ipinapatupad sa onMeasure na may mga parameter na MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). Sa Flutter, ang sukat ay ipinapasa sa paint(Canvas, Size) at maaaring kalkulahin sa pamamagitan ng computeDryLayout o LayoutBuilder.
Ang intrinsicContentSize ay nagbabalik ng CGSize — ang natural na sukat ng View batay sa nilalaman nito. Ang setContentHuggingPriority at setContentCompressionResistancePriority ay kumokontrol sa pag-uugali sa panahon ng pag-unat at pag-compress. Ang sizeThatFits ay tinatawag ng system upang kalkulahin ang sukat sa Auto Layout. Para sa mga custom na View, i-override ang intrinsicContentSize kung ang iyong bahagi ay may natural na sukat — halimbawa, ang isang bilog ay dapat palaging 100x100.
Ang onMeasure ay tumatanggap ng widthMeasureSpec at heightMeasureSpec. Ang MeasureSpec ay naglalaman ng mode at sukat: UNSPECIFIED (walang mga hadlang, pinipili ng View ang sarili nitong sukat), EXACTLY (eksaktong sukat mula sa magulang), AT_MOST (maximum na sukat). Ang setMeasuredDimension(width, height) ay nag-iimbak ng resulta ng pagsukat. Kapag nagbago ang data, tawagan ang requestLayout() para sa muling pagsukat. Ang nested ViewGroup ay nangangailangan ng pag-override sa onLayout para sa pag-aayos ng mga elementong anak.
| Platform | Paraan ng Pagsukat | Tawag sa pagbabago | Pagbabalik |
|---|---|---|---|
| iOS | sizeThatFits / intrinsicContentSize | setNeedsLayout / invalidateIntrinsicContentSize | CGSize |
| Android | onMeasure / setMeasuredDimension | requestLayout / invalidate | void (nag-iimbak ng sukat) |
| Flutter | computeDryLayout | setState / LayoutBuilder | Size |
Ang computeDryLayout ay isang pamamaraan ng RenderObject para sa pagkalkula ng sukat nang walang buong layout cycle. LayoutBuilder.getSize — isang alternatibo para sa pagkuha ng magagamit na espasyo sa pamamaraang build. Sa Flutter, ang sukat ng canvas ay ipinapasa sa paint bilang Size at hindi nangangailangan ng hiwalay na pagsukat — ang CustomPainter ay gumuhit sa loob ng ipinasa na mga hangganan. Gayunpaman, para sa custom na RenderObject, kailangan mong i-override ang performLayout at computeDryLayout.
Mga Madalas Itanong
drawRect ay isang pamamaraan ng UIView para sa custom na pagguhit sa pamamagitan ng Core Graphics. Ito ay tinatawag sa unang render ng View at pagkatapos ng bawat tawag sa setNeedsDisplay(). Gamitin ang CGContext sa loob ng drawRect para sa mga linya, hugis, at teksto.
Lumikha ng isang klase na nagpapalawak ng View, i-override ang onDraw(Canvas canvas) at gamitin ang Canvas API: drawCircle, drawRect, drawPath. Ang Paint ay nag-configure ng kulay, kapal, at estilo. Para mag-update, tawagan ang invalidate().
CustomPainter ay isang klase ng Flutter para sa custom na pagguhit sa Canvas. Ipatupad ang mga pamamaraang paint(Canvas, Size) at shouldRepaint. Ito ay inilalagay sa pamamagitan ng CustomPaint widget. Ang Flutter ay walang drawRect — lahat ng pagguhit ay sa pamamagitan ng CustomPainter.
Sa iOS gamitin ang sizeThatFits at intrinsicContentSize. Sa Android — onMeasure na may MeasureSpec. Sa Flutter, ang sukat ay ipinapasa sa paint(Canvas, Size) o kinakalkula sa pamamagitan ng computeDryLayout. Ang bawat platform ay gumagamit ng sarili nitong paraan ng pagsukat.
Ang mga custom na View ay kinakailangan para sa natatanging graphics, animation, chart, at mga elementong hindi maipatupad gamit ang karaniwang UIKit o View. Para sa mga simpleng istilo, sapat na ang pag-configure ng mga karaniwang bahagi — huwag gawing kumplikado ang arkitektura nang hindi kinakailangan.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.