UE4 富文本裝飾器——超鏈接

 

遊戲裏需要超鏈接,比如點擊文字或圖片然後會彈出tips。需要實現的是文字的可點擊和超鏈接內容的讀取。

如格式<a itemId="001">物品1</>

顯示文字 物品1 然後點擊後我們能夠知道是itemId=“001”

代碼如下:

頭文件:

#pragma once

#include "Components/RichTextBlockDecorator.h"
#include "CoreMinimal.h"

#include "HyperLinkRichTextBlockDecorator.generated.h"


class FRichHyperLinkData
{
public:
	FRichHyperLinkData(UHyperLinkRichTextBlockDecorator* decorator, TMap<FString, FString> metaData);
	FSimpleDelegate m_LinkDelegate;
};

class FRichInlineHyperLinkDecorator : public FRichTextDecorator
{
public:
	FRichInlineHyperLinkDecorator(URichTextBlock* InOwner, UHyperLinkRichTextBlockDecorator* decorator);
	virtual bool Supports(const FTextRunParseResults& RunParseResult, const FString& Text) const override;

protected:
	virtual TSharedPtr<SWidget> CreateDecoratorWidget(const FTextRunInfo& RunInfo, const FTextBlockStyle& TextStyle) const override;

	void ExplodeTextStyleInfo(TMap<FString, FString>& MetaData, FSlateFontInfo& OutFont, FLinearColor& OutFontColor) const;

	UHyperLinkRichTextBlockDecorator* m_Decorator;
	mutable FHyperlinkStyle m_Linkstyle;
	mutable FSlateFontInfo m_DefaultFont;
	mutable FSlateColor m_DefaultColor;
	mutable TArray<FRichHyperLinkData> m_LinkData;
	mutable uint8 m_curLinkIndex;
	mutable FString m_Content;
};
//////////////////////////////////////////////////////////////////////////

UCLASS()
class RICHTEXTBLOCKDECORATOR_API UHyperLinkRichTextBlockDecorator : public URichTextBlockDecorator
{
	GENERATED_BODY()
public:
	UHyperLinkRichTextBlockDecorator(const FObjectInitializer& ObjectInitializer);

	virtual TSharedPtr<ITextDecorator> CreateDecorator(URichTextBlock* InOwner) override;

	UPROPERTY(EditAnywhere, Category = Appearance)
	FHyperlinkStyle m_Style;

	UFUNCTION(BlueprintNativeEvent)
	void ClickFun(const TMap<FString, FString>& metaData);
};

 

cpp文件:

#include "HyperLinkRichTextBlockDecorator.h"

#include "Components/RichTextBlockDecorator.h"
#include "Widgets/Input/SRichTextHyperlink.h"

FRichHyperLinkData::FRichHyperLinkData(UHyperLinkRichTextBlockDecorator* decorator, TMap<FString, FString> metaData)
{
	// m_Decorator = decorator;
	// m_MetaData = metaData;
	m_LinkDelegate.BindLambda([=]() {
		if (decorator)
		{
			decorator->ClickFun(metaData);
		}
	});
}

UHyperLinkRichTextBlockDecorator::UHyperLinkRichTextBlockDecorator(const FObjectInitializer& ObjectInitializer) :
	Super(ObjectInitializer)
{
}

FRichInlineHyperLinkDecorator::FRichInlineHyperLinkDecorator(URichTextBlock* InOwner, UHyperLinkRichTextBlockDecorator* decorator) :
	FRichTextDecorator(InOwner)
{
	m_Decorator = decorator;
	m_Linkstyle = decorator->m_Style;
	m_DefaultFont = m_Linkstyle.TextStyle.Font;
	m_DefaultColor = m_Linkstyle.TextStyle.ColorAndOpacity;
}

bool FRichInlineHyperLinkDecorator::Supports(const FTextRunParseResults& RunParseResult, const FString& Text) const

