Android Görünümlerinde Temel Renk Uyumu

1. Başlamadan önce

Bu codelab'de, özel renklerinizi dinamik tema tarafından oluşturulan renklerle nasıl uyumlu hale getireceğinizi öğreneceksiniz.

Ön koşullar

Geliştiriciler

  • Android'deki temel tema kavramlarına aşina olmak
  • Android widget görünümleri ve özellikleri ile rahatça çalışabilme

Neler öğreneceksiniz?

  • Birden fazla yöntem kullanarak uygulamanızda renk uyumunu kullanma
  • Uyumlaştırmanın işleyiş şekli ve renkleri değiştirme yöntemi

İhtiyacınız olanlar

  • İsterseniz Android yüklü bir bilgisayar

2. Uygulamaya Genel Bakış

Voyaĝi, dinamik tema kullanan bir toplu taşıma uygulamasıdır. Birçok toplu taşıma sisteminde renk, trenlerin, otobüslerin veya tramvayların önemli bir göstergesidir ve bunlar, mevcut dinamik birincil, ikincil veya üçüncül renklerle değiştirilemez. Çalışmamızı, renkli toplu taşıma kartlarının RecyclerView'ı üzerinde yoğunlaştıracağız.

62ff4b2fb6c9e14a.png

3. Tema oluşturma

Material 3 teması oluşturmak için ilk olarak Material Theme Builder aracımızı kullanmanızı öneririz. Özel sekmesinde artık temanıza daha fazla renk ekleyebilirsiniz. Sağ tarafta, bu renklerin renk rolleri ve ton paletleri gösterilir.

Genişletilmiş renk bölümünde renkleri kaldırabilir veya yeniden adlandırabilirsiniz.

20cc2cf72efef213.png

Dışa aktarma menüsünde, olası dışa aktarma seçenekleri gösterilir. Bu makalenin yazıldığı sırada, Material Theme Builder'ın uyumlaştırma ayarlarını özel olarak ele alma özelliği yalnızca Android Views'da kullanılabilir.

6c962ad528c09b4.png

Yeni dışa aktarma değerlerini anlama

Bu renkleri ve ilişkili renk rollerini temalarınızda uyumlaştırmayı seçip seçmemenizden bağımsız olarak kullanabilmeniz için dışa aktarılan indirme işlemine artık her özel rengin renk rolü adlarını içeren bir attrs.xml dosyası ekleniyor.

<resources>
   <attr name="colorCustom1" format="color" />
   <attr name="colorOnCustom1" format="color" />
   <attr name="colorCustom1Container" format="color" />
   <attr name="colorOnCustom1Container" format="color" />
   <attr name="harmonizeCustom1" format="boolean" />

   <attr name="colorCustom2" format="color" />
   <attr name="colorOnCustom2" format="color" />
   <attr name="colorCustom2Container" format="color" />
   <attr name="colorOnCustom2Container" format="color" />
   <attr name="harmonizeCustom2" format="boolean" />
</resources>

themes.xml dosyasında her özel renk için dört renk rolü oluşturduk (color<name>, colorOn<name>, color<name>Container, and colorOn<nameContainer>). harmonize<name> özellikleri, geliştiricinin Material Theme Builder'da seçeneği seçip seçmediğini yansıtır. Temel temadaki renk değişmez.

<resources>
   <style name="AppTheme" parent="Theme.Material3.Light.NoActionBar">
       <!--- Normal theme attributes ... -->

       <item name="colorCustom1">#006876</item>
       <item name="colorOnCustom1">#ffffff</item>
       <item name="colorCustom1Container">#97f0ff</item>
       <item name="colorOnCustom1Container">#001f24</item>
       <item name="harmonizeCustom1">false</item>

       <item name="colorCustom2">#016e00</item>
       <item name="colorOnCustom2">#ffffff</item>
       <item name="colorCustom2Container">#78ff57</item>
       <item name="colorOnCustom2Container">#002200</item>
       <item name="harmonizeCustom2">false</item>
   </style>
</resources>

colors.xml dosyasında, yukarıda listelenen renk rollerini oluşturmak için kullanılan başlangıç renkleri, renk paletinin kaydırılıp kaydırılmayacağıyla ilgili Boole değerleriyle birlikte belirtilir.

<resources>
   <!-- other colors used in theme -->

   <color name="custom1">#1AC9E0</color>
   <color name="custom2">#32D312</color>
</resources>

4. Özel Rengi İnceleme

