شیبهای رنگی مش بااستفاده از شبکه دوبعدی از وصلهها، انتقالهای رنگی پیچیده و چندجهتی ایجاد میکنند. برخلاف گرادیانهای خطی یا شعاعی، گرادیانهای توری بهآرامی
رنگها را در یک شبکه دوبعدی درونیابی میکنند. هنگام ایجاد پسزمینههای سیال، ارگانیک، یا چندنقطهای در میانای کاربر، بهجای چیدن چندین قلمموی radialGradient یا linearGradient روی هم، از گرادیانهای مش استفاده کنید.
مفاهیم اصلی
برای ساختن گرادیان مش، ابعاد شبکه، رئوس، و گذارهای رنگی بین نقاط را تعریف کنید:
- ابعاد شبکه: مش در امتداد محورهای عمودی و افقی به وصلههایی تقسیم میشود. شبکهای از
rowsوcolumnsشامل (ردیفها+۱)×(ستونها+۱) رأس است. برای مثال، یک مش ۱×۱ از ۴ رأس تشکیل شده است که یک وصله را تشکیل میدهند. - مختصات نرمالشده: همه موقعیتهای رأس از سیستم مختصات نرمالشده استفاده میکنند که در آن
(0f, 0f)نشاندهنده بالا سمت چپ و(1f, 1f)نشاندهنده پایین سمت راست مرزهای طراحی است. - نقاط کنترل بزیه (مماسها): هر رأس شامل حداکثر چهار نقطه کنترل بزیه اختیاری است. این مماسها انحنای لبه بین رأسهای همسایه را مشخص میکنند. اگر از
Offset.Unspecifiedاستفاده کنید، Compose مماسها را استنباط میکند تا از انتقال روان در سراسر وصلهها اطمینان حاصل کند. هر سلول شبکه که از ۴ رأس بههمراه نقاط کنترل آنها تشکیل شده است، یک وصله بزیه تولید میکند. - درونیابی رنگ: چارچوب رنگهای بین رأسهای اصلی را محاسبه میکند. برای انتقال رنگ ملایمتر،
hasBicubicColorرا رویtrueبرای درونیابی Catmull-Rom تنظیم کنید، یا برای درونیابی دوخطی رویfalseتنظیم کنید.
کشیدن با MeshGradientPainter
در Jetpack Compose، از
MeshGradientPainter
برای رندر کردن گرادیان مش استفاده کنید. MeshGradientPainter روی بوم نقاشی میکشد.
ایجاد گرادیان مش ساده
برای ایجاد گرادیان مش ثابت پایه، MeshGradientPainter را با مشخص کردن ابعاد آن و استفاده از تابع setVertex در بلوک پیکربندی مقداردهی اولیه کنید تا نقاط گوشه را جایگذاری کنید و به آنها رنگ اختصاص دهید.
val rows = 1 val columns = 1 val gradientPainter = remember { MeshGradientPainter(rows, columns) { // Parameters: row, column, position, color setVertex(0, 0, Offset(0f, 0f), Color.Red) // Top-Left setVertex(0, 1, Offset(1f, 0f), Color.Blue) // Top-Right setVertex(1, 0, Offset(0f, 1f), Color.Green) // Bottom-Left setVertex(1, 1, Offset(1f, 1f), Color.Yellow) // Bottom-Right } } Box( modifier = modifier .aspectRatio(16/9f) .fillMaxWidth() .paint(gradientPainter) )
استفاده از نقاط کنترل بزیه خاص
بهطور پیشفرض، تولیدکننده مش محاسبات پیچیده را انجام میدهد تا انتقالهای شبکه هموار بماند. بااینحال، اگر میخواهید بخشهای رنگی خاصی را بهطور انتخابی فشار دهید، بکشید، یا بهطور تیز نیشگون بگیرید، میتوانید مماسها را بهطور صریح روی هر رأس تکی سفارشیسازی کنید.
انحرافهای کنترل نسبت به موقعیت رأس میزبان اندازهگیری میشود.
val customTangentPainter = remember { MeshGradientPainter(rows = 1, columns = 1) { // Tweak the top-left vertex to curve outwards to the right and bottom setVertex( row = 0, column = 0, position = Offset(0f, 0f), color = Color.Magenta, rightControlPoint = Offset(0.4f, 0.1f), bottomControlPoint = Offset(0.1f, 0.4f) ) // Other points can remain unspecified to use default inferred fallback tangents setVertex(0, 1, Offset(1f, 0f), Color.Cyan) setVertex(1, 0, Offset(0f, 1f), Color.Blue) setVertex(1, 1, Offset(1f, 1f), Color.Black) } } Box( modifier = modifier .aspectRatio(16/9f) .fillMaxWidth() .paint(customTangentPainter) )
ایجاد شبکههای پیشرفته
این مثال یک شبکه ۳ در ۳ را نشان میدهد، یعنی ۱۶ نقطه وجود دارد که باید مشخص شود، و نقاط میانی با جابهجاییهای مختلف تنظیم شدهاند:
val points = remember { listOf( Offset(0.0f, 0.0f), Offset(0.3f, 0.0f), Offset(0.7f, 0.0f), Offset(1.0f, 0.0f), Offset(0.0f, 0.3f), Offset(0.2f, 0.4f), Offset(0.7f, 0.2f), Offset(1.0f, 0.3f), Offset(0.0f, 0.7f), Offset(0.3f, 0.8f), Offset(0.7f, 0.6f), Offset(1.0f, 0.7f), Offset(0.0f, 1.0f), Offset(0.3f, 1.0f), Offset(0.7f, 1.0f), Offset(1.0f, 1.0f) ) } val gradientPainter = remember { MeshGradientPainter(rows = 3, columns = 3) { // Row 0 setVertex(0, 0, points[0], yellow) setVertex(0, 1, points[1], orange) setVertex(0, 2, points[2], yellow) setVertex(0, 3, points[3], purple) // Row 1 setVertex(1, 0, points[4], pink) setVertex(1, 1, points[5], yellow) setVertex(1, 2, points[6], pink) setVertex(1, 3, points[7], purple) // Row 2 setVertex(2, 0, points[8], indigo) setVertex(2, 1, points[9], pink) setVertex(2, 2, points[10], purple) setVertex(2, 3, points[11], indigo) // Row 3 setVertex(3, 0, points[12], purple) setVertex(3, 1, points[13], indigo) setVertex(3, 2, points[14], pink) setVertex(3, 3, points[15], yellow) } } Box( modifier = modifier.padding(32.dp) .aspectRatio(16 / 9f) .fillMaxWidth() .paint(gradientPainter) // ... )
پویانمایی گرادیان مش
چون پارامتر لامبدا block از MeshGradientPainter در
DrawScope اجرا میشود، میتواند وضعیت تغییرپذیر را بخواند و مشاهده کند. میتوانید موقعیتها یا رنگها را درطول زمان بدون تخصیص مجدد سایهزنها یا نقشههای بیتی پویانمایی کنید.
val infiniteTransition = rememberInfiniteTransition(label = "meshMovement") val animatedOffset by infiniteTransition.animateFloat( initialValue = -0.1f, targetValue = 0.1f, animationSpec = infiniteRepeatable( animation = tween(2500, easing = LinearEasing), repeatMode = RepeatMode.Reverse ), label = "offset" ) val coral = Color(255, 90, 90) val peach = Color(255, 139, 90) val amber = Color(255, 169, 90) val sunshine = Color(255, 212, 90) val indigo = Color(0xFF5856D6) val pink = Color(0xFFFF2D55) val gradientPainter = remember { MeshGradientPainter(rows = 3, columns = 3) { // Row 0 setVertex(0, 0, Offset(0.0f, 0.0f), indigo) setVertex(0, 1, Offset(0.3f, 0.0f), peach) setVertex(0, 2, Offset(0.7f, 0.0f), amber) setVertex(0, 3, Offset(1.0f, 0.0f), sunshine) // Row 1 setVertex(1, 0, Offset(0.0f, 0.3f), pink) setVertex(1, 1, Offset(0.2f, 0.4f) + Offset(animatedOffset, animatedOffset), coral) setVertex(1, 2, Offset(0.7f, 0.2f) + Offset(animatedOffset, animatedOffset), peach) setVertex(1, 3, Offset(1.0f, 0.3f), indigo) // Row 2 setVertex(2, 0, Offset(0.0f, 0.7f), coral) setVertex(2, 1, Offset(0.3f, 0.8f) + Offset(animatedOffset, 0f), pink) setVertex(2, 2, Offset(0.7f, 0.6f) + Offset(animatedOffset, 0f), sunshine) setVertex(2, 3, Offset(1.0f, 0.7f), amber) // Row 3 setVertex(3, 0, Offset(0.0f, 1.0f), sunshine) setVertex(3, 1, Offset(0.3f, 1.0f), amber) setVertex(3, 2, Offset(0.7f, 1.0f), pink) setVertex(3, 3, Offset(1.0f, 1.0f), indigo) } } Box( modifier = modifier.padding(32.dp) .safeContentPadding() .aspectRatio(16 / 9f) .fillMaxWidth() .paint(gradientPainter) )