رسم یک مسیر: رندر کردن VectorDrawable های اندروید

چهارشنبه ۱۲ دی ۹۷ توسط سالار ساری نوایی

در مقاله‌ی قبل، به بررسی فرمت VectorDrawable اندروید و مزایا و قابلیت‌های آن پرداختیم.

دیدیم که چگونه می‌توان مسیرهایی که شکل شما را در تصویر ایجاد می‌کنند را تعریف کرد. VectorDrawable از چندین روش برای رسم این اشکال پشتیبانی می‌کند که با آن‌ها می‌توانیم تصاویری زیبا، تغییر پذیر، قابل تم‌دهی و تعاملی ایجاد کنیم. در این پست من به بررسی این تکنیک‌ها خواهم پرداخت: استفاده از منابع رنگ، رنگ‌های تم، ColorStateList ها و گرادینت‌ها.

رنگ‌های ساده

ساده‌ترین راه برای رسم یک مسیر این است که یک رنگ پر/خط‌کشی شده و هارد کد شده را مشخص کنیم.

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

    <path
      android:pathData="..."
      android:fillColor="#ff00ff"
      android:strokeColor="#999"
      android:strokeWidth="2"
      android:strokeLineCap="square" />

</vector>

شما می‌توانید یکی از این ویژگی‌ها یا هر دوی آن‌ها را تعریف کنید و به ازای هر مسیر تنها یک پر/خط‌کشی کردن می‌تواند اعمال شود (بر خلاف برخی پکیج‌های گرافیکی). ابتدا پر کردنی‌ها رسم می‌شوند و سپس هر گونه خط‌کشی‌ای صورت می‌گیرد. خط‌کشی‌ها همواره مرکزی هستند (مجددا بر خلاف برخی برنامه‌های گرافیکی که اجازه‌ی خط‌کشی‌های درونی و بیرونی را هم می‌دهند)، نیاز دارند که strokeWidth مشخص شود و می‌توان در صورت تمایل strokeLineCap و strokeLineJoin را هم مشخص کرد که حالت پایان/اتصال خطوط خط‌کشی شده را کنترل می‌کنند. (همچنین strokeMiterLimit برای اتصالات خطی miter). از خط‌کشی‌های قطعه قطعه پشتیبانی نمی‌شود.

