How do you use EditorGUILayout.TextArea with EditorGUILayout.ScrollViewScope?

My TextArea doesn’t scroll with ScrollViewScope but it works with Begin/EndScrollView. Using the fixed sample code from TextArea:

public class TextAreaExample : EditorWindow
{
    string text = "Nothing Opened...";
    TextAsset txtAsset;
    Vector2 scroll;
    Vector2 scroll_for_scope;

    [MenuItem("Examples/TextArea usage")]
    static void Init()
    {
        TextAreaExample window = (TextAreaExample)GetWindow(typeof(TextAreaExample), true, "EditorGUILayout.TextArea");
        window.Show();
    }

    Object source;

    void OnGUI()
    {
        source = EditorGUILayout.ObjectField(source, typeof(Object), true);
        TextAsset newTxtAsset = (TextAsset)source;

        if (newTxtAsset != txtAsset)
            ReadTextAsset(newTxtAsset);

        using (new GUILayout.HorizontalScope())
        {
            using (new GUILayout.VerticalScope())
            {
                GUILayout.Label("Begin/EndScrollView");

                // original example has the GUIStyle parameters wrong, but this works.
                scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.Height(position.height - 30));
                {
                    EditorGUILayout.TextArea(text, GUILayout.ExpandHeight(true));
                }
                EditorGUILayout.EndScrollView();
            }

            using (new GUILayout.VerticalScope())
            {
                GUILayout.Label("ScrollViewScope");

                // this looks right, but doesn't scroll
                using (new EditorGUILayout.ScrollViewScope(scroll_for_scope, GUILayout.Height(position.height - 30)))
                {
                    EditorGUILayout.TextArea(text, GUILayout.ExpandHeight(true));
                }
            }
        }
    }

    void ReadTextAsset(TextAsset txt)
    {
        text = txt.text;
        txtAsset = txt;
    }
}

You need to assign scrollPosition to your Vector2 for the scrollview’s scrolling to be stored between frames. For some reason, ScrollViewScope doesn’t do this automatically.

See below for a subclass of ScrollViewScope that will do it automatically.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class TextAreaExample : EditorWindow
{
    string text = "Nothing Opened...";
    TextAsset txtAsset;
    Vector2 scroll_for_scope1;
    Vector2 scroll_for_scope2;

    [MenuItem("Examples/TextArea usage")]
    static void Init()
    {
        TextAreaExample window = (TextAreaExample)GetWindow(typeof(TextAreaExample), true, "EditorGUILayout.TextArea");
        window.Show();
    }

    Object source;

    void OnGUI()
    {
        source = EditorGUILayout.ObjectField(source, typeof(Object), true);
        TextAsset newTxtAsset = (TextAsset)source;

        if (newTxtAsset != txtAsset)
            ReadTextAsset(newTxtAsset);

        using (new GUILayout.HorizontalScope())
        {
            using (new GUILayout.VerticalScope())
            {
                GUILayout.Label("ScrollViewScope");

                using (var scope = new EditorGUILayout.ScrollViewScope(scroll_for_scope2, GUILayout.Height(position.height - 30)))
                {
                    // Assign scrollPosition to your Vector2
                    scroll_for_scope2 = scope.scrollPosition;
                    EditorGUILayout.TextArea(text, GUILayout.ExpandHeight(true));
                }
            }

            using (new GUILayout.VerticalScope())
            {
                GUILayout.Label("ScrollViewScopeSmart");

                // Use a smarter alternative. See implementation below.
                using (new ScrollViewScopeSmart(ref scroll_for_scope1, GUILayout.Height(position.height - 30)))
                {
                    EditorGUILayout.TextArea(text, GUILayout.ExpandHeight(true));
                }
            }
        }
    }

    void ReadTextAsset(TextAsset txt)
    {
        text = txt.text;
        txtAsset = txt;
    }
}

public class ScrollViewScopeSmart : EditorGUILayout.ScrollViewScope
{
    public ScrollViewScopeSmart(ref Vector2 scroll, params GUILayoutOption[] options)
        : base(scroll, options)
    {
        scroll = scrollPosition;
    }
}