1. Hinweis
In diesem Codelab erfahren Sie, wie Sie Ihre benutzerdefinierten Farben mit denen abstimmen, die von einem dynamischen Design generiert werden.
Vorbereitung
Entwickelnde sollten
- Machen Sie sich mit den grundlegenden Themenkonzepten in Android vertraut.
- Praktisches Arbeiten mit Android-Widget-Ansichten und ihren Eigenschaften
Lerninhalte
- So verwenden Sie die Farbharmonisierung in Ihrer Anwendung mithilfe mehrerer Methoden
- Wie Harmonisierung funktioniert und wie sie die Farbe ändert
Voraussetzungen
- Einen Computer, auf dem Android installiert ist
2. App-Übersicht
Voyaĝi ist eine Verkehrsanwendung, die bereits ein dynamisches Design verwendet. Bei vielen Verkehrsnetzen sind Farben ein wichtiger Indikator für Züge, Busse und Straßenbahnen und können nicht durch die verfügbaren dynamischen Primär-, Sekundär- oder Tertiärfarben ersetzt werden. Wir konzentrieren uns dabei auf RecyclerView für farbige Fahrkarten.
3. Design erstellen
Wir empfehlen, als Erstes unser Tool Material Theme Builder zu verwenden, um ein Material3-Design zu erstellen. Auf dem Tab Benutzerdefiniert können Sie Ihrem Design jetzt weitere Farben hinzufügen. Rechts sehen Sie die Farbrollen und Tonpaletten für diese Farben.
Im erweiterten Farbbereich können Sie Farben entfernen oder umbenennen.
Das Exportmenü enthält eine Reihe von möglichen Exportoptionen. Zum Zeitpunkt der Entstehung dieses Artikels war die spezielle Handhabung der Harmonisierungseinstellungen von Material Theme Builder nur in Android Views verfügbar.
Informationen zu den neuen Exportwerten
Damit Sie diese Farben und die zugehörigen Farbrollen in Ihren Designs verwenden können, unabhängig davon, ob Sie sie harmonisieren möchten oder nicht, enthält der exportierte Download jetzt eine attrs.xml-Datei mit den Farbrollennamen für jede benutzerdefinierte Farbe.
<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>
In Themen.xml haben wir die vier Farbrollen für jede benutzerdefinierte Farbe (color<name>, colorOn<name>, color<name>Container, and colorOn<nameContainer>
) generiert. harmonize<name>
-Eigenschaften geben an, ob der Entwickler die Option im Material Theme Builder ausgewählt hat. Die Farbe im Hauptthema wird dadurch nicht verändert.
<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>
In der Datei colors.xml
werden die Startfarben, die zum Generieren der oben aufgeführten Farbrollen verwendet werden, zusammen mit booleschen Werten angegeben, die festlegen, ob die Farbpalette verschoben wird oder nicht.
<resources>
<!-- other colors used in theme -->
<color name="custom1">#1AC9E0</color>
<color name="custom2">#32D312</color>
</resources>
4. Benutzerdefinierte Farbe wird untersucht
Wenn wir in die Seitenleiste des Material Theme Builder hineinzoomen, sehen wir, dass durch das Hinzufügen einer benutzerdefinierten Farbe ein Steuerfeld mit den vier Hauptfarbrollen in einer hellen und einer dunklen Palette angezeigt wird.
In Android Views exportieren wir diese Farben für Sie. Im Hintergrund können sie jedoch durch eine Instanz des ColorRoles
-Objekts dargestellt werden.
Die ColorRoles-Klasse hat vier Attribute: accent
, onAccent
, accentContainer
und onAccentContainer
. Diese Eigenschaften sind die Ganzzahldarstellung der vier hexadezimalen Farben.
public final class ColorRoles {
private final int accent;
private final int onAccent;
private final int accentContainer;
private final int onAccentContainer;
// truncated code
}
Sie können zur Laufzeit die vier Hauptfarbrollen aus einer beliebigen Farbe abrufen. Verwenden Sie dazu getColorRoles
in der MaterialColors-Klasse namens getColorRoles
. Damit können Sie diesen Satz von vier Farbrollen zur Laufzeit für eine bestimmte Startfarbe erstellen.
public static ColorRoles getColorRoles(
@NonNull Context context,
@ColorInt int color
) { /* implementation */ }
Ebenso sind die Ausgabewerte die tatsächlichen Farbwerte, NICHT auf sie verweisen.**
5. Was ist Farbharmonisierung?
Das neue Farbsystem von Material basiert auf einem Algorithmus und generiert primäre, sekundäre, tertiäre und neutrale Farben aus einer bestimmten Samenfarbe. Ein Punkt, den wir in Gesprächen mit internen und externen Partnern häufig geäußert haben, war, wie wir dynamische Farben einsetzen und gleichzeitig die Kontrolle über bestimmte Farben behalten sollten.
Diese Farben haben in der Anwendung häufig eine bestimmte Bedeutung oder einen bestimmten Kontext, der verloren gehen würde, wenn sie durch eine zufällige Farbe ersetzt werden würden. Wenn Sie sie unverändert lassen, können diese Farben aber auch auffällig oder deplatziert wirken.
Farbe in Material You wird durch Farbton, Chroma und Ton beschrieben. Der Farbton bezieht sich auf die Wahrnehmung einer Farbe als Element eines Farbbereichs gegenüber einem anderen. Der Ton beschreibt, wie hell oder dunkel er erscheint, und Chroma entspricht der Intensität der Farbe. Die Wahrnehmung des Farbtons kann durch kulturelle und linguistische Faktoren beeinflusst werden, wie das häufig erwähnte fehlende Wort für Blau in alten Kulturen, wobei es stattdessen in derselben Familie wie Grün gesehen wird.
Ein bestimmter Farbton kann je nachdem, wo er innerhalb des Farbspektrums liegt, als warm oder kalt eingestuft werden. Eine Verschiebung in Richtung eines roten, orangefarbenen oder gelben Farbtons wird im Allgemeinen als wärmer zu betrachten, in Richtung eines blauen, grün oder lilafarbenen Farbtons, um ihn kühler zu machen. Auch in warmen oder kühlen Farben gibt es warme und kühle Töne. Darunter ist der „wärmere“ Gelb ist eher orange gefärbt, während das "kühlere" Gelb wird eher von Grün beeinflusst.
Der Farbharmonisierungsalgorithmus untersucht den Farbton der nicht verschobenen Farbe und die Farbe, mit der sie harmonisiert werden sollte, um einen harmonischen Farbton zu finden, der die zugrunde liegenden Farbqualitäten nicht ändert. In der ersten Grafik werden in einem Spektrum weniger harmonische Grün-, Gelb- und Orangetöne dargestellt. In der nächsten Grafik wurden Grün und Orange mit dem gelben Farbton harmoniert. Das neue Grün ist warmer und das neue Orange kühler.
Der Farbton hat sich nach Orange und Grün verschoben, kann aber immer noch als Orange und Grün wahrgenommen werden.
Wenn Sie mehr über einige Designentscheidungen, explorative Datenanalysen und Überlegungen erfahren möchten, haben meine Kollegen Ayan Daniels und Andrew Lu einen Blogpost verfasst, der etwas ausführlicher geht.
6. Manuelle Harmonisierung einer Farbe
Um einen einzelnen Ton zu harmonisieren, gibt es in MaterialColors
, harmonize
und harmonizeWithPrimary
zwei Funktionen.
harmonizeWithPrimary
verwendet Context
, um auf das aktuelle Design und anschließend seine Hauptfarbe zuzugreifen.
@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);
}
Um die vier Töne abzurufen, müssen wir ein wenig mehr anpassen.
Da die Quellfarbe bereits bekannt ist, müssen wir:
- ob es harmonisiert werden sollte,
- ob wir uns im dunklen Modus befinden
- gibt entweder ein harmonisiertes oder nicht harmonisiertes
ColorRoles
-Objekt zurück.
Entscheiden, ob eine Harmonisierung durchgeführt werden soll
In das aus Material Theme Builder exportierte Design haben wir boolesche Attribute mit der Nomenklatur harmonize<Color>
eingefügt. Unten sehen Sie eine praktische Funktion, mit der Sie auf diesen Wert zugreifen können.
Wenn der Schlüssel gefunden wird, wird der zugehörige Wert zurückgegeben. sonst wird die Farbe nicht harmonisiert.
// 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
}
Harmonisiertes ColorRoles
-Objekt erstellen
retrieveHarmonizedColorRoles
ist eine weitere praktische Funktion, die alle oben genannten Schritte kombiniert: Das Abrufen des Farbwerts für eine benannte Ressource, der Versuch, ein boolesches Attribut aufzulösen, um die Harmonisierung zu bestimmen, und ein ColorRoles
-Objekt, das von der ursprünglichen oder der gemischten Farbe (bei einem hellen oder dunklen Schema) abgeleitet ist.
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. Fahrkarten werden ausgefüllt
Wie bereits erwähnt, werden wir eine RecyclerView und einen Adapter verwenden, um die Sammlung von Fahrkarten zu füllen und einzufärben.
Daten zu öffentlichen Verkehrsmitteln speichern
Zum Speichern der Textdaten und Farbinformationen für die Fahrkarten verwenden wir eine Datenklasse, die den Namen, das Ziel und die Farbressourcen-ID speichert.
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)
)
Mit dieser Farbe erzeugen wir die benötigten Töne in Echtzeit.
Mit der folgenden onBindViewHolder
-Funktion können Sie zur Laufzeit harmonisieren.
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. Automatische Farbanpassung
Anstatt die Harmonisierung manuell durchzuführen, können Sie sie auch für Sie übernehmen. HarmonizedColorOptions ist eine Builder-Klasse, mit der Sie einen Großteil der bisher manuellen Aktionen angeben können.
Nachdem Sie den aktuellen Kontext abgerufen haben, damit Sie Zugriff auf das aktuelle dynamische Schema haben, müssen Sie die Grundfarben angeben, die Sie harmonisieren möchten, und einen neuen Kontext erstellen, der auf dem HarmonizedColorOptions-Objekt und dem für DynamicColors aktivierten Kontext basiert.
Wenn Sie eine Farbe nicht harmonisieren möchten, nehmen Sie sie einfach nicht in harmonizedOptions auf.
val newContext = DynamicColors.wrapContextIfAvailable(requireContext())
val harmonizedOptions = HarmonizedColorsOptions.Builder()
.setColorResourceIds(intArrayOf(R.color.custom1, R.color.custom2))
.build();
harmonizedContext =
HarmonizedColors.wrapContextIfAvailable(dynamicColorsContext, harmonizedOptions)
Wenn die harmonisierte Grundfarbe bereits verarbeitet wurde, können Sie den onBindViewHolder aktualisieren, um einfach MaterialColors.getColorRoles
aufzurufen und anzugeben, ob die zurückgegebenen Rollen hell oder dunkel sein sollen.
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. Automatische Harmonisierung von Designattributen
Die bisher gezeigten Methoden basieren auf dem Abrufen der Farbrollen aus einer einzelnen Farbe. Das ist gut, um zu zeigen, dass ein echter Ton erzeugt wird, der für die meisten vorhandenen Anwendungen jedoch nicht realistisch ist. Sie werden eine Farbe wahrscheinlich nicht direkt ableiten, sondern mithilfe eines vorhandenen Designattributs.
In diesem Codelab haben wir bereits über das Exportieren von Themenattributen gesprochen.
<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>
Ähnlich wie bei der ersten automatischen Methode können wir Werte für HarmonizedColorOptions bereitstellen und HarmonizedColors verwenden, um einen Kontext mit den harmonisierten Farben abzurufen. Es gibt einen wesentlichen Unterschied zwischen den beiden Methoden. Zusätzlich muss ein Design-Overlay mit den Feldern bereitgestellt werden, die harmonisiert werden sollen.
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)
Ihr Adapter würde den harmonisierten Kontext verwenden. Die Werte im Design-Overlay sollten sich auf die nicht harmonisierte helle oder dunkle Variante beziehen.
<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>
Innerhalb der XML-Layoutdatei können wir diese harmonisierten Attribute wie gewohnt verwenden.
<?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. Quellcode
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. Beispiel-UIs
Standarddesigns und benutzerdefinierte Farben ohne Harmonisierung
Harmonisierte benutzerdefinierte Farben
12. Zusammenfassung
In diesem Codelab haben Sie Folgendes gelernt:
- Die Grundlagen unseres Farbharmonisierungsalgorithmus
- So generieren Sie Farbrollen aus einer bestimmten sichtbaren Farbe.
- Wie Sie eine Farbe in einer Benutzeroberfläche selektiv harmonisieren.
- So harmonisieren Sie mehrere Attribute in einem Thema.
Wenn Sie Fragen haben, können Sie sich jederzeit unter @MaterialDesign auf Twitter an uns wenden.
Weitere Inhalte und Anleitungen zum Thema Design findest du unter youtube.com/MaterialDesign.