هر دو نوع پر کردنی و خط‌کشی دارای خصوصیت آلفای مستقلی هستند: fillAlpha و strokeAlpha با مقداری بین [1-0] که هر دوی آن‌ها در حالت عادی مقدار 1 را دارند، یعنی کاملا مات و تیره. اگر شما یک مقدار fillColor یا strokeColor را به همراه موجودیت آلفا مشخص کنید، این دو مقدار با هم ترکیب می‌شوند. به عنوان مثال، اگر شما یک fillColor قرمز با 50% وضوح (#80ff0000) و fillAlpha برابر با 0.5 را تعریف کنید، حاصل آن رنگ قرمز با 0.25% وضوح خواهد بود. خصوصیات آلفای مستقل تعیین ماتی و تیرگی یک مسیر را راحت‌تر می‌کنند.

منابع رنگ

وکتورهای هم برای رنگ‌های پر شده و هم خط‌کشی شده از سینتکس منبع color@ پشتیبانی می‌کنند:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

  <path
    android:pathData="..."
    android:fillColor="@color/teal"
    android:strokeColor="@color/purple"
    android:strokeWidth="2" />

</vector>

این کار اصلاحات را برای شما آسان‌تر می‌کند و باعث می‌شود بتوانید برنامه را بر روی یک طیف رنگی یکدست نگه دارید.

همچنین این کار شما را مقدور می‌سازد که با استفاده از توصیف کننده‌های منبع اندروید، مقادیر متفاوت رنگ را در وضعیت‌های مختلف به کار گیرید. به عنوان مثال، شما می‌توانید برای حالت شب برنامه‌ی خود مقادیر رنگی جایگزینی تعیین کنید (res/colors-night/colors.xml) یا اگر دستگاه شما از گاموت رنگی پشتیبانی می‌کند از آن بهره ببرید (res/colors-widecg/colors.xml).

رنگ‌های تم

تمامی ورژن‌های وکتورها (از API14 تا AndroidX) از استفاده از خصوصیات تم (برای مثال attr/colorPrimary?) برای تعیین رنگ‌ها پشتیبانی می‌کنند. این‌ها رنگ‌هایی هستند که توسط یک تم فراهم شده‌اند و برای ایجاد تصاویر قابل تغییری که می‌توانید در مکان‌های مختلفی از برنامه‌تان استفاده کنید بسیار مفیدند.

2 روش اصلی برای استفاده از رنگ‌های تم وجود دارد.

پر/خط‌کشی شده‌های تم‌دار

شما می‌توانید به طور مستقیم رنگ‌های تم را به مسیرهای پر شده یا خط‌کشی شده ارجاع دهید:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

  <path
    android:pathData="..."
    android:fillColor="?attr/colorPrimary" />

</vector>

در صورتی که المانی در یک تصویر دارید که می‌خواهید با توجه به تم متفاوت باشد، این مورد بسیار کاربردی است. به عنوان مثال، یک برنامه‌ی ورزشی ممکن است با توجه به رنگ تیم به عکس موقتی (placeholder) تم بدهد؛ آن هم تنها با یک drawable:

ته‌رنگ‌زنی (Tinting)

المان ریشه‌ای <vector> خصوصیات tint و tintMode را ارائه می‌دهد:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...
  android:tint="?attr/colorControlNormal">

    <path ... />

</vector>

در حالی که می‌توانید از این خصوصیات برای اعمال ته‌رنگ استاتیک استفاده کنید، این مورد در صورت ترکیب با خصوصیات تم بسیار کاربردی‌تر است. این کار به شما اجازه می‌دهد که رنگ کل تصویر را با توجه به تمی که انتخاب شده است تغییر بدهید. برای مثال، شما این امکان را دارید که با استفاده از attr/colorControlNormal? ته‌رنگ آیکون را تغییر بدهید که رنگ استاندارد را برای آیکون‌ها تعریف می‌کند و در تم‌های روشن یا تاریک متفاوت است. در این حالت شما می‌توانید یک آیکون را در صفحاتی با تم‌های متفاوت استفاده کنید.

یک مزیت استفاده از ته‌رنگ‌ها این است که شما متکی بر سازگاری رنگی اثر مبدا (معمولا از سوی طراح) به عنوان تصویر خود نیستید. اعمال یک ته‌رنگ استاندارد مانند attr/colorControlNormal? به آیکون‌ها هم باعث تم‌دهی می‌شود و هم تضمین می‌کند که محتوای موجود دقیقا به یک رنگ هستند.

خصوصیت tintMode به شما اجازه می‌دهد حالت ترکیب ته‌رنگ در drawable را تغییر دهید و از این موارد پشتیبانی می‌کند: add، multiply، screen، src_atop، src_over یا src_in؛ مطابق با معادلش PorterDuff.Mode. خصوصیت src_in معمولا چیزی است که می‌خواهید و با تصویر مانند یک ماسک آلفا برخورد می‌کند که یک ته‌رنگ را به تمام آیکون اعمال می‌کند و به هر گونه اطلاعات رنگی در مسیرهای منحصربفرد توجه‌ای نمی‌کند (البته کانال آلفا ابقاء می‌شود). به همین دلیل اگر می‌خواهید از ته‌رنگ برای آیکون‌ها استفاده کنید، بهتر است که یک رنگ پر/خط‌کشی شده‌ی کاملا مات را به کار بگیرید (مرسوم است که از #fff استفاده شود).

شاید برای‌تان سوال باشد که چه زمانی از ته‌رنگ در تصاویر استفاده کنیم و چه زمانی رنگ‌های تم را در مسیرهای منحصربفرد به کار بگیریم، زیرا هر دوی این موارد می‌توانند نتایج مشابه‌ای به همراه داشته باشند. اگر می‌خواهید از رنگ‌های تم در برخی مسیرها استفاده کنید، پس باید آن‌ها را مستقیما اعمال کنید. مورد دیگر می‌تواند این باشد که آیا در رندرینگ تصویر شما هیچ گونه هم‌پوشانی وجود دارد یا خیر. اگر این طور است، پس پر کردن آن با یک رنگ تم نیمه‌مات ممکن است تاثیری که انتظارش را دارید را تولید نکند، اما اعمال ته‌رنگ ممکن است مطابق انتظارتان عمل کند.

در نظر داشته باشید که شما می‌توانید تم مورد استفاده در drawable را یا در سطح Activity/View با خصوصیت android:theme و یا در کد با استفاده از ContextThemeWapper و یک تم بخصوص تغییر دهید.

/* Copyright 2018 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */
val themedContext = ContextThemeWrapper(context, R.style.baz)
val drawable = AppCompatResources.getDrawable(themedContext, R.drawable.vector)

ColorStateLists

در مورد پر/خط‌کشی شده‌ها VectorDrawable از ارجاع ColorStateLists پشتیبانی می‌کند. با این امکان، شما می‌توانید یک drawable بسازید که در آن مسیرها با توجه به وضعیت view/drawable (مانند لمس شده، انتخاب شده، فعال شده و غیره) تغییر رنگ بدهند.

این قابلیت در API24 معرفی شد اما به تازگی به AndroidX اضافه شده است که باعث می‌شود این قابلیت در API14 به بعد پشتیبانی شود. همچنین این مورد از متورم‌ساز (inflater) منبع ColorStateList در AndroidX استفاده می‌کند که یعنی شما این امکان را دارید که از خصوصیت‌های تم و آلفا در خود ColorStateList بهره ببرید (که خودشان در API23 به پلتفرم اضافه شده بودند).

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<selector ...>
  <item android:state_pressed="true"
    android:color="?attr/colorPrimary"
    app:alpha="0.8"/>
  <item android:color="#ec407a"/>
</selector>

در حالی که با استفاده از چندین drawable در یک StateListDrawable نیز می‌توان به نتایج مشابه‌ای دست یافت، اما اگر رندرینگ میان وضعیت‌ها تفاوت کمی داشته باشد این امر باعث کاهش دوباره‌کاری می‌شود و نگهداری آن نیز آسان‌تر است.

همچنین من طرفدار بزرگ ساختن وضعیت‌های خودم برای view های سفارشی هستم که می‌تواند با این قابلیت ترکیب شود تا المان‌های درون یک تصویر را کنترل کرد، مانند شفاف کردن مسیرها مگر این که حالت به خصوصی تنظیم شود.

گرادینت‌ها

VectorDrawable از گرادینت‌های خطی، شعاعی و جارویی (زاویه‌ای) برای پر/خط‌کشی شده‌ها پشتیبانی می‌کند. این قابلیت به واسطه AndroidX تا API14 نیز موجود است. گرادینت‌ها در فایل مخصوص خود در res/colors/ تعریف می‌شوند اما ما می‌توانیم از تکنیک منبع inline به منظور تعریف یک گرادینت درون یک وکتور استفاده کنیم – که می‌تواند آسان‌تر باشد:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>
  <path android:pathData="...">
    <aapt:attr name="android:fillColor">
      <gradient .../>
    </aapt:attr>
  </path>
</vector>

در زمان بیلد، گرادینت به منبع خودش استخراج می‌شود و یک ارجاع به آن در المان مرتبه‌ی بالاتر (parent) قرار داده می‌شود. اگر می‌خواهید از یک گرادینت چندین مرتبه استفاده کنید، بهتر است که یک بار آن را تعریف کرده و آن را ارجاع دهید، چرا که نسخه‌ی inline هر بار یک منبع از آن خواهد ساخت.

به هنگام تعیین گرادینت‌ها، هر مختصاتی در فضای viewport از المان ریشه‌ای vector قرار دارد. بگذارید به هر نوع از گرادینت‌ها و طرز استفاده از آن‌ها نگاهی داشته باشیم:

خطی

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="linear"
  android:startX="12"
  android:startY="0"
  android:endX="12"
  android:endY="24"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>

گرادینت‌های خطی می‌بایست مختصات آغاز و پایان X/Y و ”type=”linear را مشخص کنند.

شعاعی

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="radial"
  android:centerX="0"
  android:centerY="12"
  android:gradientRadius="12"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>

گرادینت‌های شعاعی می‌بایست X/Y مرکز و یک شعاع (مجددا در مختصات viewport) و ”type=”radial را مشخص کنند.

جارویی

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="sweep"
  android:centerX="0"
  android:centerY="12"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>

گرادینت‌های جارویی تنها نیاز دارند که X/Y مرکزی و ”type=”sweep را مشخص کنند.

توقف‌های رنگ

برای راحتی کار گرادینت‌ها به شما اجازه می‌دهند که startColor، centerColor، و endColor را مستقیما در خود گرادینت تعیین کنید. اگر نیاز به کنترل بیشتر یا توقف‌های رنگ بیشتری دارید می‌توانید با افزودن المان‌های item فرزند و مشخص کردن یک رنگ و آفست [0-1] به آن دست یابید.

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient ...>
  <item
    android:offset="0.0"
    android:color="#1b82bd"/>
  <item
    android:offset="0.72"
    android:color="#6f5fb8"/>
  <item
    android:offset="1.0"
    android:color="#a242b4"/>
</gradient>

حالت‌های کاشی

گرادینت‌های خطی و شعاعی (اما جارویی نه) مفهومی به عنوان کاشی‌کاری ارائه می‌دهند – یعنی اگر گرادینت به طور کامل مسیری که پر/خط‌کشی می‌کند را نپوشاند، آن وقت چه؟ حالت عادی آن clamp است که رنگ‌های آغاز و پایان را ادامه می‌دهد. اما شما می‌توانید حالت‌های کاشی repeat (تکرار) و mirror (آینه) را هم انتخاب کنید که... کاری که از نام‌شان پیداست را انجام می‌دهند! در مثال‌های پایین یک گرادینت شعاعی بر روی دایره‌ی مرکزی آبی به بنفش تعریف شده است، اما مسیر مربعی بزرگتر را پر می‌کند.

الگوها

ما می‌توانیم استفاده از توقف‌های رنگ و حالت‌های کاشی را با یکدیگر ترکیب کنیم تا به پشتیبانی از الگوهای پایه‌ای در وکتورها دست پیدا کنیم. به عنوان مثال، اگر توقف‌های رنگ همسانی را مشخص کنید، می‌توانید به تغییرات رنگی ناگهانی دست پیدا کنید. این مورد را با حالت کاشی تکراری ترکیب کنید و ما می‌توانیم یک الگوی راه راه ایجاد کنیم. به عنوان مثال، اینجا یک نماد بارگذاری وجود دارد که از یک شکل پر شده با الگو ساخته شده است. با متحرک ساختن خاصیت translateX روی گروه این الگو می‌توانیم به این افکت دست پیدا کنیم:

در نظر داشته باشید که این تکنیک بسیار متفاوت از الگوی SVG است، اما می‌تواند کاربردی باشد.

Illustration ها

گرادینت‌ها در اثرهای وکتور بزرگتر بسیار رایج‌اند. وکتورها می‌توانند گزینه‌ی خوبی برای illustration ها باشند اما به هنگام استفاده از آن‌ها در اندازه‌های بزرگ مراقب بده‌بستان‌های حافظه باشید. در ادامه مجموعه مجددا به این موضوع خواهیم پرداخت.

سایه‌ها

VectorDrawable ها از افکت‌های سایه اندازی پشتیبانی نمی‌کنند؛ با این حال می‌توان با استفاده از گرادینت‌ها به سایه‌های ساده‌ای دست پیدا کرد. به عنوان مثال این آیکون از گرادینت شعاعی برای سایه انداختن تقریبی دایره‌های سفید و از گرادینت خطی برای سایه‌ی پایین مثلث استفاده می‌کند.

مجددا، این کار با پشتیبانی کامل از سایه‌ها بسیار فاصله دارد، چرا که تنها گرادینت‌های خطی/شعاعی/جارویی می‌توانند رسم شوند و آن هم نه در طول مسیرهای دلخواه. شما می‌توانید بعضی اشکال را تا حدی تقریب بزنید؛ مخصوصا با اعمال تبدیلات به المان‌های گرادینت مانند این مثال که از خصوصیت scaleY برای تبدیل یک دایره با گرادینت شعاعی به یک شکل بیضوی استفاده می‌کند تا سایه را بسازد:

با توجه به اعداد رنگ کنید

امیدوارم که این پست نشان داده باشد که VectorDrawable ها از چندین ویژگی پیشرفته پشتیبانی می‌کنند که می‌توانید برای رندر کردن تصاویر پیچیده در برنامه‌تان یا حتی جایگزینی چند فایل با یکی برای ساخت برنامه‌های سبک‌تر از آن‌ها استفاده کنید.

پیشنهاد من این است که تمام برنامه‌ها باید از ته‌رنگ‌های رنگ تم برای آیکون‌ها استفاده کنند. ColorStateList و گرادینت کمتر استفاده می‌شوند اما اگر به آن‌ها نیاز دارید، خوب است که بدانیم وکتورها از این موارد پشتیبانی می‌کنند.

داستان سازگاری با وکتورها خوب است پس این ویژگی‌ها می‌توانند در اکثر برنامه‌ی امروزه استفاده شوند (توضیحات تکمیلی در بخش بعد).

در قسمت بعدی ماجراجویی ما در سرزمین وکتورها با ما همراه باشید.


کلیدواژه: اندروید Android Vector Drawable

منابع: medium.com

ارسال دیدگاه:
برای ارسال دیگاه باید به سیستم وارد شوید و یا ثبت نام کنید. ثبت نام چند لحظه بیشتر زمان شما را نمیگیرد.
مولف:
سالار ساری نوایی
عضو تیم تولید محتوای آرکادمی
مشاهده‌ی پروفایل
آمار و مشخصات:
event
سه شنبه ۱۱ دی ۹۷
public
arcademy.ir/+a350
favorite
۰ پسند
comment
۰ دیدگاه
group
۷۳ بازدیدکننده
visibility
۸۹ بازدید
رده های این مقاله: