بسیاری از برنامه ها باید بتوانند دقیقاً آنچه را که روی صفحه ترسیم می شود، کنترل کنند. این ممکن است به اندازه قرار دادن یک جعبه یا یک دایره بر روی صفحه نمایش در مکان مناسب باشد، یا ممکن است یک چیدمان دقیق از عناصر گرافیکی در سبک های مختلف باشد.
طراحی اولیه با اصلاح کننده ها و DrawScope
راه اصلی برای ترسیم چیزی سفارشی در Compose با اصلاحکنندههایی مانند Modifier.drawWithContent
، Modifier.drawBehind
و Modifier.drawWithCache
است.
به عنوان مثال، برای ترسیم چیزی در پشت composable خود، می توانید از اصلاح کننده drawBehind
برای شروع اجرای دستورات ترسیم استفاده کنید:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
اگر تنها چیزی که نیاز دارید یک ترکیب بندی است که طراحی کند، می توانید از Canvas
composable استفاده کنید. Canvas
composable یک بسته بندی مناسب در اطراف Modifier.drawBehind
است. Canvas
را به همان روشی که با هر عنصر دیگر Compose UI قرار می دهید، در طرح بندی خود قرار می دهید. در داخل Canvas
، می توانید عناصر را با کنترل دقیق بر سبک و مکان آنها ترسیم کنید.
همه اصلاحکنندههای طراحی، یک DrawScope
نشان میدهند، یک محیط طراحی با محدودهای که حالت خود را حفظ میکند. این به شما امکان می دهد پارامترهای گروهی از عناصر گرافیکی را تنظیم کنید. DrawScope
چندین فیلد مفید را فراهم می کند، مانند size
، یک شی Size
که ابعاد فعلی DrawScope
را مشخص می کند.
برای ترسیم چیزی، می توانید از یکی از بسیاری از توابع ترسیم در DrawScope
استفاده کنید. به عنوان مثال، کد زیر یک مستطیل در گوشه سمت چپ بالای صفحه رسم می کند:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
برای کسب اطلاعات بیشتر در مورد اصلاحکنندههای مختلف طراحی، به مستندات Graphics Modifiers مراجعه کنید.
سیستم مختصات
برای ترسیم چیزی روی صفحه، باید افست ( x
و y
) و اندازه مورد خود را بدانید. با بسیاری از روش های ترسیم در DrawScope
، موقعیت و اندازه توسط مقادیر پارامتر پیش فرض ارائه می شود. پارامترهای پیشفرض عموماً مورد را در نقطه [0, 0]
روی بوم قرار میدهند و size
پیشفرضی را ارائه میکنند که کل منطقه طراحی را پر میکند، مانند مثال بالا - میتوانید ببینید که مستطیل در سمت چپ بالا قرار گرفته است. برای تنظیم اندازه و موقعیت آیتم خود، باید سیستم مختصات را در Compose درک کنید.
مبدا سیستم مختصات ( [0,0]
) در سمت چپ بالای پیکسل در ناحیه ترسیم است. x
با حرکت به سمت راست افزایش می یابد و y
با حرکت به سمت پایین افزایش می یابد.
به عنوان مثال، اگر می خواهید یک خط مورب از گوشه سمت راست بالای قسمت بوم به گوشه سمت چپ پایین بکشید، می توانید از تابع DrawScope.drawLine()
استفاده کنید و شروع و پایان را با x مربوطه مشخص کنید. و موقعیت های y:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
تحولات اساسی
DrawScope
تبدیل هایی را برای تغییر مکان یا نحوه اجرای دستورات ترسیم ارائه می دهد.
مقیاس
از DrawScope.scale()
برای افزایش اندازه عملیات طراحی خود با یک عامل استفاده کنید. عملیاتی مانند scale()
برای تمام عملیات ترسیم در لامبدا مربوطه اعمال می شود. به عنوان مثال، کد زیر scaleX
10 برابر و scaleY
15 برابر افزایش می دهد:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
ترجمه کنید
از DrawScope.translate()
برای حرکت دادن عملیات طراحی خود به بالا، پایین، چپ یا راست استفاده کنید. به عنوان مثال، کد زیر نقاشی را 100 پیکسل به سمت راست و 300 پیکسل به بالا حرکت می دهد:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
چرخش
از DrawScope.rotate()
برای چرخاندن عملیات ترسیم حول یک نقطه محوری استفاده کنید. به عنوان مثال، کد زیر یک مستطیل را 45 درجه می چرخاند:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
درج شده
از DrawScope.inset()
برای تنظیم پارامترهای پیشفرض DrawScope
فعلی، تغییر مرزهای طراحی و ترجمه نقشهها بر این اساس استفاده کنید:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
این کد به طور موثر padding را به دستورات ترسیم اضافه می کند:
دگرگونی های متعدد
برای اعمال تبدیل های متعدد به نقشه های خود، از تابع DrawScope.withTransform()
استفاده کنید، که یک تبدیل واحد ایجاد و اعمال می کند که تمام تغییرات مورد نظر شما را ترکیب می کند. استفاده از withTransform()
کارآمدتر از برقراری تماس های تودرتو برای تبدیل های فردی است، زیرا همه تبدیل ها با هم در یک عملیات واحد انجام می شوند، به جای اینکه Compose نیاز به محاسبه و ذخیره هر یک از تبدیل های تودرتو داشته باشد.
به عنوان مثال، کد زیر هم ترجمه و هم یک چرخش را برای مستطیل اعمال می کند:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
عملیات ترسیم رایج
متن را ترسیم کنید
برای ترسیم متن در Compose، معمولاً می توانید از Text
composable استفاده کنید. با این حال، اگر در یک DrawScope
هستید یا می خواهید متن خود را به صورت دستی با سفارشی سازی ترسیم کنید، می توانید از متد DrawScope.drawText()
استفاده کنید.
برای ترسیم متن، با استفاده از rememberTextMeasurer
یک TextMeasurer
ایجاد کنید و drawText
با اندازهگیر فراخوانی کنید:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
متن را اندازه گیری کنید
طراحی متن کمی متفاوت از سایر دستورات ترسیم عمل می کند. به طور معمول، شما به دستور ترسیم اندازه (عرض و ارتفاع) می دهید تا شکل/تصویر را به عنوان ترسیم کند. با متن، چند پارامتر وجود دارد که اندازه متن ارائه شده را کنترل می کند، مانند اندازه فونت، فونت، لیگاتورها و فاصله حروف.
با Compose، بسته به عوامل فوق، می توانید از TextMeasurer
برای دسترسی به اندازه اندازه گیری شده متن استفاده کنید. اگر میخواهید پسزمینهای پشت متن بکشید، میتوانید از اطلاعات اندازهگیری شده برای به دست آوردن اندازه ناحیهای که متن اشغال میکند استفاده کنید:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
این قطعه کد یک پس زمینه صورتی روی متن ایجاد می کند:
تنظیم محدودیتها، اندازه فونت یا هر ویژگی که بر اندازه اندازهگیری شده تأثیر میگذارد، اندازه جدیدی گزارش میشود. شما می توانید اندازه ثابتی را هم برای width
و هم height
تنظیم کنید و سپس متن از مجموعه TextOverflow
پیروی می کند. به عنوان مثال، کد زیر متن را در ⅓ ارتفاع و ⅓ از عرض ناحیه قابل ترکیب رندر می کند و TextOverflow
را روی TextOverflow.Ellipsis
قرار می دهد:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
اکنون متن در قیود با یک بیضی در پایان ترسیم شده است:
رسم تصویر
برای ترسیم ImageBitmap
با DrawScope
، تصویر را با استفاده از ImageBitmap.imageResource()
بارگذاری کنید و سپس drawImage
فراخوانی کنید:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
شکل های اساسی را رسم کنید
بسیاری از توابع ترسیم شکل در DrawScope
وجود دارد. برای ترسیم یک شکل، از یکی از توابع ترسیم از پیش تعریف شده مانند drawCircle
استفاده کنید:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API | خروجی |
مسیر را ترسیم کنید
مسیر مجموعه ای از دستورالعمل های ریاضی است که پس از اجرا منجر به ترسیم می شود. DrawScope
می تواند با استفاده از متد DrawScope.drawPath()
مسیری را ترسیم کند.
به عنوان مثال، بگویید می خواهید یک مثلث بکشید. شما می توانید یک مسیر با توابعی مانند lineTo()
و moveTo()
با استفاده از اندازه منطقه ترسیم ایجاد کنید. سپس، drawPath()
با این مسیر تازه ایجاد شده فراخوانی کنید تا یک مثلث به دست آورید.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )
دسترسی به شی Canvas
با DrawScope
، دسترسی مستقیم به یک شی Canvas
ندارید. می توانید از DrawScope.drawIntoCanvas()
برای دسترسی به خود شی Canvas
استفاده کنید که می توانید توابع را روی آن فراخوانی کنید.
برای مثال، اگر یک Drawable
سفارشی دارید که میخواهید آن را روی بوم بکشید، میتوانید به بوم دسترسی داشته باشید و Drawable#draw()
با عبور از شی Canvas
فراخوانی کنید:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )
بیشتر بدانید
برای اطلاعات بیشتر در مورد طراحی در نوشتن، به منابع زیر نگاهی بیندازید:
- اصلاح کننده های گرافیک - با انواع مختلف اصلاح کننده های طراحی آشنا شوید.
- Brush - یاد بگیرید که چگونه نقاشی محتوای خود را سفارشی کنید.
- طرحبندیها و گرافیکهای سفارشی در Compose - Android Dev Summit 2022 - با نحوه ایجاد یک رابط کاربری سفارشی در Compose with Layouts and Graphics آشنا شوید.
- JetLagged Sample - نوشتن نمونه که نحوه رسم نمودار سفارشی را نشان می دهد.
برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- اصلاح کننده های گرافیکی
- گرافیک در Compose
- خطوط تراز در Jetpack Compose