【UE】富文本块(RichTextBlock) 增加超链接支持

RichTextBlock使用方式参考官方文档:RichTextBlockUE
文档中描述了不同样式文字以及图片的使用,但没有具体说明超链接的实现,但库中有hyperlink结构。
因此照猫画虎实现,仿照RichImgDecorator实现。

  • 首先在build.cs 里增加Slate引用
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{ 
				"UMG",
				"Slate",
				"SlateCore",
			});
  • 编写SRichTextHyperlink_Ex.h文件 基于SRichTextHyperlink的拓展,增加点击回调href连接地址。
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once

#include "CoreMinimal.h"
#include "SlateGlobals.h"
#include "Input/Reply.h"
#include "Layout/Margin.h"
#include "Styling/SlateTypes.h"
#include "Framework/Text/SlateHyperlinkRun.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Styling/CoreStyle.h"
#include "Widgets/Input/SHyperlink.h"

class FWidgetViewModel;
enum class ETextShapingMethod : uint8;
DECLARE_DELEGATE_TwoParams(FHyperlinkDelegate,FString ,FString);
#if WITH_FANCY_TEXT

class SRichTextHyperlink_Ex : public SHyperlink
{
public:

	SLATE_BEGIN_ARGS(SRichTextHyperlink_Ex)
	: _Text()
	, _Href()
	, _Type()
	, _Style(&FCoreStyle::Get().GetWidgetStyle< FHyperlinkStyle >("Hyperlink"))
	, _TextStyle(nullptr)
	, _UnderlineStyle(nullptr)
	, _Delegate()
	, _Padding()
	, _OnNavigate()
	, _TextShapingMethod()
	, _TextFlowDirection()
	{}

	SLATE_ATTRIBUTE( FText, Text )
	SLATE_ARGUMENT( FString , Href )
	SLATE_ARGUMENT( FString , Type )
	SLATE_STYLE_ARGUMENT( FHyperlinkStyle, Style )
	SLATE_STYLE_ARGUMENT( FTextBlockStyle, TextStyle )
	SLATE_STYLE_ARGUMENT( FButtonStyle, UnderlineStyle )
	SLATE_ATTRIBUTE( FMargin, Padding )
	SLATE_EVENT( FSimpleDelegate, OnNavigate )
	SLATE_EVENT( FHyperlinkDelegate, Delegate )
	SLATE_ARGUMENT( TOptional<ETextShapingMethod>, TextShapingMethod )
	SLATE_ARGUMENT( TOptional<ETextFlowDirection>, TextFlowDirection )
	SLATE_END_ARGS()

public:

	void Construct( const FArguments& InArgs, const TSharedRef< FSlateHyperlinkRun::FWidgetViewModel >& InViewModel );
	

	FReply OnClicked () const;
	
	


	virtual void OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
	{
		SHyperlink::OnMouseEnter( MyGeometry, MouseEvent );
		ViewModel->SetIsHovered( true );
	}

	virtual void OnMouseLeave( const FPointerEvent& MouseEvent ) override
	{
		SHyperlink::OnMouseLeave( MouseEvent );
		ViewModel->SetIsHovered( false );
	}

	virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
	{
		FReply Reply = SHyperlink::OnMouseButtonDown( MyGeometry, MouseEvent );
		ViewModel->SetIsPressed( bIsPressed );

		return Reply;
	}

	virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
	{
		FReply Reply = SHyperlink::OnMouseButtonUp( MyGeometry, MouseEvent );
		ViewModel->SetIsPressed( bIsPressed );

		return Reply;
	}

	virtual bool IsHovered() const override
	{
		return ViewModel->IsHovered();
	}

	virtual bool IsPressed() const override
	{
		return ViewModel->IsPressed();
	}


private:
	FHyperlinkDelegate HyperDelegate;
	FString Href ;
	FString Type ;
	TSharedPtr< FSlateHyperlinkRun::FWidgetViewModel > ViewModel;
};


