نظرة عامة على "رسومات Google"

تجربة طريقة ComposeAllowed
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي ننصح بها لنظام التشغيل Android. تعرَّف على كيفية عرض الرسومات في Compose.

عندما تحتاج إلى عرض صور ثابتة في تطبيقك، يمكنك استخدام الفئة Drawable وفئاتها الفرعية لرسم أشكال الصور. Drawable هو تجريد عام شيء يمكن رسمه. وتساعد الفئات الفرعية المختلفة في الحصول على صورة محددة ويمكنك توسيعها لتحديد الكائنات القابلة للرسم تتصرف بطرق فريدة.

هناك طريقتان لتحديد Drawable وإنشاء مثيل منه إلى جانب استخدام الدوال الإنشائية للفئة:

  • تضخيم مورد الصور (ملف الصور النقطية) المحفوظ في مشروعك.
  • تضخيم مورد XML الذي يحدد السمات القابلة للرسم

ملاحظة: قد تفضل بدلاً من ذلك استخدام متجه قابل للرسم، والذي يحدد صورة بمجموعة من النقاط والخطوط والمنحنيات، إلى جانب معلومات اللون المرتبطة بها. يسمح هذا بإتاحة رسم المتجهات ليتم قياسها لتناسب أحجام مختلفة دون فقدان الجودة. لمزيد من المعلومات، يُرجى الاطّلاع على قسم متّجه نظرة عامة على العناصر القابلة للرسم.

إنشاء عناصر قابلة للرسم من صور الموارد

يمكنك إضافة رسومات إلى تطبيقك من خلال الإشارة إلى ملف صورة من موارد المشروع. أنواع الملفات المعتمدة هي PNG (الخيار المفضّل) وJPG (مقبول) وGIF (لا يُنصح باستخدامها) رموز التطبيقات والشعارات والرسومات الأخرى، مثل الرسومات المستخدَمة في الألعاب، هي مناسبة تمامًا لهذه التقنية.

لاستخدام مورد صور، أضِف ملفك إلى res/drawable/. دليل مشروعك. بعد الوصول إلى مشروعك، يمكنك الرجوع إلى الصورة من الرمز البرمجي أو تنسيق XML. وفي كلتا الحالتين، يشار إليه باستخدام ومعرّف المورد، وهو اسم الملف بدون امتداد نوع الملف. بالنسبة على سبيل المثال، ارجع إلى my_image.png باسم my_image.

ملاحظة: تتوفّر موارد الصور في قد يتم تحسين الدليل res/drawable/ تلقائيًا باستخدام ضغط الصور بدون فقدان البيانات باستخدام أداة aapt أثناء عملية التصميم الدفع. على سبيل المثال، ملف PNG باللون الحقيقي لا يتطلب أكثر من 256 لونًا يمكن تحويلها إلى ملف PNG بحجم 8 بت مع لوحة ألوان. ينتج عن ذلك صورة بجودة متساوية ولكن تتطلب ذاكرة أقل. نتيجةً لذلك، تصبح الصور الثنائية الموضوعة في هذا الدليل يمكن أن تتغير في وقت الإنشاء. إذا كنت تخطط لقراءة وتحويلها إلى صورة نقطية، فضع صورك في res/raw/ بدلاً من ذلك، حيث لا تفعل الأداة aapt وتعديلها.

يوضح مقتطف الرمز التالي كيفية إنشاء ImageView يستخدم صورة تم إنشاؤها من مورد قابل للرسم وتضيفها إلى التخطيط:

Kotlin

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)
}

Java

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، كما هو موضّح في ما يلي مثال:

Kotlin

val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)

Java

Resources res = context.getResources();
Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);

تحذير: يشير هذا المصطلح إلى كل مورد فريد في مشروعك. يمكنك الاحتفاظ بحالة واحدة فقط، بغض النظر عن عدد العناصر المختلفة لإنشاء مثيل لها. على سبيل المثال، في حال إنشاء مثيل كائنَين Drawable من مورد الصور نفسه تغيير خاصية (مثل ألفا) لكائن واحد، فسيؤثر ذلك أيضًا الأخرى. عند التعامل مع مثيلات متعددة لمورد صورة، بدلاً من من تحويل الكائن Drawable مباشرةً، يجب تنفيذ ما قبل سن المراهقة صورة متحركة.

