After digging into UUserWidget, found that setup the widget layout in NativeOnInitialized instead of NativeConstruct(). I Post the example code here and please noted that I put the code in an folder name UI
Public/UI/SCrosshair.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "SCrosshair.generated.h"
class UImage;
class UCanvasPanel;
/**
*
*/
UCLASS()
class ACTIONROGUELIKE_API USCrosshair : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativeOnInitialized() override;
};
Private/UI/SCrosshair.cpp
#include "UI/SCrosshair.h"
#include "Blueprint/WidgetBlueprintLibrary.h"
#include "Blueprint/WidgetTree.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "Components/Image.h"
void USCrosshair::NativeOnInitialized()
{
Super::NativeOnInitialized();
auto MyCanvas = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
if(MyCanvas)
{
const FString tempIconPath = "Texture2D'/Game/UI/StyleBrush/FirstPersonCrosshair.FirstPersonCrosshair'";
UTexture2D* tempTexture = LoadObject<UTexture2D>(this,*tempIconPath);
auto CrossImage = WidgetTree->ConstructWidget<UImage>();
CrossImage->SetBrush(UWidgetBlueprintLibrary::MakeBrushFromTexture(tempTexture));
//CrossImage->SetBrushSize(FVector2D(16.0f,16.0f));
MyCanvas->AddChild(CrossImage);
const auto tempSlot = Cast<UCanvasPanelSlot>(CrossImage->Slot);
if(tempSlot)
{
tempSlot->SetAutoSize(true);
tempSlot->SetOffsets(FMargin(0,0));
tempSlot->SetAnchors(FAnchors(0.5f,0.5f));
}
WidgetTree->RootWidget = MyCanvas;
}
}