{
	if (RunParseResult.Name == TEXT("a"))
	{
		/*ExplodeTextStyleInfo(RunParseResult.MetaData)*/

		TMap<FString, FString> metaData;
		TArray<FString> keys;
		RunParseResult.MetaData.GetKeys(keys);
		for (int i = 0; i < keys.Num(); i++)
		{
			const FTextRange& curRange = RunParseResult.MetaData[keys[i]];
			FString valueString = Text.Mid(curRange.BeginIndex, curRange.EndIndex - curRange.BeginIndex);
			metaData.Add(keys[i], valueString);
		}

		if (metaData.Contains("font") || metaData.Contains("size") || metaData.Contains("style") || metaData.Contains("color"))
		{
			FSlateFontInfo OutFont;
			FLinearColor OutColor;
			ExplodeTextStyleInfo(metaData, OutFont, OutColor);
			m_Linkstyle.TextStyle.SetFont(OutFont);
			FSlateColor color = FSlateColor(OutColor);
			m_Linkstyle.TextStyle.ColorAndOpacity = color;
		}
		else
		{
			m_Linkstyle.TextStyle.SetFont(m_DefaultFont);
			m_Linkstyle.TextStyle.ColorAndOpacity = m_DefaultColor;
		}

		m_LinkData.Add(FRichHyperLinkData(m_Decorator, metaData));
		m_curLinkIndex = m_LinkData.Num() - 1;
		m_Content = Text.Mid(
			RunParseResult.ContentRange.BeginIndex, RunParseResult.ContentRange.EndIndex - RunParseResult.ContentRange.BeginIndex);
		return true;
	}

	return false;
}

void FRichInlineHyperLinkDecorator::ExplodeTextStyleInfo(
	TMap<FString, FString>& MetaData, FSlateFontInfo& OutFont, FLinearColor& OutFontColor) const
{
	OutFont = m_DefaultFont;

	const FString* const FontFamilyString = MetaData.Find(TEXT("font"));
	const FString* const FontSizeString = MetaData.Find(TEXT("size"));
	const FString* const FontStyleString = MetaData.Find(TEXT("style"));
	const FString* const FontColorString = MetaData.Find(TEXT("color"));

	if (FontFamilyString)
	{
		FSoftObjectPath Font(**FontFamilyString);
		if (UObject* FontAsset = Font.TryLoad())
		{
			OutFont.FontObject = FontAsset;
		}
		MetaData.Remove("font");
	}

	if (FontSizeString)
	{
		OutFont.Size = static_cast<uint8>(FPlatformString::Atoi(**FontSizeString));
		MetaData.Remove("size");
	}

	if (FontStyleString)
	{
		OutFont.TypefaceFontName = FName(**FontStyleString);
		MetaData.Remove("style");
	}

	OutFontColor = m_DefaultColor.GetSpecifiedColor();
	if (FontColorString)
	{
		const FString& FontColorStringRef = *FontColorString;

		// Is Hex color?
		if (!FontColorStringRef.IsEmpty() && FontColorStringRef[0] == TCHAR('#'))
		{
			OutFontColor = FLinearColor(FColor::FromHex(FontColorStringRef));
		}
		else if (OutFontColor.InitFromString(*FontColorString))
		{
			// Initialized
		}
		else
		{
			OutFontColor = m_DefaultColor.GetSpecifiedColor();
		}
		MetaData.Remove("color");
	}
}

TSharedPtr<SWidget> FRichInlineHyperLinkDecorator::CreateDecoratorWidget(
	const FTextRunInfo& RunInfo, const FTextBlockStyle& TextStyle) const
{
	const bool bWarnIfMissing = true;

	TSharedPtr<FSlateHyperlinkRun::FWidgetViewModel> model = MakeShareable(new FSlateHyperlinkRun::FWidgetViewModel);

	TSharedPtr<SRichTextHyperlink> link = SNew(SRichTextHyperlink, model.ToSharedRef())
											  .Text(FText::FromString(m_Content))
											  .Style(&m_Linkstyle)
											  .OnNavigate(m_LinkData[m_curLinkIndex].m_LinkDelegate);

	return link;
}

//////////////////////////////////////////////////////////////////////////

TSharedPtr<ITextDecorator> UHyperLinkRichTextBlockDecorator::CreateDecorator(URichTextBlock* InOwner)
{
	return MakeShareable(new FRichInlineHyperLinkDecorator(InOwner, this));
}

void UHyperLinkRichTextBlockDecorator::ClickFun_Implementation(const TMap<FString, FString>& metaData)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Red, "click link");
	}
}

 

外部新建藍圖繼承UHyperLinkRichTextBlockDecorator然後重載ClickFun就可以在藍圖處理超鏈接的具體內容和邏輯

如果有圖片點擊的需求參考這個和引擎自身的URichTextBlockImageDecorator寫就行了

 

如果有文字顯示不了的問題,看一下是不是沒有設置字體

參考:

1.https://answers.unrealengine.com/questions/920385/umg-richtextblock-hyperlink-href-markup.html

2.https://www.youtube.com/watch?v=m0IH4GqqZIU

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章