يوضّح مقتطف 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 وإنشاء مثيل لها حسب تطبيقك.

تستخدم كل فئة قابلة للرسم تتوافق مع تضخيم XML سمات XML محدّدة. تساعد في تعريف خصائص الكائن. تنشئ التعليمة البرمجية التالية مثيلاً TransitionDrawable وتعيينه كمحتوى كائن ImageView:

Kotlin

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.

Java

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 لضبط الخلفية. العرض من خلال تمريره إلى طريقة العرض setBackgroundDrawable(). يمكنك أيضًا رسم الشكل الخاص بك طريقة عرض مخصصة لك وإضافتها إلى تخطيط في تطبيقك.

بما أنّ ShapeDrawable يستخدم طريقة draw() الخاصة به، يمكنك إنشاء فئة فرعية من View ترسم السمة ShapeDrawable كائن أثناء الحدث onDraw()، كما هو موضح في مثال التعليمة البرمجية التالي:

Kotlin

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)
    }
}

Java

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 في عيّنة الرمز البرمجي. أعلاه كما تستخدم أي طريقة عرض مخصّصة أخرى. على سبيل المثال، يمكنك إضافتها آليًا إلى نشاط في تطبيقك، كما هو موضح في ما يلي مثال:

Kotlin

private lateinit var customDrawableView: CustomDrawableView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    customDrawableView = CustomDrawableView(this)

    setContentView(customDrawableView)
}

Java

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. لمزيد من المعلومات، المعلومات، راجع شكل قابل للرسم في أنواع المراجع القابلة للرسم:

عناصر NinePatch القابلة للرسم

الرسم NinePatchDrawable هو صورة نقطية قابلة للتمديد يمكنك استخدامها كخلفية للعرض. جهاز Android تغيير حجم الرسم تلقائيًا لاستيعاب محتويات طريقة العرض. إنّ مثال على استخدام صورة NinePatch هو الخلفية التي يستخدمها نظام Android الأزرار — يجب أن تمتد الأزرار لتلائم السلاسل ذات الأطوال المختلفة. حاسمة رسم NinePatch هو صورة PNG قياسية تتضمن حدًا إضافيًا يبلغ 1 بكسل. يجب حفظه باستخدام الإضافة 9.png في دليل res/drawable/ لمشروعك.

استخدم الحدود لتحديد المناطق القابلة للتمديد والثابتة من الصورة. يمكنك الإشارة إلى قسم قابل للتمديد من خلال رسم بكسل واحد (أو أكثر) بعرض واحد (أو أكثر) الخطوط السوداء في الجزء الأيسر والعلوي من الحد (وحدات بكسل الحد الأخرى) شفافة تمامًا أو بيضاء). يمكنك إنشاء العديد من الأقسام القابلة للتمدّد كما تريد. ويظل الحجم النسبي للأقسام القابلة للتمديد كما هو، وبالتالي يظل القسم الأكبر هو الأكبر دائمًا.

ويمكنك أيضًا تحديد قسم اختياري قابل للرسم من الصورة (بشكل فعال، خطوط المساحة المتروكة) عن طريق رسم خط على اليمين وخط في الأسفل. إذا يضبط الكائن View رسم NinePatch كخلفية له. ومن ثم تحدد نص العرض، فإنه يتسع نفسه حتى لا تشغل سوى المنطقة المحددة في السطرين اليمنى والسفلية (إذا تم تضمينها). إذا لم يتم تضمين خطوط المساحة المتروكة، يستخدم Android السطرين الأيسر والعلوي من أجل لتحديد هذه المنطقة القابلة للرسم.

لتوضيح الفرق بين الخطوط، تحدد الخطوط اليسرى والعلوية وحدات بكسل الصورة المسموح بنسخها من أجل تمديد . يحدد الخطان السفليان واليمينان المنطقة النسبية داخل الصورة يُسمح لمحتويات العرض بشغلها.

يوضح الشكل 1 مثالاً لرسم NinePatch يستخدم لتحديد زر:

صورة لمنطقة قابلة للتمديد
ومربّع المساحة المتروكة

الشكل 1: مثال على رسم NinePatch الذي يعرّف الزر

يحدد رسم NinePatch هذا منطقة واحدة قابلة للتمدد يتم عرضها جهة اليسار والأعلى والخطوط والمنطقة القابلة للرسم بالخطوط السفلية واليمنى. في الصورة العلوية، تحدد الخطوط الرمادية المنقطة مناطق الصورة التي يتم نسخها من أجل توسيع الصورة. يحدد المستطيل الوردي في الصورة السفلية المنطقة التي يُسمح فيها بمحتوى العرض. إذا لم يكن المحتوى مناسبة لهذه المنطقة، ثم يتم تمديد الصورة لجعلها مناسبة.

تقدم أداة الرسم 9-التصحيح طريقة سهلة للغاية لإنشاء صور 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 كما هو موضح أعلاه. لاحظ كيف يختلف عرض الزر وارتفاعه مع النص، وتمتد صورة الخلفية لتتلاءم معها.

صورة لجسم صغير
أزرار بالحجم العادي

الشكل 2: الأزرار المعروضة باستخدام ملف XML المورد ورسم NinePatch

عناصر مخصَّصة للرسم

عندما تريد إنشاء بعض الرسومات المخصّصة، يمكنك إجراء ذلك من خلال توسيع الفئة Drawable (أو أي من فئاتها الفرعية).

وأهم طريقة للتنفيذ هي draw(Canvas). لأنّ هذا الإجراء يوفّر الكائن Canvas الذي يجب استخدامه لتقديمه تعليمات الرسم.

يُظهر الرمز البرمجي التالي فئة فرعية بسيطة من Drawable ترسم دائرة:

Kotlin

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
}

Java

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 كما هو موضّح هنا:

Kotlin

val myDrawing = MyDrawable()
val image: ImageView = findViewById(R.id.imageView)
image.setImageDrawable(myDrawing)
image.contentDescription = resources.getString(R.string.my_image_desc)

Java

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 (المستوى 24 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك أيضًا تحديد نُسخ افتراضية مخصّصة للرسم. مع XML بالطرق التالية:

  • استخدام اسم الفئة المؤهلة بالكامل كاسم لعنصر XML. بالنسبة لهذا النهج، يتم تخصيص يجب أن تكون فئة قابلة للرسم فئة عامة عالية المستوى:
    <com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#ffff0000" />
    
  • استخدام drawable كاسم علامة XML وتحديد الفئة المؤهلة بالكامل من تصنيف الفئة. يمكن استخدام هذا النهج لكل من صفوف المستوى الأعلى العامة الفئات الداخلية الثابتة العامة:
    <drawable xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.myapp.MyTopLevelClass$MyDrawable"
        android:color="#ffff0000" />
    

إضافة درجة اللون إلى العناصر القابلة للرسم

من خلال الإصدار Android 5.0 (المستوى 21 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك تلوين الصور النقطية وتسع تصحيحات أقنعة ألفا. يمكنك تلوينها باستخدام موارد الألوان أو سمات المظاهر التي تتغيّر إلى اللون. الموارد (على سبيل المثال، ?android:attr/colorPrimary). في العادة، تُنشئ مواد العرض هذه مرة واحدة فقط وقم بتلوينها تلقائيًا لتلائم مظهرك.

يمكنك تطبيق تلوين خفيف على BitmapDrawable أو NinePatchDrawable أو VectorDrawable. باستخدام الطريقة setTint(). يمكنك أيضًا ضبط لون درجة اللون ووضعها في التنسيقات باستخدام android:tint android:tintMode سمة.

استخراج الألوان البارزة من صورة

تحتوي مكتبة دعم Android على فئة Palette التي تتيح لك استخراج الألوان البارزة من صورة. يمكنك تحميل عناصرك القابلة للرسم على أنّها Bitmap وتمريرها إلى Palette للوصول إلى ألوانها. لمزيد من المعلومات، يُرجى قراءة المقالة تحديد الألوان باستخدام واجهة برمجة التطبيقات Palette API