docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Native Integration

    App UI supports communication with the operating system through native plugins. For now plugins have been developed for the following platforms:

    • Android
    • iOS
    • Windows
    • macOS

    Screen Scale Factor

    Thanks to the Screen class from Unity, you can get information about the screen size and orientation. However we found that the relationship between the dpi and the UI Toolkit PanelSettings is different from a platform to another.

    We provide a scaleFactor property which gives an accurate scale factor that takes into account the dpi of the screen but also user-defined display scaling from the operating system.

    When you enable the Auto Scale Mode on the UI Toolkit PanelSettings, the UI elements will be scaled according to the referenceDpi value which is calculated using the scaleFactor property.

    Here is a small example of how you can use the scaleFactor property when generating custom UI elements content:

    using Unity.AppUI.Core;
    using Unity.AppUI.UI;
    using UnityEngine;
    
    class MyCustomElement : VisualElement
    {
        RenderTexture m_RT;
    
        static readonly Vertex[] k_Vertices = new Vertex[4];
        static readonly ushort[] k_Indices = { 0, 1, 2, 2, 3, 0 };
    
        static MyCustomElement()
        {
            k_Vertices[0].tint = Color.white;
            k_Vertices[1].tint = Color.white;
            k_Vertices[2].tint = Color.white;
            k_Vertices[3].tint = Color.white;
        }
    
        public MyCustomElement()
        {
            generateVisualContent += OnGenerateVisualContent;
        }
    
        void OnGenerateVisualContent(MeshGenerationContext ctx)
        {
            var rect = contentRect;
            if (!rect.IsValid())
                return;
    
            // check the current scale factor to apply on the RenderTexture
            var dpi = Mathf.Max(Platform.scaleFactor, 1f);
            var rectSize = rect.size * dpi;
    
            // create or re-create the RenderTexture if the size has changed
            if (m_RT && (Mathf.Abs(m_RT.width - rectSize.x) > 1 || Mathf.Abs(m_RT.height - rectSize.y) > 1))
            {
                m_RT.Release();
                UnityObject.Destroy(m_RT);
                m_RT = null;
            }
    
            if (!m_RT)
            {
                m_RT = new RenderTexture((int) rectSize.x, (int) rectSize.y, 24)
                {
                    hideFlags = HideFlags.HideAndDontSave,
                };
                m_RT.Create();
            }
    
            // TODO: draw the content on the RenderTexture here...
    
            // Place the RenderTexture in the MeshGenerationContext
            var left = paddingRect.xMin;
            var right = paddingRect.xMax;
            var top = paddingRect.yMin;
            var bottom = paddingRect.yMax;
    
            k_Vertices[0].position = new Vector3(left, bottom, Vertex.nearZ);
            k_Vertices[1].position = new Vector3(left, top, Vertex.nearZ);
            k_Vertices[2].position = new Vector3(right, top, Vertex.nearZ);
            k_Vertices[3].position = new Vector3(right, bottom, Vertex.nearZ);
    
            var mwd = mgc.Allocate(k_Vertices.Length, k_Indices.Length, m_RT);
    
    #if !UNITY_2023_1_OR_NEWER
            // Since the texture may be stored in an atlas, the UV coordinates need to be
            // adjusted. Simply rescale them in the provided uvRegion.
            var uvRegion = mwd.uvRegion;
    #else
            var uvRegion = new Rect(0, 0, 1, 1);
    #endif
            k_Vertices[0].uv = new Vector2(0, 0) * uvRegion.size + uvRegion.min;
            k_Vertices[1].uv = new Vector2(0, 1) * uvRegion.size + uvRegion.min;
            k_Vertices[2].uv = new Vector2(1, 1) * uvRegion.size + uvRegion.min;
            k_Vertices[3].uv = new Vector2(1, 0) * uvRegion.size + uvRegion.min;
    
            mwd.SetAllVertices(k_Vertices);
            mwd.SetAllIndices(k_Indices);
        }
    }
    

    Accessibility Features

    High-Contrast Mode

    App UI provides a highContrast property that allows you to know if the high-contrast mode is enabled.

    It is common to see apps that adapt their UI when the high-contrast mode is enabled.

    You can also subscribe to the highContrastChanged event in order to be notified when the high-contrast mode changes.

    Reduced Motion

    App UI provides a reduceMotion property that allows you to know if the reduce motion mode is enabled.

    This way you can adapt your animations to be less distracting for users who have this mode enabled.

    Text Scale Factor

    In addition to the overall screen scale, you can also get the scale of the textual elements using the textScaleFactor property.

    Layout Direction

    App UI provides a layoutDirection property that allows you to know the layout direction of the system.

    Since UI-Toolkit is based on a flexbox layout, you can use this property to adapt your UI to RTL languages (by using flexDirection: row-reverse for example).

    Dark Mode

    App UI provides a darkMode property that allows you to know if the system theme is dark or light. We also provide a darkModeChanged event that you can subscribe to in order to be notified when the system theme changes.

    It is common to see apps that let the user choose between a light and a dark theme, or stick to the system theme. You can offer the same feature by using the darkMode property.

    Here is an example using the darkMode property inside a RadioGroup:

    // Get the closest provider, assuming you call this method from a UI Toolkit element
    // contained in a hierarchy that has a ThemeContext provider
    var provider = this.GetContextProvider<ThemeContext>();
    
    // Create the callback that will be called when the system theme changes
    void OnDarkModeChanged(bool darkMode) => provider.theme = darkMode ? "dark" : "light";
    
    // Setup the RadioGroup
    var themeSwitcher = new RadioGroup();
    themeSwitcher.Add(new Radio("System") { key = "system" });
    themeSwitcher.Add(new Radio("Dark" { key = "dark" }));
    themeSwitcher.Add(new Radio("Light" { key = "light" }));
    void SetTheme()
    {
        Platform.darkModeChanged -= OnDarkModeChanged;
        if (themeSwitcher.value == "system")
        {
            Platform.systemThemeChanged += OnDarkModeChanged;
            provider.theme = Platform.darkMode ? "dark" : "light";
        }
        else
        {
            provider.theme = themeSwitcher.value;
        }
        PlayerPrefs.SetInt("theme", themeSwitcher.value);
    }
    themeSwitcher.RegisterValueChangedCallback(_ => SetTheme());
    
    // Load and set the theme value
    themeSwitcher.SetValueWithoutNotify(PlayerPrefs.GetInt("theme", "dark"));
    SetTheme();
    

    To know more about theming, see the dedicated documentation page.

    Haptic Feedback

    App UI provides a RunHapticFeedback method that allows you to trigger haptic feedback on supported platforms. For now, the only supported platforms are iOS and Android.

    Note

    In the current state of App UI components, none of them use haptic feedback directly. However, you can use this method to trigger haptic feedback when you need it.

    Clipboard

    We provide a way to interact with the Clipboard on the following platforms:

    • iOS
    • Windows
    • macOS
    • Linux

    You can use GetPasteboardData and SetPasteboardData to interact with the Clipboard.

    You can also check if the Clipboard currently contains data using the HasPasteboardData method.

    The supported formats are:

    • Text: a UTF-8 string
    • PNG: a PNG image
    Note

    On Windows platform, Text content will be automatically converted from/to Unicode (UTF-16LE). You only need to deal with UTF-8 encoding in C# code.

    // Get the text content from the clipboard
    byte[] clipboardContent = Platform.GetPasteboardData(PasteboardType.Text);
    if (clipboardContent is { Length: >0 })
    {
        string text = Encoding.UTF8.GetString(clipboardContent);
        Debug.Log($"Clipboard content: {text}");
    }
    
    // Set the text content to the clipboard
    string textToCopy = "Hello, World!";
    Platform.SetPasteboardData(PasteboardType.Text, Encoding.UTF8.GetBytes(textToCopy));
    
    // Get the image content from the clipboard
    byte[] clipboardContent = Platform.GetPasteboardData(PasteboardType.PNG);
    if (clipboardContent is { Length: >0 })
    {
        Texture2D texture = new Texture2D(2, 2);
        texture.LoadImage(clipboardContent);
        Debug.Log($"Clipboard image size: {texture.width}x{texture.height}");
    }
    
    // Set the image content to the clipboard
    Texture2D texture = new Texture2D(2, 2);
    byte[] imageBytes = texture.EncodeToPNG();
    Platform.SetPasteboardData(PasteboardType.PNG, imageBytes);
    
    In This Article
    Back to top
    Copyright © 2025 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)