#endif //WITH_FANCY_TEXT

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

#pragma once

#include "CoreMinimal.h"
#include "RichTextBlockDecorator.h"
#include "SRichTextHyperlink_Ex.h"
#include "HyperlinkRichTextBlockDecorator.generated.h"



USTRUCT(Blueprintable, BlueprintType)
struct CLOUDGAME_API FRichHyperlinkRow : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(EditAnywhere, Category = Appearance)
	FHyperlinkStyle HlStyle;
};


/**
 * 
 */
UCLASS(Abstract, Blueprintable)
class CLOUDGAME_API UHyperlinkRichTextBlockDecorator : public URichTextBlockDecorator
{
	GENERATED_BODY()
public:
	UHyperlinkRichTextBlockDecorator(const FObjectInitializer& ObjectInitializer);
	
	virtual TSharedPtr<ITextDecorator> CreateDecorator(URichTextBlock* InOwner) override;
	
	virtual const FHyperlinkStyle* FindHyperlinkStyle(FName TagOrId, bool bWarnIfMissing);
	
	void OnClickHyperlink(FString Type,FString Href);
protected:
	FRichHyperlinkRow* FindHyperlinkRow(FName TagOrId, bool bWarningIfMissing);
	
	UPROPERTY(EditAnywhere, Category = Appearance, meta = (RequiredAssetDataTags = "RowStructure=RichHyperlinkRow"))
	class UDataTable* HyperlinkSet;
	
};

  • FHyperlinkRichTextDecorator.h
#pragma once

#include "CoreMinimal.h"
#include "HyperlinkRichTextBlockDecorator.h"

/**
 * 
 */
class CLOUDGAME_API FHyperlinkRichTextDecorator : public FRichTextDecorator
{
public:
	FHyperlinkRichTextDecorator(URichTextBlock* InOwner, UHyperlinkRichTextBlockDecorator* InDecorator);
	virtual bool Supports(const FTextRunParseResults& RunParseResult, const FString& Text) const override;
protected:
	virtual TSharedPtr<SWidget> CreateDecoratorWidget(const FTextRunInfo& RunInfo, const FTextBlockStyle& TextStyle) const override;
private:
	UHyperlinkRichTextBlockDecorator* Decorator;
	FHyperlinkDelegate HlDelegate;
	FString ParseName = FString("a");

};
  • SRichTextHyperlink_Ex.cpp
#include "UMG/Hyperlink/SRichTextHyperlink_Ex.h"






void SRichTextHyperlink_Ex::Construct(const FArguments& InArgs, const TSharedRef<FSlateHyperlinkRun::FWidgetViewModel>& InViewModel)
{
	ViewModel = InViewModel;
	this->HyperDelegate = InArgs._Delegate;
	this->Href = InArgs._Href;
	this->Type = InArgs._Type;
	check (InArgs._Style);
	const FButtonStyle* UnderlineStyle = InArgs._UnderlineStyle != nullptr ? InArgs._UnderlineStyle : &InArgs._Style->UnderlineStyle;
	const FTextBlockStyle* TextStyle = InArgs._TextStyle != nullptr ? InArgs._TextStyle : &InArgs._Style->TextStyle;
	TAttribute<FMargin> Padding = InArgs._Padding.IsSet() ? InArgs._Padding : InArgs._Style->Padding;

	SButton::Construct(
		SButton::FArguments()
		.Text( InArgs._Text )
		.ContentPadding( Padding )
		.ButtonStyle( UnderlineStyle )
		.TextStyle( TextStyle )
		.OnClicked(FOnClicked::CreateRaw(this,&SRichTextHyperlink_Ex::OnClicked))
		.ForegroundColor(FSlateColor::UseForeground())
		.TextShapingMethod( InArgs._TextShapingMethod )
		.TextFlowDirection( InArgs._TextFlowDirection )
	);
}

FReply SRichTextHyperlink_Ex::OnClicked() const
{
	HyperDelegate.ExecuteIfBound(Type, Href);
	return FReply::Handled();
}


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


#include "Hyperlink/HyperlinkRichTextBlockDecorator.h"

#include "GEventSubsystem.h"
#include "Hyperlink/HyperlinkRichTextDecorator.h"

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

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

const FHyperlinkStyle* UHyperlinkRichTextBlockDecorator::FindHyperlinkStyle(FName TagOrId, bool bWarnIfMissing)
{
	const FRichHyperlinkRow* HlRow = FindHyperlinkRow(TagOrId, bWarnIfMissing);
	if (HlRow)
	{
		return &HlRow->HlStyle;
	}
	
	return nullptr;
}

void UHyperlinkRichTextBlockDecorator::OnClickHyperlink( FString Type,FString Href)
{
	UE_LOG(LogTemp,Display,TEXT("OnClickHyperlink type =  %s  ; href = %s"),*Type,*Href)
	
}

FRichHyperlinkRow* UHyperlinkRichTextBlockDecorator::FindHyperlinkRow(FName TagOrId, bool bWarningIfMissing)
{
	if (HyperlinkSet)
	{
		FString ContextString;
		return HyperlinkSet->FindRow<FRichHyperlinkRow>(TagOrId, ContextString, bWarningIfMissing);
	}

	return nullptr;
}

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


#include "Hyperlink/HyperlinkRichTextDecorator.h"



FHyperlinkRichTextDecorator::FHyperlinkRichTextDecorator(URichTextBlock* InOwner, UHyperlinkRichTextBlockDecorator* InDecorator)
: FRichTextDecorator(InOwner),Decorator(InDecorator)
{
	HlDelegate.BindUObject(Decorator,&UHyperlinkRichTextBlockDecorator::OnClickHyperlink);
}

bool FHyperlinkRichTextDecorator::Supports(const FTextRunParseResults& RunParseResult, const FString& Text) const
{
	if (RunParseResult.Name == ParseName && RunParseResult.MetaData.Contains(TEXT("id")))
	{
		const FTextRange& IdRange = RunParseResult.MetaData[TEXT("id")];
		const FString TagId = Text.Mid(IdRange.BeginIndex, IdRange.EndIndex - IdRange.BeginIndex);
		const bool bWarnIfMissing = false;
		return Decorator->FindHyperlinkStyle(*TagId, bWarnIfMissing) != nullptr;
	}

	return false;
}

TSharedPtr<SWidget> FHyperlinkRichTextDecorator::CreateDecoratorWidget(const FTextRunInfo& RunInfo,
	const FTextBlockStyle& TextStyle) const
{
	const bool bWarnIfMissing = false;
	const FHyperlinkStyle* HlStyle =  Decorator->FindHyperlinkStyle(*RunInfo.MetaData[TEXT("id")], bWarnIfMissing);
	const FString* Href = RunInfo.MetaData.Find(TEXT("href"));
	const FString* Type = RunInfo.MetaData.Find(TEXT("id"));
	
	const TSharedPtr<FSlateHyperlinkRun::FWidgetViewModel> Model = MakeShareable(new FSlateHyperlinkRun::FWidgetViewModel);
	TSharedPtr<SRichTextHyperlink_Ex> HlWidget = SNew(SRichTextHyperlink_Ex,Model.ToSharedRef())
	.Text(RunInfo.Content)
	.Style(HlStyle)
	.Href(FString(*Href))
	.Type(FString(*Type))
	.Delegate(HlDelegate);

	return HlWidget;
}



  • 然后项目中引用,使用方式与richimg保持一直,创建蓝图时选择hyperlinkDecorator为父类。数据方式为:

      <a id="name" href="content">点击我</>
    

点击ui中的点击我 会打印 onclick的数据 type为name href为 content;

参考连接:
https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/UMG/UserGuide/UMGRichTextBlock/

https://forums.unrealengine.com/t/umg-richtextblock-hyperlink-href-markup/454860

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫的于

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值