Material Theme Builder'ın yan paneline yakınlaştırdığımızda, özel bir renk eklemenin açık ve koyu paletlerdeki dört temel renk rolünü içeren bir panel oluşturduğunu görüyoruz.

c6ee942b2b93cd92.png

Android Views'da bu renkleri sizin için dışa aktarırız ancak arka planda ColorRoles nesnesinin bir örneğiyle temsil edilebilirler.

ColorRoles sınıfının accent, onAccent, accentContainer ve onAccentContainer olmak üzere dört özelliği vardır. Bu özellikler, dört onaltılık rengin tam sayı gösterimidir.

public final class ColorRoles {

  private final int accent;
  private final int onAccent;
  private final int accentContainer;
  private final int onAccentContainer;

  // truncated code

}

MaterialColors sınıfındaki getColorRoles adlı getColorRoles işlevini kullanarak çalışma zamanında rastgele bir renkten dört temel renk rolünü alabilirsiniz. Bu işlev, belirli bir temel renk verildiğinde çalışma zamanında dört renk rolü kümesi oluşturmanıza olanak tanır.

public static ColorRoles getColorRoles(
    @NonNull Context context,
    @ColorInt int color
) { /* implementation */ }

Aynı şekilde, çıkış değerleri de gerçek renk değerleridir, bunlara yönelik işaretçiler DEĞİLDİR.**

5. Renk uyumlaştırma nedir?

Material'ın yeni renk sistemi, algoritmik bir tasarıma sahiptir. Belirli bir başlangıç renginden birincil, ikincil, üçüncül ve nötr renkler oluşturur. Dahili ve harici iş ortaklarıyla konuşurken çok sık duyduğumuz bir endişe, bazı renkleri kontrol altında tutarken dinamik renkleri nasıl kullanacağımızla ilgiliydi.

Bu renkler genellikle uygulamada belirli bir anlam veya bağlam taşır. Rastgele bir renkle değiştirildiklerinde bu anlam veya bağlam kaybolur. Aksi takdirde, bu renkler görsel olarak rahatsız edici veya uygunsuz görünebilir.

Material You'da renk; ton, kroma ve ton ile tanımlanır. Bir rengin tonu, o rengin bir renk aralığının üyesi olarak algılanmasıyla ilgilidir. Ton, rengin ne kadar açık veya koyu göründüğünü, kroma ise rengin yoğunluğunu ifade eder. Renk tonu algısı, kültürel ve dilsel faktörlerden etkilenebilir. Örneğin, eski kültürlerde mavi kelimesinin olmaması ve mavinin yeşille aynı ailede görülmesi bu faktörler arasındadır.

57c46d9974c52e4a.pngBelirli bir renk tonu, renk tonu spektrumunda bulunduğu yere bağlı olarak sıcak veya soğuk olarak kabul edilebilir. Kırmızı, turuncu veya sarı tonlara geçiş genellikle daha sıcak, mavi, yeşil veya mor tonlara geçiş ise daha soğuk olarak kabul edilir. Sıcak veya soğuk renkler arasında bile sıcak ve soğuk tonlar bulunur. Aşağıdaki örnekte, "daha sıcak" sarı, turuncuya daha yakınken "daha soğuk" sarı, yeşilden daha fazla etkilenmiştir. 597c6428ff6b9669.png

Renk uyumlaştırma algoritması, uyumlu ancak temel renk özelliklerini değiştirmeyen bir ton bulmak için kaydırılmamış rengin tonunu ve uyumlaştırılması gereken rengi inceler. İlk grafikte, spektrum üzerinde daha az uyumlu yeşil, sarı ve turuncu tonlar gösteriliyor. Bir sonraki grafikte, yeşil ve turuncu renkler sarı tonla uyumlu hale getirilmiştir. Yeni yeşil daha sıcak, yeni turuncu ise daha soğuk bir ton.

Turuncu ve yeşilin tonu değişmiş olsa da bu renkler hâlâ turuncu ve yeşil olarak algılanabiliyor.

766516c321348a7c.png

Tasarım kararları, keşifler ve değerlendirmeler hakkında daha fazla bilgi edinmek isterseniz meslektaşlarım Ayan Daniels ve Andrew Lu'nun bu bölümden biraz daha ayrıntılı bir blog yayını yazdığını belirtmek isterim.

6. Rengi manuel olarak uyumlu hale getirme

Tek bir tonu uyumlu hale getirmek için MaterialColors, harmonize ve harmonizeWithPrimary'de iki işlev bulunur.

harmonizeWithPrimary, geçerli temaya ve ardından bu temadaki birincil renge erişmek için Context öğesini kullanır.

@ColorInt
public static int harmonizeWithPrimary(@NonNull Context context, @ColorInt int colorToHarmonize) {
    return harmonize(
        colorToHarmonize,
        getColor(context, R.attr.colorPrimary, MaterialColors.class.getCanonicalName()));
  }


@ColorInt
  public static int harmonize(@ColorInt int colorToHarmonize, @ColorInt int colorToHarmonizeWith) {
    return Blend.harmonize(colorToHarmonize, colorToHarmonizeWith);
  }

Dört tonluk seti almak için biraz daha çalışmamız gerekiyor.

Kaynak rengi zaten bildiğimiz için şunları yapmamız gerekir:

  1. uyumlu hale getirilip getirilmeyeceğini belirleme,
  2. koyu modda olup olmadığımızı belirlemek ve
  3. uyumlu veya uyumsuz bir ColorRoles nesnesi döndürür.

Uyumlaştırma yapılıp yapılmayacağına karar verme

Material Theme Builder'dan dışa aktarılan temada, harmonize<Color> adlandırma kuralını kullanarak boole özellikleri ekledik. Bu değere erişmek için aşağıdaki kolaylık işlevini kullanabilirsiniz.

Bulunursa değeri döndürülür, aksi takdirde rengin uyumlu hale getirilmemesi gerektiği belirlenir.

// Looks for associated harmonization attribute based on the color id
// custom1 ===> harmonizeCustom1
fun shouldHarmonize(context: Context, colorId: Int): Boolean {
   val root = context.resources.getResourceEntryName(colorId)
   val harmonizedId = "harmonize" + root.replaceFirstChar { it.uppercaseChar() }
   
   val identifier = context.resources.getIdentifier(
           harmonizedId, "bool", context.packageName)
   
   return if (identifier != 0) context.resources.getBoolean(identifier) else false
}

Uyumlaştırılmış ColorRoles nesnesi oluşturma

retrieveHarmonizedColorRoles, yukarıda belirtilen tüm adımları birleştiren başka bir kolaylık işlevidir: adlandırılmış bir kaynağın renk değerini alma, uyumlaştırmayı belirlemek için bir Boole özelliğini çözmeye çalışma ve orijinal veya karıştırılmış renkten (açık veya koyu şema verildiğinde) türetilmiş bir ColorRoles nesnesi döndürme.

fun retrieveHarmonizedColorRoles(
   view: View,
   customId: Int,
   isLight: Boolean
): ColorRoles {
   val context = view.context
   val custom = context.getColor(customId);
  
   val shouldHarmonize = shouldHarmonize(context, customId)
   if (shouldHarmonize) {
       val blended = MaterialColors.harmonizeWithPrimary(context, custom)
       return MaterialColors.getColorRoles(blended, isLight)
   } else return MaterialColors.getColorRoles(custom, isLight)
}

7. Toplu taşıma kartlarını doldurma

Daha önce de belirttiğimiz gibi, toplu taşıma kartı koleksiyonunu doldurmak ve renklendirmek için RecyclerView ve bağdaştırıcı kullanacağız.

e4555089b065b5a7.png

Toplu taşıma verilerini saklama

Toplu taşıma kartlarının metin verilerini ve renk bilgilerini depolamak için ad, hedef ve renk kaynağı kimliğini depolayan bir veri sınıfı kullanıyoruz.

data class TransitInfo(val name: String, val destination: String, val colorId: Int)

/*  truncated code */

val transitItems = listOf(
   TransitInfo("53", "Irvine", R.color.custom1),
   TransitInfo("153", "Brea", R.color.custom1),
   TransitInfo("Orange County Line", "Oceanside", R.color.custom2),
   TransitInfo("Pacific Surfliner", "San Diego", R.color.custom2)
)

Bu rengi, ihtiyacımız olan tonları anında oluşturmak için kullanırız.

Aşağıdaki onBindViewHolder işleviyle çalışma zamanında uyum sağlayabilirsiniz.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
   val transitInfo = list.get(position)
   val color = transitInfo.colorId
   if (!colorRolesMap.containsKey(color)) {

       val roles = retrieveHarmonizedColorRoles(
           holder.itemView, color,
           !isNightMode(holder.itemView.context)
       )
       colorRolesMap.put(color, roles)
   }

   val card = holder.card
   holder.transitName.text = transitInfo.name
   holder.transitDestination.text = transitInfo.destination

   val colorRoles = colorRolesMap.get(color)
   if (colorRoles != null) {
       holder.card.setCardBackgroundColor(colorRoles.accentContainer)
       holder.transitName.setTextColor(colorRoles.onAccentContainer)
       holder.transitDestination.setTextColor(colorRoles.onAccentContainer)
   }
}

8. Renkleri otomatik olarak uyumlu hale getirme

Uyumlaştırmayı manuel olarak yapmak yerine sizin için yapılmasını sağlayabilirsiniz. HarmonizedColorOptions, şu ana kadar elle yaptığımız işlemlerin çoğunu belirtmenize olanak tanıyan bir oluşturucu sınıfıdır.

Mevcut dinamik şemaya erişebilmek için mevcut bağlamı aldıktan sonra, uyumlu hale getirmek istediğiniz temel renkleri belirtmeniz ve bu HarmonizedColorOptions nesnesine ve DynamicColors etkin bağlamına dayalı yeni bir bağlam oluşturmanız gerekir.

Bir rengi uyumlu hale getirmek istemiyorsanız bu rengi harmonizedOptions'a dahil etmeyin.

val newContext = DynamicColors.wrapContextIfAvailable(requireContext())


val harmonizedOptions = HarmonizedColorsOptions.Builder()
 .setColorResourceIds(intArrayOf(R.color.custom1, R.color.custom2))
 .build();

harmonizedContext =
 HarmonizedColors.wrapContextIfAvailable(dynamicColorsContext, harmonizedOptions)

Uyumlu temel renk zaten işlendiğinden onBindViewHolder işlevinizi yalnızca MaterialColors.getColorRoles işlevini çağıracak ve döndürülen rollerin açık mı yoksa koyu mu olması gerektiğini belirtecek şekilde güncelleyebilirsiniz.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
   /*...*/
   val color = transitInfo.colorId
   if (!colorRolesMap.containsKey(color)) {

       val roles = MaterialColors.getColorRoles(context.getColor(color), !isNightMode(context))

       )
       colorRolesMap.put(color, roles)
   }

   val card = holder.card
   holder.transitName.text = transitInfo.name
   holder.transitDestination.text = transitInfo.destination

   val colorRoles = colorRolesMap.get(color)
   if (colorRoles != null) {
       holder.card.setCardBackgroundColor(colorRoles.accentContainer)
       holder.transitName.setTextColor(colorRoles.onAccentContainer)
       holder.transitDestination.setTextColor(colorRoles.onAccentContainer)
   }
}

9. Tema özelliklerini otomatik olarak uyumlu hale getirme

Şimdiye kadar gösterilen yöntemler, renk rollerini tek bir renkten almayı temel alıyordu. Bu, gerçek bir tonun oluşturulduğunu göstermek için harika olsa da mevcut uygulamaların çoğu için gerçekçi değildir. Muhtemelen doğrudan bir renk türetmeyecek, bunun yerine mevcut bir tema özelliğini kullanacaksınız.

Bu codelab'in önceki bölümlerinde tema özelliklerini dışa aktarma konusundan bahsetmiştik.

<resources>
   <style name="AppTheme" parent="Theme.Material3.Light.NoActionBar">
       <!--- Normal theme attributes ... -->

       <item name="colorCustom1">#006876</item>
       <item name="colorOnCustom1">#ffffff</item>
       <item name="colorCustom1Container">#97f0ff</item>
       <item name="colorOnCustom1Container">#001f24</item>
       <item name="harmonizeCustom1">false</item>

       <item name="colorCustom2">#016e00</item>
       <item name="colorOnCustom2">#ffffff</item>
       <item name="colorCustom2Container">#78ff57</item>
       <item name="colorOnCustom2Container">#002200</item>
       <item name="harmonizeCustom2">false</item>
   </style>
</resources>

İlk otomatik yönteme benzer şekilde, HarmonizedColorOptions'a değerler sağlayabilir ve uyumlu renklerle bir bağlam almak için HarmonizedColors'ı kullanabiliriz. Bu iki yöntem arasında önemli bir fark vardır. Ayrıca, uyumlu hale getirilecek alanları içeren bir tema katmanı da sağlamamız gerekir.

val dynamicColorsContext = DynamicColors.wrapContextIfAvailable(requireContext())

// Harmonizing individual attributes
val harmonizedColorAttributes = HarmonizedColorAttributes.create(
 intArrayOf(
   R.attr.colorCustom1,
   R.attr.colorOnCustom1,
   R.attr.colorCustom1Container,
   R.attr.colorOnCustom1Container,
   R.attr.colorCustom2,
   R.attr.colorOnCustom2,
   R.attr.colorCustom2Container,
   R.attr.colorOnCustom2Container
 ), R.style.AppTheme_Overlay
)
val harmonizedOptions =
 HarmonizedColorsOptions.Builder().setColorAttributes(harmonizedColorAttributes).build()

val harmonizedContext =
 HarmonizedColors.wrapContextIfAvailable(dynamicColorsContext, harmonizedOptions)

Adaptörünüz, uyumlu bağlamı kullanır. Tema yer paylaşımındaki değerler, uyumlu olmayan açık veya koyu varyanta referans vermelidir.

<style name="AppTheme.Overlay" parent="AppTheme">
   <item name="colorCustom1">@color/harmonized_colorCustom1</item>
   <item name="colorOnCustom1">@color/harmonized_colorOnCustom1</item>
   <item name="colorCustom1Container">@color/harmonized_colorCustom1Container</item>
   <item name="colorOnCustom1Container">@color/harmonized_colorOnCustom1Container</item>

   <item name="colorCustom2">@color/harmonized_colorCustom2</item>
   <item name="colorOnCustom2">@color/harmonized_colorOnCustom2</item>
   <item name="colorCustom2Container">@color/harmonized_colorCustom2Container</item>
   <item name="colorOnCustom2Container">@color/harmonized_colorOnCustom2Container</item>
</style>

XML düzen dosyasında, bu uyumlu öznitelikleri normal şekilde kullanabiliriz.

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   style="?attr/materialCardViewFilledStyle"
   android:id="@+id/card"
   android:layout_width="80dp"
   android:layout_height="100dp"
   android:layout_marginStart="8dp"
   app:cardBackgroundColor="?attr/colorCustom1Container"
   >

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_margin="8dp">

       <TextView
           android:id="@+id/transitName"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:textSize="28sp"
           android:textStyle="bold"
           android:textColor="?attr/colorOnCustom1Container"
           app:layout_constraintTop_toTopOf="parent" />

       <TextView
           android:id="@+id/transitDestination"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginBottom="4dp"
           android:textColor="?attr/colorOnCustom1Container"
           app:layout_constraintBottom_toBottomOf="parent" />
   </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

10. Kaynak Kod

package com.example.voyagi.harmonization.ui.dashboard

import android.content.Context
import android.content.res.Configuration
import android.graphics.Typeface
import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.voyagi.harmonization.R
import com.example.voyagi.harmonization.databinding.FragmentDashboardBinding
import com.example.voyagi.harmonization.ui.home.TransitCardAdapter
import com.example.voyagi.harmonization.ui.home.TransitInfo
import com.google.android.material.card.MaterialCardView
import com.google.android.material.color.ColorRoles
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.HarmonizedColorAttributes
import com.google.android.material.color.HarmonizedColors
import com.google.android.material.color.HarmonizedColorsOptions
import com.google.android.material.color.MaterialColors


class DashboardFragment : Fragment() {

 enum class TransitMode { BUS, TRAIN }
 data class TransitInfo2(val name: String, val destination: String, val mode: TransitMode)

 private lateinit var dashboardViewModel: DashboardViewModel
 private var _binding: FragmentDashboardBinding? = null

 // This property is only valid between onCreateView and
 // onDestroyView.
 private val binding get() = _binding!!

 override fun onCreateView(
   inflater: LayoutInflater,
   container: ViewGroup?,
   savedInstanceState: Bundle?
 ): View? {
   dashboardViewModel =
     ViewModelProvider(this).get(DashboardViewModel::class.java)

   _binding = FragmentDashboardBinding.inflate(inflater, container, false)
   val root: View = binding.root


   val recyclerView = binding.recyclerView

   val transitItems = listOf(
     TransitInfo2("53", "Irvine", TransitMode.BUS),
     TransitInfo2("153", "Brea", TransitMode.BUS),
     TransitInfo2("Orange County Line", "Oceanside", TransitMode.TRAIN),
     TransitInfo2("Pacific Surfliner", "San Diego", TransitMode.TRAIN)
   )
  
   val dynamicColorsContext = DynamicColors.wrapContextIfAvailable(requireContext())

   // Harmonizing individual attributes
   val harmonizedColorAttributes = HarmonizedColorAttributes.create(
     intArrayOf(
       R.attr.colorCustom1,
       R.attr.colorOnCustom1,
       R.attr.colorCustom1Container,
       R.attr.colorOnCustom1Container,
       R.attr.colorCustom2,
       R.attr.colorOnCustom2,
       R.attr.colorCustom2Container,
       R.attr.colorOnCustom2Container
     ), R.style.AppTheme_Overlay
   )
   val harmonizedOptions =
     HarmonizedColorsOptions.Builder().setColorAttributes(harmonizedColorAttributes).build()

   val harmonizedContext =
     HarmonizedColors.wrapContextIfAvailable(dynamicColorsContext, harmonizedOptions)


   val adapter = TransitCardAdapterAttr(transitItems, harmonizedContext)
   recyclerView.adapter = adapter
   recyclerView.layoutManager =
     LinearLayoutManager(harmonizedContext, RecyclerView.HORIZONTAL, false)

   return root
 }

