Visuella teman

Teman möjliggör flexibel kontroll av UX-tillgångar som svar på olika tillståndsövergångar. Detta kan innebära att ändra en knapps färg, ändra storlek på ett element som svar på fokus osv. Ramverket för visuella teman består av två viktiga delar: 1) konfiguration och 2) körningsmotorer.

Temakonfigurationer är definitioner av egenskaper och typer medan temamotorer är klasser som använder konfigurationerna och implementerar logiken för att uppdatera transformeringar, material med mera under körning.

Temakonfiguration

Temakonfigurationer är ScriptableObjects som definierar hur temamotorer initieras vid körning. De definierar vilka egenskaper och värden som ska användas som svar på indata eller andra tillståndsändringar när appen körs. Eftersom ScriptableObjects-tillgångar kan temakonfigurationer definieras en gång och sedan användas på nytt över olika UX-komponenter.

Så här skapar du en ny Theme tillgång:

  1. Högerklicka i Project fönster
  2. Välj Create Mixed Reality Toolkit Theme (Skapa > Mixed Reality Toolkit-tema) >

Exempel på konfigurationstillgångar för tema finns under MRTK/SDK/Features/UX/Interactable/Themes .

Exempel på tema scriptableObject i kontroll

Tillstånd

När du skapar en Theme ny är det första du anger vilka tillstånd som är tillgängliga. Egenskapen Tillstånd anger hur många värden en temakonfiguration måste definiera eftersom det kommer att finnas ett värde per tillstånd. I exempelbilden ovan är standardinställningarna som definierats för komponenten Interagerande standard, Fokus, Nedtryckt och Inaktiverat. Dessa definieras i DefaultInteractableStates tillgångsfilen (Assets/MRTK/SDK/Features/UX/Interactable/States).

Så här skapar du en ny State tillgång:

  1. Högerklicka i Project fönster
  2. Välj Create Mixed Reality Toolkit State (Skapa > Mixed Reality Toolkit > State)

States ScriptableObject-exempel i inspector

Ett State ScriptableObject definierar både listan över tillstånd samt typen av StateModel som ska skapas för dessa tillstånd. En StateModel är en klass som utökar och BaseStateModel implementerar tillståndsdatorlogiken för att generera det aktuella tillståndet vid körning. Det aktuella tillståndet från den här klassen används vanligtvis av temamotorer vid körning för att avgöra vilka värden som ska anges mot materialegenskaper, GameObject-transformeringar med mera.

Egenskaper för temamotor

Utanför Tillstånd definierar en Theme tillgång även en lista över temamotorer och tillhörande egenskaper för dessa motorer. En temamotor definierar återigen logiken för att ange rätt värden mot ett GameObject vid körning.

En Theme tillgång kan definiera flera temamotorer för att uppnå avancerade övergångar av visuella tillstånd med flera GameObject-egenskaper som mål.

Temakörning

Definierar klasstypen för den temamotor som ska skapas

Lätta

Vissa temamotorer har stöd för easing mellan delstater om de definierar egenskapen IsEasingSupported som true. Det kan till exempel vara att växla mellan två färger när en tillståndsändring inträffar. Varaktigheten definierar i sekunder hur lång tid det ska gå från startvärde till slutvärde och animeringskurvan definierar ändringshastigheten under den tidsperioden.

Shader-egenskaper

Vissa temamotorer, om de definierar sin egenskap AreShadersSupported som true, ändrar vissa skuggaregenskaper vid körning. Fälten Shader och Egenskap definierar skuggningsegenskapen till målet.

Skapa en temakonfiguration via kod

I allmänhet är det enklare att utforma temakonfigurationer via Unity-kontroll, men det finns fall där teman måste genereras dynamiskt vid körning via kod. Kodfragmentet nedan ger ett exempel på hur du utför den här uppgiften.

För att påskynda utvecklingen är följande hjälpmetoder användbara för att förenkla installationen.

Interactable.GetDefaultInteractableStates()– skapar ett nytt Tillstånd ScriptableObject med de fyra standardtillståndsvärdena som används i komponenten Som kan interagera.

ThemeDefinition.GetDefaultThemeDefinition<T>() – Varje temamotor definierar en standardkonfiguration med rätt egenskaper som behövs för den temakörningstypen. Den här hjälpmotorn skapar en definition för den angivna temamotorns typ.

// This code example builds a Theme ScriptableObject that can be used with an Interactable component.
// A random color is selected for the on pressed state every time this code is executed.

// Use the default states utilized in the Interactable component
var defaultStates = Interactable.GetDefaultInteractableStates();

// Get the default configuration for the Theme engine InteractableColorTheme
var newThemeType = ThemeDefinition.GetDefaultThemeDefinition<InteractableColorTheme>().Value;

// Define a color for every state in our Default Interactable States
newThemeType.StateProperties[0].Values = new List<ThemePropertyValue>()
{
    new ThemePropertyValue() { Color = Color.black},  // Default
    new ThemePropertyValue() { Color = Color.black}, // Focus
    new ThemePropertyValue() { Color = Random.ColorHSV()},   // Pressed
    new ThemePropertyValue() { Color = Color.black},   // Disabled
};

// Create the Theme configuration asset
Theme testTheme = ScriptableObject.CreateInstance<Theme>();
testTheme.States = defaultStates;
testTheme.Definitions = new List<ThemeDefinition>() { newThemeType };

Temamotorer

En temamotor är en klass som sträcker sig från InteractableThemeBase klassen . Dessa klasser instansieras vid körning och konfigureras med ett ThemeDefinition -objekt som beskrevs tidigare.

Standardtemamotorer

MRTK levereras med en standarduppsättning temamotorer som anges nedan:

Standardtemamotorerna finns under MRTK/SDK/Features/UX/Scripts/VisualThemes/ThemeEngines .

Anpassade temamotorer

Som vi nämnt definieras en temamotor som en klass som sträcker sig från InteractableThemeBase klassen . Den nya temamotorn behöver därför bara utöka den här klassen och implementera följande:

Obligatoriska implementeringar

public abstract void SetValue(ThemeStateProperty property, int index, float percentage) (xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.SetValue)

För den angivna egenskapen, som kan identifieras av , anger du dess aktuella ThemeStateProperty.Name tillståndsvärde på målvärden för GameObject (d.v.s. ange materialfärg osv.). Indexet anger det aktuella tillståndsvärdet att komma åt och procentandelen , ett flyttal mellan 0 och 1 används för att easing/floatping mellan värden.

public abstract ThemePropertyValue GetProperty(ThemeStateProperty property)(xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.GetProperty)

För den angivna egenskapen, som kan identifieras av , returnerar du det aktuella värdet som angetts ThemeStateProperty.Name för målvärdens GameObject (d.v.s. aktuell materialfärg, aktuell lokal position förskjutning osv.). Detta används främst för cachelagring av startvärdet vid easing mellan tillstånd.

public abstract ThemeDefinition GetDefaultThemeDefinition()(xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.GetDefaultThemeDefinition)

Returnerar ThemeDefinition ett -objekt som definierar standardegenskaperna och konfigurationen som krävs för det anpassade temat

protected abstract void SetValue(ThemeStateProperty property, ThemePropertyValue value)

Skyddad variant av den offentliga definitionen, med undantag för ThemePropertyValue att ange i stället för att dirigera till att använda SetValue() index- och/eller procentkonfiguration.

InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)

Utför alla initieringssteg här för den angivna GameObject-parametern och använd de egenskaper och konfigurationer som definieras i parametern ThemeDefinition. Vi rekommenderar att du base.Init(host, settings) anropar i början av en åsidosättning.

InteractableThemeBase.IsEasingSupported

Om den anpassade temamotorn har stöd för easing mellan värden som har konfigurerats via ThemeDefinition.Easing egenskapen .

InteractableThemeBase.AreShadersSupported

Om den anpassade temamotorn har stöd för skuggaregenskaper som mål. Vi rekommenderar att du utökar från för att dra nytta av den befintliga infrastrukturen för att effektivt InteractableShaderTheme ange/hämta skuggaregenskaper via MaterialPropertyBlocks. Information om shader-egenskapen lagras i varje ThemeStateProperty via ThemeStateProperty.TargetShader och ThemeStateProperty.ShaderPropertyName .

Anteckning

Om du utökar kan det också vara användbart att åsidosätta InteractableShaderTheme InteractableShaderTheme.DefaultShaderProperty via ny.

Exempelkod: protected new const string DefaultShaderProperty = "_Color";

Dessutom utökar följande klasser nedan klassen InteractableShaderTheme som återigen använder MaterialPropertyBlocks för att ändra shader-egenskapsvärden. Den här metoden hjälper till med prestanda eftersom MaterialPropertyBlocks inte skapar nya instansmaterial när värden ändras. Åtkomst till de typiska egenskaperna för materialklassen returnerar dock inte förväntade värden. Använd MaterialPropertyBlocks för att hämta och validera aktuella egenskapsvärden för material (dvs. _Color eller _MainTex).

InteractableThemeBase.Reset

Dirigerar temat för att återställa ändrade egenskaper till sina ursprungliga värden som ställts in på värden GameObject när temamotorn initierades.

Exempel på anpassad temamotor

Klassen nedan är ett exempel på en anpassad ny temamotor. Den här implementeringen hittar en MeshRenderer-komponent på det initierade värdobjektet och styr dess synlighet baserat på det aktuella tillståndet.

using Microsoft.MixedReality.Toolkit.UI;
using System;
using System.Collections.Generic;
using UnityEngine;

// This class demonstrates a custom theme to control a Host's MeshRenderer visibility
public class MeshVisibilityTheme : InteractableThemeBase
{
    // Bool visibility does not make sense for lerping
    public override bool IsEasingSupported => false;

    // No material or shaders are being modified
    public override bool AreShadersSupported => false;

    // Cache reference to the MeshRenderer component on our Host
    private MeshRenderer meshRenderer;

    public MeshVisibilityTheme()
    {
        Types = new Type[] { typeof(MeshRenderer) };
        Name = "Mesh Visibility Theme";
    }

    // Define a default configuration to simplify initialization of this theme engine
    // There is only one state property with a value per available state
    // This state property is a boolean that defines whether the renderer is enabled
    public override ThemeDefinition GetDefaultThemeDefinition()
    {
        return new ThemeDefinition()
        {
            ThemeType = GetType(),
            StateProperties = new List<ThemeStateProperty>()
            {
                new ThemeStateProperty()
                {
                    Name = "Mesh Visible",
                    Type = ThemePropertyTypes.Bool,
                    Values = new List<ThemePropertyValue>(),
                    Default = new ThemePropertyValue() { Bool = true }
                },
            },
            CustomProperties = new List<ThemeProperty>()
        };
    }

    // When initializing, cache a reference to the MeshRenderer component
    public override void Init(GameObject host, ThemeDefinition definition)
    {
        base.Init(host, definition);

        meshRenderer = host.GetComponent<MeshRenderer>();
    }

    // Get the current state of the MeshRenderer visibility
    public override ThemePropertyValue GetProperty(ThemeStateProperty property)
    {
        return new ThemePropertyValue()
        {
            Bool = meshRenderer.enabled
        };
    }

    // Update the MeshRenderer visibility based on the property state value data
    public override void SetValue(ThemeStateProperty property, int index, float percentage)
    {
        meshRenderer.enabled = property.Values[index].Bool;
    }
}

Exempel på slutpunkt till slutpunkt

Om du utökar från den anpassade temamotorn som definierades i det tidigare avsnittet visar kodexe exemplet nedan hur du styr det här temat vid körning. I synnerhet hur du ställer in det aktuella tillståndet på temat så att MeshRenderer-synligheten uppdateras på rätt sätt.

Anteckning

theme.OnUpdate(state,force) bör vanligtvis anropas i metoden Update() för att stödja temamotorer som använder easing/settping mellan värden.

using Microsoft.MixedReality.Toolkit.UI;
using System;
using System.Collections.Generic;
using UnityEngine;

public class MeshVisibilityController : MonoBehaviour
{
    private MeshVisibilityTheme themeEngine;
    private bool hideMesh = false;

    private void Start()
    {
        // Define the default configuration. State 0 will be on while State 1 will be off
        var themeDefinition = ThemeDefinition.GetDefaultThemeDefinition<MeshVisibilityTheme>().Value;
        themeDefinition.StateProperties[0].Values = new List<ThemePropertyValue>()
        {
            new ThemePropertyValue() { Bool = true }, // show state
            new ThemePropertyValue() { Bool = false }, // hide state
        };

        // Create the actual Theme engine and initialize it with the GameObject we are attached to
        themeEngine = (MeshVisibilityTheme)InteractableThemeBase.CreateAndInitTheme(themeDefinition, this.gameObject);
    }

    private void Update()
    {
        // Update the theme engine to set our MeshRenderer visibility
        // based on our current state (i.e the hideMesh variable)
        themeEngine.OnUpdate(Convert.ToInt32(hideMesh));
    }

    public void ToggleVisibility()
    {
        // Alternate state of visibility
        hideMesh = !hideMesh;
    }
}

Se även