هنگامی که نیاز به نمایش تصاویر ثابت در برنامه خود دارید، می توانید از کلاس Drawable
و زیر کلاس های آن برای ترسیم اشکال و تصاویر استفاده کنید. Drawable
یک انتزاع کلی برای چیزی است که می توان ترسیم کرد . زیر کلاس های مختلف به سناریوهای تصویری خاص کمک می کنند و می توانید آنها را گسترش دهید تا اشیاء قابل ترسیم خود را تعریف کنید که به روش های منحصر به فردی رفتار می کنند.
دو راه برای تعریف و نمونه سازی یک Drawable
علاوه بر استفاده از سازنده کلاس وجود دارد:
- یک منبع تصویر (یک فایل بیت مپ) ذخیره شده در پروژه خود را باد کنید.
- یک منبع XML که ویژگی های قابل ترسیم را تعریف می کند، باد کنید.
توجه: ممکن است در عوض ترجیح دهید از یک ترسیم برداری برداری استفاده کنید که تصویری را با مجموعه ای از نقاط، خطوط و منحنی ها به همراه اطلاعات رنگ مرتبط تعریف می کند. این اجازه می دهد تا نقشه های برداری برای اندازه های مختلف بدون از دست دادن کیفیت مقیاس شوند. برای اطلاعات بیشتر، به نمای کلی وکتور drawables مراجعه کنید.
از تصاویر منبع، طرحهایی ایجاد کنید
می توانید با ارجاع به یک فایل تصویری از منابع پروژه خود، گرافیک را به برنامه خود اضافه کنید. انواع فایل های پشتیبانی شده PNG (ترجیحا)، JPG (قابل قبول) و GIF (ممکن است). آیکونهای برنامه، لوگوها و سایر گرافیکها، مانند مواردی که در بازیها استفاده میشوند، برای این تکنیک مناسب هستند.
برای استفاده از یک منبع تصویر، فایل خود را به دایرکتوری res/drawable/
پروژه خود اضافه کنید. پس از ورود به پروژه خود، می توانید منبع تصویر را از کد خود یا طرح XML خود ارجاع دهید. در هر صورت، به استفاده از شناسه منبع اشاره می شود که نام فایل بدون پسوند نوع فایل است. به عنوان مثال، به my_image.png
به عنوان my_image
مراجعه کنید.
توجه: منابع تصویری که در دایرکتوری res/drawable/
قرار میگیرند ممکن است به طور خودکار با فشردهسازی تصویر بدون تلفات توسط ابزار aapt
در طول فرآیند ساخت بهینه شوند. به عنوان مثال، یک PNG با رنگ واقعی که به بیش از 256 رنگ نیاز ندارد، ممکن است به یک PNG 8 بیتی با یک پالت رنگ تبدیل شود. این منجر به تصویری با کیفیت برابر می شود که به حافظه کمتری نیاز دارد. در نتیجه، باینری های تصویر قرار داده شده در این دایرکتوری می توانند در زمان ساخت تغییر کنند. اگر قصد دارید یک تصویر را به صورت بیت استریم بخوانید تا آن را به بیت مپ تبدیل کنید، به جای آن تصاویر خود را در پوشه res/raw/
قرار دهید، جایی که ابزار aapt
آنها را تغییر نمی دهد.
قطعه کد زیر نحوه ساخت ImageView
را نشان می دهد که از یک تصویر ایجاد شده از یک منبع قابل ترسیم استفاده می کند و آن را به طرح اضافه می کند:
کاتلین
private lateinit var constraintLayout: ConstraintLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Instantiate an ImageView and define its properties val i = ImageView(this).apply { setImageResource(R.drawable.my_image) contentDescription = resources.getString(R.string.my_image_desc) // set the ImageView bounds to match the Drawable's dimensions adjustViewBounds = true layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) } // Create a ConstraintLayout in which to add the ImageView constraintLayout = ConstraintLayout(this).apply { // Add the ImageView to the layout. addView(i) } // Set the layout as the content view. setContentView(constraintLayout) }
جاوا
ConstraintLayout constraintLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a ConstraintLayout in which to add the ImageView constraintLayout = new ConstraintLayout(this); // Instantiate an ImageView and define its properties ImageView i = new ImageView(this); i.setImageResource(R.drawable.my_image); i.setContentDescription(getResources().getString(R.string.my_image_desc)); // set the ImageView bounds to match the Drawable's dimensions i.setAdjustViewBounds(true); i.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // Add the ImageView to the layout and set the layout as the content view. constraintLayout.addView(i); setContentView(constraintLayout); }
در موارد دیگر، ممکن است بخواهید منبع تصویر خود را به عنوان یک شیء Drawable
مدیریت کنید، همانطور که در مثال زیر نشان داده شده است:
کاتلین
val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)
جاوا
Resources res = context.getResources(); Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);
اخطار: هر منبع منحصربهفرد در پروژه شما میتواند تنها یک حالت را حفظ کند، مهم نیست که چند شی مختلف برای آن نمونهسازی میکنید. به عنوان مثال، اگر شما دو شیء Drawable
را از یک منبع تصویر نمونه سازی کنید و یک ویژگی (مانند آلفا) را برای یک شی تغییر دهید، آنگاه روی دیگری نیز تأثیر می گذارد. هنگامی که با چندین نمونه از یک منبع تصویر سروکار دارید، به جای تبدیل مستقیم شیء Drawable
، باید یک انیمیشن tween اجرا کنید.
قطعه XML زیر نحوه افزودن یک منبع قابل ترسیم به ImageView
در طرح XML را نشان می دهد:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/my_image" android:contentDescription="@string/my_image_desc" />
برای اطلاعات بیشتر در مورد استفاده از منابع پروژه، به منابع و دارایی ها مراجعه کنید.
توجه: هنگام استفاده از منابع تصویری به عنوان منبع ترسیمیها، مطمئن شوید که تصاویر اندازه مناسبی برای تراکم پیکسلهای مختلف دارند. اگر تصاویر صحیح نباشند، به اندازه مناسب بزرگ می شوند، که می تواند باعث ایجاد مصنوعات در نقشه های شما شود. برای اطلاعات بیشتر، پشتیبانی از تراکم پیکسل های مختلف را بخوانید.
از منابع XML قابل ترسیم ایجاد کنید
اگر یک شی Drawable
وجود دارد که می خواهید ایجاد کنید، که در ابتدا به متغیرهای تعریف شده توسط کد یا تعامل کاربر شما وابسته نیست، تعریف Drawable
در XML گزینه خوبی است. حتی اگر انتظار دارید که Drawable
شما در طول تعامل کاربر با برنامه شما، ویژگیهای خود را تغییر دهد، باید شی را در XML تعریف کنید، زیرا میتوانید ویژگیها را پس از نمونهسازی شی تغییر دهید.
پس از اینکه Drawable
خود را در XML تعریف کردید، فایل را در دایرکتوری res/drawable/
پروژه خود ذخیره کنید. مثال زیر XML را نشان می دهد که یک منبع TransitionDrawable
را تعریف می کند که از Drawable
به ارث می رسد:
<!-- res/drawable/expand_collapse.xml --> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/image_expand"/> <item android:drawable="@drawable/image_collapse"/> </transition>
سپس، با فراخوانی Resources#getDrawable()
و ارسال شناسه منبع فایل XML خود، شی را بازیابی و نمونه سازی کنید. هر زیرکلاس Drawable
که از متد inflate()
پشتیبانی میکند، میتواند در XML تعریف شده و توسط برنامه شما نمونهسازی شود.
هر کلاس قابل ترسیم که از inflation XML پشتیبانی می کند از ویژگی های XML خاصی استفاده می کند که به تعریف ویژگی های شی کمک می کند. کد زیر TransitionDrawable
را نمونه سازی می کند و آن را به عنوان محتوای یک شی ImageView
تنظیم می کند:
کاتلین
val transition= ResourcesCompat.getDrawable( context.resources, R.drawable.expand_collapse, null ) as TransitionDrawable val image: ImageView = findViewById(R.id.toggle_image) image.setImageDrawable(transition) // Description of the initial state that the drawable represents. image.contentDescription = resources.getString(R.string.collapsed) // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000) // After the transition is complete, change the image's content description // to reflect the new state.
جاوا
Resources res = context.getResources(); TransitionDrawable transition = (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null); ImageView image = (ImageView) findViewById(R.id.toggle_image); image.setImageDrawable(transition); // Description of the initial state that the drawable represents. image.setContentDescription(getResources().getString(R.string.collapsed)); // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000); // After the transition is complete, change the image's content description // to reflect the new state.
برای اطلاعات بیشتر در مورد ویژگی های XML پشتیبانی شده، به کلاس های ذکر شده در بالا مراجعه کنید.
شکل های قابل ترسیم
هنگامی که می خواهید به صورت پویا یک گرافیک دو بعدی بکشید، یک شی ShapeDrawable
می تواند گزینه خوبی باشد. شما می توانید به صورت برنامه نویسی اشکال ابتدایی را روی یک شی ShapeDrawable
بکشید و سبک هایی را که برنامه شما به آن نیاز دارد اعمال کنید.
ShapeDrawable
یک زیر کلاس از Drawable
است. به همین دلیل، میتوانید از ShapeDrawable
در هر جایی که انتظار میرود Drawable
استفاده کنید. برای مثال، میتوانید از یک شی ShapeDrawable
برای تنظیم پسزمینه یک View با ارسال آن به متد setBackgroundDrawable()
view استفاده کنید. شما همچنین می توانید شکل خود را به عنوان نمای سفارشی خود ترسیم کنید و آن را به یک طرح در برنامه خود اضافه کنید.
از آنجایی که ShapeDrawable
متد draw()
مخصوص به خود را دارد، می توانید یک زیر کلاس از View
ایجاد کنید که شی ShapeDrawable
را در طول رویداد onDraw()
ترسیم کند، همانطور که در مثال کد زیر نشان داده شده است:
کاتلین
class CustomDrawableView(context: Context) : View(context) { private val drawable: ShapeDrawable = run { val x = 10 val y = 10 val width = 300 val height = 50 contentDescription = context.resources.getString(R.string.my_view_desc) ShapeDrawable(OvalShape()).apply { // If the color isn't set, the shape uses black as the default. paint.color = 0xff74AC23.toInt() // If the bounds aren't set, the shape can't be drawn. setBounds(x, y, x + width, y + height) } } override fun onDraw(canvas: Canvas) { drawable.draw(canvas) } }
جاوا
public class CustomDrawableView extends View { private ShapeDrawable drawable; public CustomDrawableView(Context context) { super(context); int x = 10; int y = 10; int width = 300; int height = 50; setContentDescription(context.getResources().getString( R.string.my_view_desc)); drawable = new ShapeDrawable(new OvalShape()); // If the color isn't set, the shape uses black as the default. drawable.getPaint().setColor(0xff74AC23); // If the bounds aren't set, the shape can't be drawn. drawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { drawable.draw(canvas); } }
میتوانید از کلاس CustomDrawableView
در نمونه کد بالا استفاده کنید، همانطور که از هر نمای سفارشی دیگری استفاده میکنید. برای مثال، همانطور که در مثال زیر نشان داده شده است، می توانید آن را به صورت برنامه نویسی به یک فعالیت در برنامه خود اضافه کنید:
کاتلین
private lateinit var customDrawableView: CustomDrawableView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) customDrawableView = CustomDrawableView(this) setContentView(customDrawableView) }
جاوا
CustomDrawableView customDrawableView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); customDrawableView = new CustomDrawableView(this); setContentView(customDrawableView); }
اگر میخواهید به جای آن از نمای سفارشی در طرح XML استفاده کنید، کلاس CustomDrawableView
باید سازنده View(Context, AttributeSet)
لغو کند، که وقتی کلاس از XML باد میشود فراخوانی میشود. مثال زیر نحوه اعلان CustomDrawableView
را در طرح XML نشان می دهد:
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
کلاس ShapeDrawable
، مانند بسیاری از انواع قابل ترسیم دیگر در بسته android.graphics.drawable
، به شما اجازه می دهد تا با استفاده از روش های عمومی، ویژگی های مختلف شی را تعریف کنید. برخی از ویژگیهای مثالی که ممکن است بخواهید تنظیم کنید عبارتند از: شفافیت آلفا، فیلتر رنگ، دودی، کدورت و رنگ.
شما همچنین می توانید اشکال اولیه قابل ترسیم را با استفاده از منابع XML تعریف کنید. برای اطلاعات بیشتر، Shape drawable در انواع منابع Drawable را ببینید.
NinePatch قابل ترسیم
یک گرافیک NinePatchDrawable
یک تصویر بیت مپ قابل کشش است که می توانید به عنوان پس زمینه یک نما از آن استفاده کنید. اندروید بهطور خودکار اندازه گرافیک را تغییر میدهد تا محتویات نما را در خود جای دهد. نمونهای از استفاده از یک تصویر NinePatch، پسزمینهای است که توسط دکمههای استاندارد اندروید استفاده میشود—دکمهها باید کشیده شوند تا رشتههایی با طولهای مختلف را در خود جای دهند. گرافیک NinePatch یک تصویر استاندارد PNG است که شامل یک حاشیه اضافی 1 پیکسلی است. باید با پسوند 9.png
در دایرکتوری res/drawable/
پروژه شما ذخیره شود.
برای تعیین نواحی قابل کشش و استاتیک تصویر از حاشیه استفاده کنید. با کشیدن یک (یا چند) خط(های) مشکی عریض 1 پیکسلی در قسمت چپ و بالای حاشیه، یک بخش قابل کشش را نشان می دهید (پیکسل های حاشیه دیگر باید کاملاً شفاف یا سفید باشند). شما می توانید هر تعداد بخش قابل کشش داشته باشید. اندازه نسبی بخش های قابل کشش ثابت می ماند، بنابراین بزرگترین بخش همیشه بزرگ ترین باقی می ماند.
همچنین می توانید با کشیدن یک خط در سمت راست و یک خط در پایین، یک بخش قابل ترسیم اختیاری از تصویر (به طور موثر، خطوط padding) تعریف کنید. اگر یک شی View
، گرافیک NinePatch را بهعنوان پسزمینه خود تنظیم کند و سپس متن نما را مشخص کند، خود را بهگونهای گسترش میدهد که تمام متن تنها ناحیه مشخصشده توسط خطوط سمت راست و پایین را اشغال کند (در صورت وجود). اگر خطوط بالشتک گنجانده نشده باشند، Android از خطوط چپ و بالا برای تعریف این ناحیه قابل ترسیم استفاده می کند.
برای روشن شدن تفاوت بین خطوط، خطوط سمت چپ و بالا مشخص می کنند که کدام پیکسل های تصویر مجاز به تکرار هستند تا تصویر کشیده شود. خطوط پایین و سمت راست ناحیه نسبی را در تصویر مشخص می کنند که محتویات نما مجاز به اشغال آن هستند.
شکل 1 نمونه ای از گرافیک NinePatch را نشان می دهد که برای تعریف یک دکمه استفاده می شود:
این گرافیک NinePatch یک ناحیه قابل کشش را با خطوط چپ و بالا و منطقه قابل کشیدن را با خطوط پایین و راست تعریف می کند. در تصویر بالا، خطوط خاکستری نقطهدار، مناطقی از تصویر را مشخص میکنند که برای کشیده شدن تصویر تکرار میشوند. مستطیل صورتی در تصویر پایین منطقه ای را که در آن محتویات نما مجاز است مشخص می کند. اگر محتویات در این ناحیه قرار نگیرند، تصویر کشیده میشود تا مناسب شود.
ابزار Draw 9-patch یک راه بسیار مفید برای ایجاد تصاویر NinePatch شما با استفاده از ویرایشگر گرافیکی WYSIWYG ارائه می دهد. حتی اگر منطقه ای که برای ناحیه قابل کشش تعریف کرده اید در معرض خطر ایجاد مصنوعات طراحی در نتیجه تکرار پیکسل باشد، هشدارهایی را نیز ایجاد می کند.
نمونه طرح XML زیر نحوه اضافه کردن یک گرافیک NinePatch را به چند دکمه نشان می دهد. تصویر NinePatch در res/drawable/my_button_background.9.png
ذخیره میشود.
<Button android:id="@+id/tiny" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:text="Tiny" android:textSize="8sp" android:background="@drawable/my_button_background"/> <Button android:id="@+id/big" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerInParent="true" android:text="Biiiiiiig text!" android:textSize="30sp" android:background="@drawable/my_button_background"/>
توجه داشته باشید که ویژگی های layout_width
و layout_height
روی wrap_content
تنظیم شده اند تا دکمه به خوبی در اطراف متن قرار بگیرد.
شکل 2 دو دکمه ارائه شده از تصویر XML و NinePatch نشان داده شده در بالا را نشان می دهد. توجه کنید که چگونه عرض و ارتفاع دکمه با متن متفاوت است و تصویر پسزمینه برای جا دادن آن کشیده میشود.
طراحی های سفارشی
هنگامی که می خواهید چند نقشه سفارشی ایجاد کنید، می توانید این کار را با گسترش کلاس Drawable
(یا هر یک از زیر کلاس های آن) انجام دهید.
مهمترین روش برای پیاده سازی، draw(Canvas)
است، زیرا این شی Canvas
را ارائه می دهد که باید برای ارائه دستورالعمل های طراحی خود از آن استفاده کنید.
کد زیر یک زیر کلاس ساده از Drawable
را نشان می دهد که یک دایره رسم می کند:
کاتلین
class MyDrawable : Drawable() { private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) } override fun draw(canvas: Canvas) { // Get the drawable's bounds val width: Int = bounds.width() val height: Int = bounds.height() val radius: Float = Math.min(width, height).toFloat() / 2f // Draw a red circle in the center canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint) } override fun setAlpha(alpha: Int) { // This method is required } override fun setColorFilter(colorFilter: ColorFilter?) { // This method is required } override fun getOpacity(): Int = // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE PixelFormat.OPAQUE }
جاوا
public class MyDrawable extends Drawable { private final Paint redPaint; public MyDrawable() { // Set up color and text size redPaint = new Paint(); redPaint.setARGB(255, 255, 0, 0); } @Override public void draw(Canvas canvas) { // Get the drawable's bounds int width = getBounds().width(); int height = getBounds().height(); float radius = Math.min(width, height) / 2; // Draw a red circle in the center canvas.drawCircle(width/2, height/2, radius, redPaint); } @Override public void setAlpha(int alpha) { // This method is required } @Override public void setColorFilter(ColorFilter colorFilter) { // This method is required } @Override public int getOpacity() { // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE return PixelFormat.OPAQUE; } }
سپس می توانید نقشه کشی خود را در هر کجا که می خواهید اضافه کنید، مانند ImageView
همانطور که در اینجا نشان داده شده است:
کاتلین
val myDrawing = MyDrawable() val image: ImageView = findViewById(R.id.imageView) image.setImageDrawable(myDrawing) image.contentDescription = resources.getString(R.string.my_image_desc)
جاوا
MyDrawable mydrawing = new MyDrawable(); ImageView image = findViewById(R.id.imageView); image.setImageDrawable(mydrawing); image.setContentDescription(getResources().getString(R.string.my_image_desc));
در Android 7.0 (سطح API 24) و بالاتر، همچنین میتوانید نمونههایی از قابل ترسیم سفارشی خود را با XML به روشهای زیر تعریف کنید:
- استفاده از نام کلاس کاملاً واجد شرایط به عنوان نام عنصر XML. برای این رویکرد، کلاس drawable سفارشی باید یک کلاس سطح بالای عمومی باشد:
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- استفاده از
drawable
به عنوان نام تگ XML و تعیین نام کلاس کاملاً واجد شرایط از ویژگی class. این رویکرد ممکن است هم برای کلاس های سطح بالای عمومی و هم برای کلاس های داخلی استاتیک عمومی استفاده شود:<drawable xmlns:android="http://schemas.android.com/apk/res/android" class="com.myapp.MyTopLevelClass$MyDrawable" android:color="#ffff0000" />
به طرحها رنگ اضافه کنید
با اندروید 5.0 (سطح API 21) و بالاتر، میتوانید بیت مپها و 9 وصلههایی که بهعنوان ماسک آلفا تعریف شدهاند را رنگ آمیزی کنید. میتوانید آنها را با منابع رنگی یا ویژگیهای موضوعی که به منابع رنگی تغییر میکنند (به عنوان مثال، ?android:attr/colorPrimary
) رنگ کنید. معمولاً این دارایی ها را فقط یک بار ایجاد می کنید و به طور خودکار آنها را رنگ می کنید تا با تم شما مطابقت داشته باشد.
می توانید با متد setTint()
یک tint به اشیاء BitmapDrawable
، NinePatchDrawable
یا VectorDrawable
اعمال کنید. همچنین میتوانید رنگ و حالت رنگ را در طرحبندیهای خود با ویژگیهای android:tint
و android:tintMode
تنظیم کنید.
استخراج رنگ های برجسته از یک تصویر
کتابخانه پشتیبانی اندروید شامل کلاس Palette
است که به شما امکان می دهد رنگ های برجسته را از یک تصویر استخراج کنید. میتوانید نقشههای خود را بهعنوان Bitmap
بارگذاری کنید و برای دسترسی به رنگهای آن به Palette
ارسال کنید. برای اطلاعات بیشتر، انتخاب رنگ ها با پالت API را بخوانید.