 override fun onDestroyView() {
   super.onDestroyView()
   _binding = null
 }
}

class TransitCardAdapterAttr(val list: List<DashboardFragment.TransitInfo2>, context: Context) :
 RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 val colorRolesMap = mutableMapOf<Int, ColorRoles>()
 private var harmonizedContext: Context? = context

 override fun onCreateViewHolder(
   parent: ViewGroup,
   viewType: Int
 ): RecyclerView.ViewHolder {
   return if (viewType == DashboardFragment.TransitMode.BUS.ordinal) {
     BusViewHolder(LayoutInflater.from(harmonizedContext).inflate(R.layout.transit_item_bus, parent, false))
   } else TrainViewHolder(LayoutInflater.from(harmonizedContext).inflate(R.layout.transit_item_train, parent, false))
 }

 override fun getItemCount(): Int {
   return list.size
 }

 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
   val item = list[position]
   if (item.mode.ordinal == DashboardFragment.TransitMode.BUS.ordinal) {
     (holder as BusViewHolder).bind(item)
     (holder as TransitBindable).adjustNameLength()
   } else {
       (holder as TrainViewHolder).bind(item)
       (holder as TransitBindable).adjustNameLength()
   }
 }

 override fun getItemViewType(position: Int): Int {
   return list[position].mode.ordinal
 }

 interface TransitBindable {
   val card: MaterialCardView
   var transitName: TextView
   var transitDestination: TextView

   fun bind(item: DashboardFragment.TransitInfo2) {
     transitName.text = item.name
     transitDestination.text = item.destination
   }
   fun Float.toDp(context: Context) =
     TypedValue.applyDimension(
       TypedValue.COMPLEX_UNIT_DIP,
       this,
       context.resources.displayMetrics
     )
   fun adjustNameLength(){
     if (transitName.length() > 4) {
       val layoutParams = card.layoutParams
       layoutParams.width = 100f.toDp(card.context).toInt()
       card.layoutParams = layoutParams
       transitName.setTypeface(Typeface.DEFAULT_BOLD);

       transitName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16.0f)
     }
   }
 }

 inner class BusViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), TransitBindable {
   override val card: MaterialCardView = itemView.findViewById(R.id.card)
   override var transitName: TextView = itemView.findViewById(R.id.transitName)
   override var transitDestination: TextView = itemView.findViewById(R.id.transitDestination)
 }
 inner class TrainViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), TransitBindable {
   override val card: MaterialCardView = itemView.findViewById(R.id.card)
   override var transitName: TextView = itemView.findViewById(R.id.transitName)
   override var transitDestination: TextView = itemView.findViewById(R.id.transitDestination)
 }
}

11. Örnek kullanıcı arayüzleri

Uyumlaştırma Olmadan Varsayılan Tema ve Özel Renkler

a5a02a72aef30529.png

Uyumlu Özel Renkler

4ac88011173d6753.png d5084780d2c6b886.png

dd0c8b90eccd8bef.png c51f8a677b22cd54.png

12. Özet

Bu codelab'de öğrendikleriniz:

  • Renk uyumlaştırma algoritmamızın temelleri
  • Görülen belirli bir renkten renk rolleri oluşturma
  • Kullanıcı arayüzünde bir rengi seçerek uyumlu hale getirme
  • Bir temadaki bir dizi özelliği uyumlu hale getirme

Sorularınız varsa Twitter'da@MaterialDesign hesabını kullanarak dilediğiniz zaman bize sorabilirsiniz.

youtube.com/MaterialDesign adresinde daha fazla tasarım içeriği ve eğitim bulabilirsiniz.