How to keep widgets on screen after changing levels

For projects using Blueprints only, you need to create a function (preferably in a Blueprint Function Library so it can be accessed from anywhere), and then call that function after you add the widget to viewport:

The input for the function is of type Widget.

If you want, you can also make a macro for it:

Now for projects that are hybrid, meaning you don’t mind adding some C++ functions for your Blueprint project you can add in an existing or new Blueprint Function Library the following:

In the .h file of the Blueprint Function Library:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Blueprint/GameViewportSubsystem.h" //You need to add this
#include "Library_Name.generated.h"

/**
 *
 */
UCLASS()
class YOUR_GAME_API ULibrary_Name : public UBlueprintFunctionLibrary
{
	UFUNCTION(BlueprintCallable, Category = "Your_Category_Name")
	static bool KeepWidget(UWidget* widget);
};

And now in .cpp file of the Blueprint Function Library:

#include "Library_Name.h"

bool ULibrary_Name::KeepWidget(UWidget* Widget)
{
	if (Widget)
	{
		if (Widget->GetWorld())
		{
			if (UGameViewportSubsystem* Subsystem = UGameViewportSubsystem::Get(Widget->GetWorld()))
			{
				FGameViewportWidgetSlot ViewportSlot = Subsystem->GetWidgetSlot(Widget);
				ViewportSlot.bAutoRemoveOnWorldRemoved = false;
				Subsystem->SetWidgetSlot(Widget, ViewportSlot);
				return true;
			}
		}
	}
	return false;
}

You can make this function void if you want, or any other type for your check in case of a problem. I choose bool, if it returns true then everything is fine and the widget will remain even after changing levels, but if it returns false there was a problem. For a more complete function with checks you can add for each if else block a different returned value so that you know what was the problem.

3 Likes