UE5 CommonUI的使用(附源码版)

UE5 CommonUI的使用

  • 前言
  • 快速配置
    • 配置Game Viewport Client Class
      • CommonGameViewportClient源代码
    • 创建CommonInputAction表
    • 默认导航Action设置
      • CommonUIInputData源码
    • Bind CommonInputBaseControllerData
      • CommonInputBaseControllerData源码
    • Common UI控件库和控件样式
      • CommonUserWidget 源码
    • 小结

注:此处使用版本是UE5.4,不爱看源码的朋友跳过往后翻就行,不影响使用

前言

为啥UE5要推CommonUI?

用过原生的UserWidget的朋友,应该都清楚,UE的UI输入都来自于Focus的UI,当遇到主机游戏上,要频繁切UI,切输入的时候,老会发现当前的UI没有Focus,导致界面按钮没输入,然后卡死。又或者鼠标上切到外部,再切回来的时候,会发现Focus又丢失掉了,当你点了Viewport时候,会发现输入跑到了GameViewPort上,整体UI也就丢失了输入。包括它的输入,蓝图WidgetTree里面的UI接收输入时候,它的WidgetTree拥有者,也会接收到输入,没有PlayerController里面的输入的Consume操作。当然,还有很多风格化(样式),手柄导航等诸多考校,大家可以去阅读官方文档:

官网

快速配置

配置Game Viewport Client Class

Project Setting->All Settings下搜索Game Viewport Client Class,将视口切换成CommonGameViewportClient(CommonGameViewportClient包含了有关输入内容)
在这里插入图片描述

CommonGameViewportClient源代码

跳过

.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Engine/GameViewportClient.h"
#include "CommonGameViewportClient.generated.h"

class FReply;

DECLARE_DELEGATE_FourParams(FOnRerouteInputDelegate, FInputDeviceId /* InputDeviceId */, FKey /* Key */, EInputEvent /* EventType */, FReply& /* Reply */);
DECLARE_DELEGATE_FourParams(FOnRerouteAxisDelegate, FInputDeviceId /* InputDeviceId */, FKey /* Key */, float /* Delta */, FReply& /* Reply */);
DECLARE_DELEGATE_FiveParams(FOnRerouteTouchDelegate, int32 /* ControllerId */, uint32 /* TouchId */, ETouchType::Type /* TouchType */, const FVector2D& /* TouchLocation */, FReply& /* Reply */);

/**
* CommonUI Viewport to reroute input to UI first. Needed to allow CommonUI to route / handle inputs.
*/
UCLASS(Within = Engine, transient, config = Engine)
class COMMONUI_API UCommonGameViewportClient : public UGameViewportClient
{
	GENERATED_BODY()

public:

	UCommonGameViewportClient(FVTableHelper& Helper);
	virtual ~UCommonGameViewportClient();

	// UGameViewportClient interface begin
	virtual bool InputKey(const FInputKeyEventArgs& EventArgs) override;
	virtual bool InputAxis(FViewport* InViewport, FInputDeviceId InputDevice, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad) override;
	virtual bool InputTouch(FViewport* InViewport, int32 ControllerId, uint32 Handle, ETouchType::Type Type, const FVector2D& TouchLocation, float Force, FDateTime DeviceTimestamp, uint32 TouchpadIndex) override;
	// UGameViewportClient interface end

	FOnRerouteInputDelegate& OnRerouteInput() { return RerouteInput; }
	FOnRerouteAxisDelegate& OnRerouteAxis() { return RerouteAxis; }
	FOnRerouteTouchDelegate& OnRerouteTouch() { return RerouteTouch; }

	FOnRerouteInputDelegate& OnRerouteBlockedInput() { return RerouteBlockedInput; }

	/** Default Handler for Key input. */
	UE_DEPRECATED(5.1, "This version of HandleRerouteInput has been deprecated. Please use the version that takes an FInputDeviceId instead")
	virtual void HandleRerouteInput(int32 ControllerId, FKey Key, EInputEvent EventType, FReply& Reply);

	/** Default Handler for Key input. */
	virtual void HandleRerouteInput(FInputDeviceId DeviceId, FKey Key, EInputEvent EventType, FReply& Reply);

	/** Default Handler for Axis input. */
	UE_DEPRECATED(5.1, "This version of HandleRerouteAxis has been deprecated. Please use the version that takes an FInputDeviceId instead")
	virtual void HandleRerouteAxis(int32 ControllerId, FKey Key, float Delta, FReply& Reply);

	/** Default Handler for Axis input. */
	virtual void HandleRerouteAxis(FInputDeviceId DeviceId, FKey Key, float Delta, FReply& Reply);

	/** Default Handler for Touch input. */
	virtual void HandleRerouteTouch(int32 ControllerId, uint32 TouchId, ETouchType::Type TouchType, const FVector2D& TouchLocation, FReply& Reply);

protected:
	
	/** Console window & fullscreen shortcut have higher priority than UI */
	virtual bool IsKeyPriorityAboveUI(const FInputKeyEventArgs& EventArgs);

	FOnRerouteInputDelegate RerouteInput;
	FOnRerouteAxisDelegate RerouteAxis;
	FOnRerouteTouchDelegate RerouteTouch;

	FOnRerouteInputDelegate RerouteBlockedInput;
};

#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
#include "CoreMinimal.h"
#include "Input/Reply.h"
#include "InputCoreTypes.h"
#include "InputKeyEventArgs.h"
#include "UObject/ObjectMacros.h"
#endif

.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "CommonGameViewportClient.h"
#include "Engine/Console.h"
#include "Engine/GameInstance.h"
#include "Engine/LocalPlayer.h"
#include "InputKeyEventArgs.h"

#if WITH_EDITOR
#endif // WITH_EDITOR

#include "Input/CommonUIActionRouterBase.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(CommonGameViewportClient)

#define LOCTEXT_NAMESPACE ""

static const FName NAME_Typing = FName(TEXT("Typing"));
static const FName NAME_Open = FName(TEXT("Open"));

UCommonGameViewportClient::UCommonGameViewportClient(FVTableHelper& Helper) : Super(Helper)
{
}

UCommonGameViewportClient::~UCommonGameViewportClient()
{
}

bool UCommonGameViewportClient::InputKey(const FInputKeyEventArgs& InEventArgs)
{
	FInputKeyEventArgs EventArgs = InEventArgs;

	if (IsKeyPriorityAboveUI(EventArgs))
	{
		return true;
	}

	// Check override before UI
	if (OnOverrideInputKey().IsBound())
	{
		if (OnOverrideInputKey().Execute(EventArgs))
		{
			return true;
		}
	}

	// The input is fair game for handling - the UI gets first dibs
#if !UE_BUILD_SHIPPING
	if (ViewportConsole && !ViewportConsole->ConsoleState.IsEqual(NAME_Typing) && !ViewportConsole->ConsoleState.IsEqual(NAME_Open))
#endif
	{		
		FReply Result = FReply::Unhandled();
		if (!OnRerouteInput().ExecuteIfBound(EventArgs.InputDevice, EventArgs.Key, EventArgs.Event, Result))
		{
			HandleRerouteInput(EventArgs.InputDevice, EventArgs.Key, EventArgs.Event, Result);
		}

		if (Result.IsEventHandled())
		{
			return true;
		}
	}

	return Super::InputKey(EventArgs);
}

bool UCommonGameViewportClient::InputAxis(FViewport* InViewport, FInputDeviceId InputDevice, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad)
{
	FReply RerouteResult = FReply::Unhandled();

	if (!OnRerouteAxis().ExecuteIfBound(InputDevice, Key, Delta, RerouteResult))
	{
		HandleRerouteAxis(InputDevice, Key, Delta, RerouteResult);
	}

	if (RerouteResult.IsEventHandled())
	{
		return true;
	}
	return Super::InputAxis(InViewport, InputDevice, Key, Delta, DeltaTime, NumSamples, bGamepad);
}

bool UCommonGameViewportClient::InputTouch(FViewport* InViewport, int32 ControllerId, uint32 Handle, ETouchType::Type Type, const FVector2D& TouchLocation, float Force, FDateTime DeviceTimestamp, uint32 TouchpadIndex)
{
#if !UE_BUILD_SHIPPING
	if (ViewportConsole != NULL && (ViewportConsole->ConsoleState != NAME_Typing) && (ViewportConsole->ConsoleState != NAME_Open))
#endif
	{
		FReply Result = FReply::Unhandled();
		if (!OnRerouteTouch().ExecuteIfBound(ControllerId, Handle, Type, TouchLocation, Result))
		{
			HandleRerouteTouch(ControllerId, Handle, Type, TouchLocation, Result);
		}

		if (Result.IsEventHandled())
		{
			return true;
		}
	}

	return Super::InputTouch(InViewport, ControllerId, Handle, Type, TouchLocation, Force, DeviceTimestamp, TouchpadIndex);
}

void UCommonGameViewportClient::HandleRerouteInput(FInputDeviceId DeviceId, FKey Key, EInputEvent EventType, FReply& Reply)
{
	FPlatformUserId OwningPlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(DeviceId);
	ULocalPlayer* LocalPlayer = GameInstance->FindLocalPlayerFromPlatformUserId(OwningPlatformUser);
	Reply = FReply::Unhandled();

	if (LocalPlayer)
	{
		UCommonUIActionRouterBase* ActionRouter = LocalPlayer->GetSubsystem<UCommonUIActionRouterBase>();
		if (ensure(ActionRouter))
		{
			ERouteUIInputResult InputResult = ActionRouter->ProcessInput(Key, EventType);
			if (InputResult == ERouteUIInputResult::BlockGameInput)
			{
				// We need to set the reply as handled otherwise the input won't actually be blocked from reaching the viewport.
				Reply = FReply::Handled();
				// Notify interested parties that we blocked the input.
				OnRerouteBlockedInput().ExecuteIfBound(DeviceId, Key, EventType, Reply);
			}
			else if (InputResult == ERouteUIInputResult::Handled)
			{
				Reply = FReply::Handled();
			}
		}
	}	
}

void UCommonGameViewportClient::HandleRerouteInput(int32 ControllerId, FKey Key, EInputEvent EventType, FReply& Reply)
{
	// Remap the old int32 ControllerId to the new platform user and input device ID
	FPlatformUserId UserId = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
	FInputDeviceId DeviceID = INPUTDEVICEID_NONE;
	IPlatformInputDeviceMapper::Get().RemapControllerIdToPlatformUserAndDevice(ControllerId, UserId, DeviceID);
	return HandleRerouteInput(DeviceID, Key, EventType, Reply);
}

void UCommonGameViewportClient::HandleRerouteAxis(FInputDeviceId DeviceId, FKey Key, float Delta, FReply& Reply)
{
	// Get the ownign platform user for this input device and their local player
	FPlatformUserId OwningPlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(DeviceId);
	ULocalPlayer* LocalPlayer = GameInstance->FindLocalPlayerFromPlatformUserId(OwningPlatformUser);
	
	Reply = FReply::Unhandled();

	if (LocalPlayer)
	{
		UCommonUIActionRouterBase* ActionRouter = LocalPlayer->GetSubsystem<UCommonUIActionRouterBase>();
		if (ensure(ActionRouter))
		{
			// We don't actually use axis inputs that reach the game viewport UI land for anything, we just want block them reaching the game when they shouldn't
			if (!ActionRouter->CanProcessNormalGameInput())
			{
				Reply = FReply::Handled();
			}
		}
	}
}

void UCommonGameViewportClient::HandleRerouteAxis(int32 ControllerId, FKey Key, float Delta, FReply& Reply)
{
	// Remap the old int32 ControllerId to the new platform user and input device ID
	FPlatformUserId UserId = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
	FInputDeviceId DeviceID = INPUTDEVICEID_NONE;
	IPlatformInputDeviceMapper::Get().RemapControllerIdToPlatformUserAndDevice(ControllerId, UserId, DeviceID);
	
	return HandleRerouteAxis(DeviceID, Key, Delta, Reply);
}

void UCommonGameViewportClient::HandleRerouteTouch(int32 ControllerId, uint32 TouchId, ETouchType::Type TouchType, const FVector2D& TouchLocation, FReply& Reply)
{
	ULocalPlayer* LocalPlayer = GameInstance->FindLocalPlayerFromControllerId(ControllerId);
	Reply = FReply::Unhandled();

	if (LocalPlayer && TouchId < EKeys::NUM_TOUCH_KEYS)
	{
		FKey KeyPressed = EKeys::TouchKeys[TouchId];
		if (KeyPressed.IsValid())
		{
			UCommonUIActionRouterBase* ActionRouter = LocalPlayer->GetSubsystem<UCommonUIActionRouterBase>();
			if (ensure(ActionRouter))
			{
				EInputEvent SimilarInputEvent = IE_MAX;
				switch (TouchType)
				{
				case ETouchType::Began:
					SimilarInputEvent = IE_Pressed;
					break;
				case ETouchType::Ended:
					SimilarInputEvent = IE_Released;
					break;
				default:
					SimilarInputEvent = IE_Repeat;
					break;
				}

				if (ActionRouter->ProcessInput(KeyPressed, SimilarInputEvent) != ERouteUIInputResult::Unhandled)
				{
					Reply = FReply::Handled();
				}
			}
		}
	}
}

bool UCommonGameViewportClient::IsKeyPriorityAboveUI(const FInputKeyEventArgs& EventArgs)
{
#if !UE_BUILD_SHIPPING
	// First priority goes to the viewport console regardless any state or setting
	if (ViewportConsole && ViewportConsole->InputKey(EventArgs.InputDevice, EventArgs.Key, EventArgs.Event, EventArgs.AmountDepressed, EventArgs.IsGamepad()))
	{
		return true;
	}
#endif

	// We'll also treat toggling fullscreen as a system-level sort of input that isn't affected by input filtering
	if (TryToggleFullscreenOnInputKey(EventArgs.Key, EventArgs.Event))
	{
		return true;
	}

	return false;
}

#undef LOCTEXT_NAMESPACE

创建CommonInputAction表

Common UI使用输入InputAction表来创建能够与各种平台的输入所关联的Action。

选用CommonInputActionDataBase 结构体来创建DataTable:

在这里插入图片描述
在这里插入图片描述
打开新建的DataTable,进行简单的输入配置
在这里插入图片描述
Common UI控件将这些抽象的Action映射到实际的输入。比如,你可以将数据表和RowName名称参考添加到 CommonButtonBase 控件中的 触发InputAction。之后,按下该Action所关联的按钮会触发Common UI按钮。

默认导航Action设置

虚幻引擎原生支持指向导航。但是这里,Common UI使用 CommonUIInputData来定义所有平台通用的 点击(Click) 和 返回(Back) 输Input Action。
(简单来说,就是实现多个界面打开关闭时候使用的,比如按A键打开某个界面,按B键关闭某个界面)

创建一个CommonUIInputData。
在这里插入图片描述

打开其ClassDefault,配置默认的点击与返回Action
在这里插入图片描述
此前我在DataTable里创建了俩测试按键配置
在这里插入图片描述
ProjectSetting下搜索InputData,并配置自己的刚创建的测试的CommonUIInputData
在这里插入图片描述

CommonUIInputData源码

跳过
.h

UCLASS(Abstract, Blueprintable, ClassGroup = Input, meta = (Category = "Common Input"))
class COMMONINPUT_API UCommonUIInputData : public UObject
{
	GENERATED_BODY()

public:
	virtual bool NeedsLoadForServer() const override;

public:
	UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (RowType = "/Script/CommonUI.CommonInputActionDataBase"))
	FDataTableRowHandle DefaultClickAction;

	UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (RowType = "/Script/CommonUI.CommonInputActionDataBase"))
	FDataTableRowHandle DefaultBackAction;

	/**
    * Newly created CommonButton widgets will use these hold values by default if bRequiresHold is true.
    * Inherits from UCommonUIHoldData.
    */
    UPROPERTY(EditDefaultsOnly, Category = "Properties")
    TSoftClassPtr<UCommonUIHoldData> DefaultHoldData;

	UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (EditCondition = "CommonInput.CommonInputSettings.IsEnhancedInputSupportEnabled", EditConditionHides))
	TObjectPtr<UInputAction> EnhancedInputClickAction;

	UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (EditCondition = "CommonInput.CommonInputSettings.IsEnhancedInputSupportEnabled", EditConditionHides))
	TObjectPtr<UInputAction> EnhancedInputBackAction;
};

.cpp

bool UCommonUIInputData::NeedsLoadForServer() const
{
	const UUserInterfaceSettings* UISettings = GetDefault<UUserInterfaceSettings>();
	return UISettings->bLoadWidgetsOnDedicatedServer;
}

Bind CommonInputBaseControllerData

新建CommonInputBaseControllerData
在这里插入图片描述
在这里插入图片描述
将你的资产配置到Platform Input里面,对应平台配置对应平台内容
在这里插入图片描述
很可惜,我只看到Android、IOS、Linux、LinuxArm64、Mac、TVOS、Windows,其他平台还是需要自己写(比如Ps5、XBox,看了一圈源代码,也没找到有哪可以新增平台,虚幻会通过FProjectManager查询支持注册好的平台,如果有哪位朋友找到添加平台的方式,可以分享一波)。

查引用时候,会发现就是获取InputInfo时候会使用它,通俗来说,就是切平台时候,我们有按键提示,不同平台里面的按键不同,意味着显示不同的按键提醒图片,这时候,我们就可以考虑用它来处理。

bool FCommonInputActionDataBase::IsKeyBoundToInputActionData(const FKey& Key) const
{
	if (Key == KeyboardInputTypeInfo.GetKey() || Key == TouchInputTypeInfo.GetKey())
	{
		return true;
	}

	for (const FName& GamepadName : UCommonInputBaseControllerData::GetRegisteredGamepads())
	{
		const FCommonInputTypeInfo& TypeInfo = GetInputTypeInfo(ECommonInputType::Gamepad, GamepadName);
		if (Key == TypeInfo.GetKey())
		{
			return true;
		}
	}

	return false;
}

CommonInputBaseControllerData源码

跳过
.h

UCLASS(Abstract, Blueprintable, ClassGroup = Input, meta = (Category = "Common Input"))
class COMMONINPUT_API UCommonInputBaseControllerData : public UObject
{
	GENERATED_BODY()

public:
	virtual bool NeedsLoadForServer() const override;
	virtual bool TryGetInputBrush(FSlateBrush& OutBrush, const FKey& Key) const;
	virtual bool TryGetInputBrush(FSlateBrush& OutBrush, const TArray<FKey>& Keys) const;

	virtual void PreSave(FObjectPreSaveContext ObjectSaveContext) override;
	virtual void PostLoad() override;

private:
#if WITH_EDITORONLY_DATA
	UPROPERTY(Transient, EditAnywhere, Category = "Editor")
	int32 SetButtonImageHeightTo = 0;
#endif

public:
	UPROPERTY(EditDefaultsOnly, Category = "Default")
	ECommonInputType InputType;
	
	UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad", GetOptions = GetRegisteredGamepads))
	FName GamepadName;

	UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta = (EditCondition = "InputType == ECommonInputType::Gamepad"))
	FText GamepadDisplayName;

	UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad"))
	FText GamepadCategory;

	UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta = (EditCondition = "InputType == ECommonInputType::Gamepad"))
	FText GamepadPlatformName;

	UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad"))
	TArray<FInputDeviceIdentifierPair> GamepadHardwareIdMapping;

	UPROPERTY(EditDefaultsOnly, Category = "Display")
	TSoftObjectPtr<UTexture2D> ControllerTexture;

	UPROPERTY(EditDefaultsOnly, Category = "Display")
	TSoftObjectPtr<UTexture2D> ControllerButtonMaskTexture;

	UPROPERTY(EditDefaultsOnly, Category = "Display", Meta = (TitleProperty = "Key"))
	TArray<FCommonInputKeyBrushConfiguration> InputBrushDataMap;

	UPROPERTY(EditDefaultsOnly, Category = "Display", Meta = (TitleProperty = "Keys"))
	TArray<FCommonInputKeySetBrushConfiguration> InputBrushKeySets;

	UFUNCTION()
	static const TArray<FName>& GetRegisteredGamepads();

private:
#if WITH_EDITOR
	virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};

.cpp

 bool UCommonInputBaseControllerData::NeedsLoadForServer() const
{
	const UUserInterfaceSettings* UISettings = GetDefault<UUserInterfaceSettings>();
	return UISettings->bLoadWidgetsOnDedicatedServer;
}

bool UCommonInputBaseControllerData::TryGetInputBrush(FSlateBrush& OutBrush, const FKey& Key) const
{
	const FCommonInputKeyBrushConfiguration* DisplayConfig = InputBrushDataMap.FindByPredicate([&Key](const FCommonInputKeyBrushConfiguration& KeyBrushPair) -> bool
	{
		return KeyBrushPair.Key == Key;
	});

	if (DisplayConfig)
	{
		OutBrush = DisplayConfig->GetInputBrush();
		return true;
	}

	return false;
}

bool UCommonInputBaseControllerData::TryGetInputBrush(FSlateBrush& OutBrush, const TArray<FKey>& Keys) const
{
	if (Keys.Num() == 0)
	{
		return false;
	}

	if (Keys.Num() == 1)
	{
		return TryGetInputBrush(OutBrush, Keys[0]);
	}

	const FCommonInputKeySetBrushConfiguration* DisplayConfig = InputBrushKeySets.FindByPredicate([&Keys](const FCommonInputKeySetBrushConfiguration& KeyBrushPair) -> bool
	{
		if (KeyBrushPair.Keys.Num() < 2)
		{
			return false;
		}

		if (Keys.Num() == KeyBrushPair.Keys.Num())
		{
			for (const FKey& Key : Keys)
			{
				if (!KeyBrushPair.Keys.Contains(Key))
				{
					return false;
				}
			}

			return true;
		}

		return false;
	});

	if (DisplayConfig)
	{
		OutBrush = DisplayConfig->GetInputBrush();
		return true;
	}

	return false;
}

void UCommonInputBaseControllerData::PreSave(FObjectPreSaveContext ObjectSaveContext)
{
	Super::PreSave(ObjectSaveContext);

	if (!ObjectSaveContext.IsProceduralSave())
	{
		// These have been organized by a human already, better to sort using this array.
		TArray<FKey> AllKeys;
		EKeys::GetAllKeys(AllKeys);

		// Organize the keys so they're nice and clean
		InputBrushDataMap.Sort([&AllKeys](const FCommonInputKeyBrushConfiguration& A, const FCommonInputKeyBrushConfiguration& B) {
			return AllKeys.IndexOfByKey(A.Key) < AllKeys.IndexOfByKey(B.Key);
		});

		// Delete any brush data where we have no image assigned
		InputBrushDataMap.RemoveAll([](const FCommonInputKeyBrushConfiguration& A) {
			return A.GetInputBrush().GetResourceObject() == nullptr;
		});
	}
}

void UCommonInputBaseControllerData::PostLoad()
{
	Super::PostLoad();

#if WITH_EDITOR
	// Have to clear it even though it's transient because it's saved into the CDO.
	SetButtonImageHeightTo = 0;
#endif
}

const TArray<FName>& UCommonInputBaseControllerData::GetRegisteredGamepads()
{
	auto GenerateRegisteredGamepads = []()
	{
		TArray<FName> RegisteredGamepads;
		RegisteredGamepads.Add(FCommonInputDefaults::GamepadGeneric);

		for (const TPair<FName, FDataDrivenPlatformInfo>& Platform : FDataDrivenPlatformInfoRegistry::GetAllPlatformInfos())
		{
			const FName PlatformName = Platform.Key;
			const FDataDrivenPlatformInfo& PlatformInfo = Platform.Value;

			// Don't add fake platforms that are used to group real platforms to make configuration for groups of platforms
			// simpler.
			if (PlatformInfo.bIsFakePlatform)
			{
				continue;
			}

			// If the platform uses the standard keyboard for default input, ignore it, all of those platforms will use "PC"
			// as their target, so Windows, Linux, but not Mac.
			if (PlatformInfo.bDefaultInputStandardKeyboard)
			{
				continue;
			}

			// Only add platforms with dedicated gamepads.
			if (PlatformInfo.bHasDedicatedGamepad)
			{
				RegisteredGamepads.Add(PlatformName);
			}
		}
		return RegisteredGamepads;
	};
	static TArray<FName> RegisteredGamepads = GenerateRegisteredGamepads();
	return RegisteredGamepads;
}

#if WITH_EDITOR
void UCommonInputBaseControllerData::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
	{
		if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UCommonInputBaseControllerData, SetButtonImageHeightTo))
		{
			if (SetButtonImageHeightTo != 0)
			{
				for (FCommonInputKeyBrushConfiguration& BrushConfig : InputBrushDataMap)
				{
					FVector2D NewBrushSize = BrushConfig.KeyBrush.GetImageSize();
					if (NewBrushSize.X != 0 && NewBrushSize.Y != 0)
					{
						NewBrushSize.X = FMath::RoundToInt(SetButtonImageHeightTo * (NewBrushSize.X / NewBrushSize.Y));
						NewBrushSize.Y = SetButtonImageHeightTo;

						BrushConfig.KeyBrush.SetImageSize(NewBrushSize);
					}
				}

				for (FCommonInputKeySetBrushConfiguration& BrushConfig : InputBrushKeySets)
				{
					FVector2D NewBrushSize = BrushConfig.KeyBrush.GetImageSize();
					if (NewBrushSize.X != 0 && NewBrushSize.Y != 0)
					{
						NewBrushSize.X = FMath::RoundToInt(SetButtonImageHeightTo * (NewBrushSize.X / NewBrushSize.Y));
						NewBrushSize.Y = SetButtonImageHeightTo;

						BrushConfig.KeyBrush.SetImageSize(NewBrushSize);
					}
				}
			}

			SetButtonImageHeightTo = 0;
		}
	}
}
#endif

Common UI控件库和控件样式

CommonUI带了一些Style,在它自己的控件里面可以使用这些
在这里插入图片描述
一样的ProjectSetting里面配置Style
在这里插入图片描述

支持的控件类型:
在这里插入图片描述
CommonUIl有俩种主要有UserWdiget,一个CommonActivatableWidget,一个CommonUserWidget 。CommonUserWidget接管了原生虚幻的输入(也像PlayerController一样的方式,采用Consume的方式)。CommonActivatableWidget是继承自CommonUserWidget,它比起原生的CommonUserWidget添加了,激活的一些内容。CommonUserWidget接管了原生虚幻的输入(也像PlayerController一样的方式,采用Consume的方式)
当然,还有其他子控件:
在这里插入图片描述
CommonActivatableWidget里面带是带堆栈的,方便用于新旧界面之间的交互
在这里插入图片描述
之前的Button,也得继承CommonButtonBase使用
在这里插入图片描述

CommonUserWidget 源码

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Blueprint/UserWidget.h"
#include "Input/UIActionBindingHandle.h"

#include "CommonUserWidget.generated.h"

class UCommonInputSubsystem;
class UCommonUISubsystemBase;
class FSlateUser;

struct FUIActionTag;
struct FBindUIActionArgs;
enum class ECommonInputMode : uint8;

UCLASS(ClassGroup = UI, meta = (Category = "Common UI", DisableNativeTick))
class COMMONUI_API UCommonUserWidget : public UUserWidget
{
	GENERATED_UCLASS_BODY()

public:
	/** Sets whether or not this widget will consume ALL pointer input that reaches it */
	UFUNCTION(BlueprintCallable, Category = CommonUserWidget)
	void SetConsumePointerInput(bool bInConsumePointerInput);

	/** Add a widget to the list of widgets to get scroll events for this input root node */
	UFUNCTION(BlueprintCallable, Category = CommonUserWidget)
	void RegisterScrollRecipientExternal(const UWidget* AnalogScrollRecipient);

	/** Remove a widget from the list of widgets to get scroll events for this input root node */
	UFUNCTION(BlueprintCallable, Category = CommonUserWidget)
	void UnregisterScrollRecipientExternal(const UWidget* AnalogScrollRecipient);

public:

	const TArray<FUIActionBindingHandle>& GetActionBindings() const { return ActionBindings; }
	const TArray<TWeakObjectPtr<const UWidget>> GetScrollRecipients() const { return ScrollRecipients; }

	/**
	 * Convenience methods for menu action registrations (any UWidget can register via FCommonUIActionRouter directly, though generally that shouldn't be needed).
	 * Persistent bindings are *always* listening for input while registered, while normal bindings are only listening when all of this widget's activatable parents are activated.
	 */
	FUIActionBindingHandle RegisterUIActionBinding(const FBindUIActionArgs& BindActionArgs);

	void RemoveActionBinding(FUIActionBindingHandle ActionBinding);
	void AddActionBinding(FUIActionBindingHandle ActionBinding);

protected:
	virtual void OnWidgetRebuilt() override;
	virtual void NativeDestruct() override;
	
	virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnMouseWheel(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnMouseButtonDoubleClick(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnTouchGesture(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent) override;
	virtual FReply NativeOnTouchStarted(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent) override;
	virtual FReply NativeOnTouchMoved(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent) override;
	virtual FReply NativeOnTouchEnded(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent) override;
	
	UCommonInputSubsystem* GetInputSubsystem() const;
	UCommonUISubsystemBase* GetUISubsystem() const;
	TSharedPtr<FSlateUser> GetOwnerSlateUser() const;

	template <typename GameInstanceT = UGameInstance>
	GameInstanceT& GetGameInstanceChecked() const
	{
		GameInstanceT* GameInstance = GetGameInstance<GameInstanceT>();
		check(GameInstance);
		return *GameInstance;
	}

	template <typename PlayerControllerT = APlayerController>
	PlayerControllerT& GetOwningPlayerChecked() const
	{
		PlayerControllerT* PC = GetOwningPlayer<PlayerControllerT>();
		check(PC);
		return *PC;
	}

	void RegisterScrollRecipient(const UWidget& AnalogScrollRecipient);
	void UnregisterScrollRecipient(const UWidget& AnalogScrollRecipient);

	/** True to generally display this widget's actions in the action bar, assuming it has actions. */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = true))
	bool bDisplayInActionBar = false;

private:

	/** Set this to true if you don't want any pointer (mouse and touch) input to bubble past this widget */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = true))
	bool bConsumePointerInput = false;

private:

	TArray<FUIActionBindingHandle> ActionBindings;
	TArray<TWeakObjectPtr<const UWidget>> ScrollRecipients;
};

#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
#include "CommonUITypes.h"
#endif
// Copyright Epic Games, Inc. All Rights Reserved.

#include "CommonUserWidget.h"

#include "Engine/GameInstance.h"
#include "CommonInputSubsystem.h"
#include "CommonUISubsystemBase.h"
#include "Input/CommonUIActionRouterBase.h"
#include "Input/CommonUIInputTypes.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(CommonUserWidget)

UCommonUserWidget::UCommonUserWidget(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{	
#if WITH_EDITORONLY_DATA
	PaletteCategory = FText::FromString(TEXT("Common UI"));
#endif
}

void UCommonUserWidget::SetConsumePointerInput(bool bInConsumePointerInput)
{
	bConsumePointerInput = bInConsumePointerInput;
}

UCommonInputSubsystem* UCommonUserWidget::GetInputSubsystem() const
{
	return UCommonInputSubsystem::Get(GetOwningLocalPlayer());
}

UCommonUISubsystemBase* UCommonUserWidget::GetUISubsystem() const
{
	return UGameInstance::GetSubsystem<UCommonUISubsystemBase>(GetGameInstance());
}

TSharedPtr<FSlateUser> UCommonUserWidget::GetOwnerSlateUser() const
{
	ULocalPlayer* LocalPlayer = GetOwningLocalPlayer();
	return LocalPlayer ? LocalPlayer->GetSlateUser() : nullptr;
}

FReply UCommonUserWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
}

FReply UCommonUserWidget::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
}

FReply UCommonUserWidget::NativeOnMouseWheel(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnMouseWheel(InGeometry, InMouseEvent);
}

FReply UCommonUserWidget::NativeOnMouseButtonDoubleClick(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnMouseButtonDoubleClick(InGeometry, InMouseEvent);
}

FReply UCommonUserWidget::NativeOnTouchGesture(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnTouchGesture(InGeometry, InGestureEvent);
}

FReply UCommonUserWidget::NativeOnTouchStarted(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnTouchStarted(InGeometry, InGestureEvent);
}

FReply UCommonUserWidget::NativeOnTouchMoved(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnTouchMoved(InGeometry, InGestureEvent);
}

FReply UCommonUserWidget::NativeOnTouchEnded(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent)
{
	return bConsumePointerInput ? FReply::Handled() : Super::NativeOnTouchEnded(InGeometry, InGestureEvent);
}

FUIActionBindingHandle UCommonUserWidget::RegisterUIActionBinding(const FBindUIActionArgs& BindActionArgs)
{
	if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
	{
		FBindUIActionArgs FinalBindActionArgs = BindActionArgs;
		if (bDisplayInActionBar && !BindActionArgs.bDisplayInActionBar)
		{
			FinalBindActionArgs.bDisplayInActionBar = true;
		}
		FUIActionBindingHandle BindingHandle = ActionRouter->RegisterUIActionBinding(*this, FinalBindActionArgs);
		ActionBindings.Add(BindingHandle);
		return BindingHandle;
	}

	return FUIActionBindingHandle();
}

void UCommonUserWidget::RemoveActionBinding(FUIActionBindingHandle ActionBinding)
{
	ActionBindings.Remove(ActionBinding);
	if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
	{
		ActionRouter->RemoveBinding(ActionBinding);
	}
}

void UCommonUserWidget::AddActionBinding(FUIActionBindingHandle ActionBinding)
{
	ActionBindings.Add(ActionBinding);
	if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
	{
		ActionRouter->AddBinding(ActionBinding);
	}
}

void UCommonUserWidget::RegisterScrollRecipient(const UWidget& AnalogScrollRecipient)
{
	if (!ScrollRecipients.Contains(&AnalogScrollRecipient))
	{
		ScrollRecipients.Add(&AnalogScrollRecipient);
		if (GetCachedWidget())
		{
			if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
			{
				ActionRouter->RegisterScrollRecipient(AnalogScrollRecipient);
			}
		}
	}
}

void UCommonUserWidget::UnregisterScrollRecipient(const UWidget& AnalogScrollRecipient)
{
	if (ScrollRecipients.Remove(&AnalogScrollRecipient) && GetCachedWidget())
	{
		if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
		{
			ActionRouter->UnregisterScrollRecipient(AnalogScrollRecipient);
		}
	}
}

void UCommonUserWidget::RegisterScrollRecipientExternal(const UWidget* AnalogScrollRecipient)
{
	if (AnalogScrollRecipient != nullptr)
	{
		RegisterScrollRecipient(*AnalogScrollRecipient);
	}
}

void UCommonUserWidget::UnregisterScrollRecipientExternal(const UWidget* AnalogScrollRecipient)
{
	if (AnalogScrollRecipient != nullptr)
	{
		UnregisterScrollRecipient(*AnalogScrollRecipient);
	}
}

void UCommonUserWidget::OnWidgetRebuilt()
{
	// Using OnWidgetRebuilt instead of NativeConstruct to ensure we register ourselves with the ActionRouter before the child receives NativeConstruct
	if (!IsDesignTime())
	{
		// Clear out any invalid bindings before we bother trying to register them
		for (int32 BindingIdx = ActionBindings.Num() - 1; BindingIdx >= 0; --BindingIdx)
		{
			if (!ActionBindings[BindingIdx].IsValid())
			{
				ActionBindings.RemoveAt(BindingIdx);
			}
		}

		if (ActionBindings.Num() > 0)
		{
			if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
			{
				ActionRouter->NotifyUserWidgetConstructed(*this);
			}
		}
	}

	Super::OnWidgetRebuilt();

	if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
	{
		for (const TWeakObjectPtr<const UWidget>& WidgetPtr : GetScrollRecipients())
		{
			if (const UWidget* Widget = WidgetPtr.Get())
			{
				ActionRouter->RegisterScrollRecipient(*Widget);
			}
		}
	}
}

void UCommonUserWidget::NativeDestruct()
{
	if (ActionBindings.Num() > 0)
	{
		if (UCommonUIActionRouterBase* ActionRouter = UCommonUIActionRouterBase::Get(*this))
		{
			ActionRouter->NotifyUserWidgetDestructed(*this);
		}
	}

	Super::NativeDestruct();
}

小结

总体来说,CommonUI的使用不是很理想,相关联的配置内容也比较繁琐,使用的成本较高,支持的也不够全面,大家根据自己的需求来看把。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/653003.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度神经网络——贝叶斯与朴素贝叶斯定理

概述 贝叶斯定理是概率论中一个非常重要的概念&#xff0c;它提供了一种在已知某些相关事件的概率时&#xff0c;计算另一个事件发生概率的方法。在你提供的内容中&#xff0c;贝叶斯定理被描述为一种“魔法”&#xff0c;因为它能够使计算机通过分析大量的数据来预测人们可能…

亚马逊自养号与机刷有何区别?

在亚马逊这一全球电商巨头中&#xff0c;买家评价的重要性如同指南针般引领着消费者的购买决策。在购买前&#xff0c;消费者们往往会驻足查看产品的评论&#xff0c;仔细比较不同产品的买家口碑&#xff0c;以确保自己的选择既明智又满意。因此&#xff0c;测评成为了各大电商…

安装sbt利用开发工具IntelliJ IDEA编写Spark应用程序(Scala+SBT)参考林子雨教程

文章目录 1、安装sbt2、下载安装IDEA3、给IDEA安装中文插件4、在Intellij里安装scala插件&#xff0c;构建基于SBT的Scala项目利用SBT 添加依赖包 创建WordCount实例 1、安装sbt sbt&#xff08;Simple Build Tool&#xff09;是对Scala或Java语言进行编译的一个工具&#xff…

多态(C++)

多态(C) 本文如果有错误或者不足的地方&#xff0c;希望各位大佬多多指点。 【本文目录】 1.多态的概念2.多态的定义及实现3.抽象类4.多态的原理5.单继承和多继承的虚函数表 1.多态的概念 多态的概念就是&#xff1a;多种形态 多态就是可以有多种的形态。不同的身份去实现同一…

【JavaScript】P2 JavaScript 书写位置

本博文总结&#xff1a; JavaScript 书写位置&#xff1a; 内部外部行内 注意事项&#xff1a; 书写的位置尽量写到 </body> 之前外部 js 标签中间不写任何内容&#xff0c;因为不予以展示 正文&#xff1a; 交互效果示例 一个简单的交互效果示例&#xff1b; <…

Echarts图表库推荐以及使用Echarts实现饼图端头弧形效果

推荐Echarts图表库官方链接http://www.ppchart.com/#/ 下面是一段实现饼图端头弧形效果的Echarts代码 虽然有了上面的图表库&#xff0c;里面案例也挺多&#xff0c;但是就是没找到我想要的这种效果&#xff0c;索性就手写了一个 下面代码可以直接去我上面的图标库运行看效果…

【CTF Web】CTFShow web11 Writeup(RCE+PHP+代码审计)

web11 1 阿呆听完自己菜死了&#xff0c;自己呆了。决定修好漏洞&#xff0c;绝对不能让自己再菜死了。 解法 可知 flag 在 config.php。 <?php # flag in config.php include("config.php"); if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/system…

线性稳压电路和开关稳压电路

稳压二极管稳压电路 电网电压增大&#xff0c;导到u1端的电压增大&#xff0c;从而使输出电压&#xff0c;稳压二极管两端的电压增大&#xff0c;稳压二极管两端电压增大&#xff0c;使流过的电注增大。那么&#xff0c;流过线性电阻R的总电流增大。 Ur电压增大&#xff0c;从…

数据挖掘与机器学习——分类算法

目录 机器学习算法最普通分类&#xff1a; 分类算法的定义&#xff1a; 分类算法的应用&#xff1a; 分类器实现分类&#xff1a; 分类器的构建标准&#xff1a; 概率模型&#xff1a; 贝叶斯公式&#xff1a; 朴素贝叶斯算法&#xff08;朴素贝叶斯分类器&#xff09;…

ShardingSphere使用案例

文章目录 一、分表1. 项目架构搭建2. 数据库搭建3. 案例开发一、分库1. 创建新的库2. 修改配置文件一、分表 1. 项目架构搭建 创建Maven项目导入相关依赖<dependencies><

【头歌】计算机网络DHCP服务器配置第二关access口配置答案

头歌计算机网络DHCP服务器配置第二关access口配置操作步骤 任务描述 本关任务&#xff1a;创建 vlan &#xff0c;并且将与 pc 机相连接口划分 vlan 。 操作要求 在第一关的拓扑图的基础上&#xff0c;配置交换机&#xff0c;具体要求如下&#xff1a; 1、在特权模式下进入 vla…

WebGL技术在教育培训中的应用

WebGL技术在教育培训中的应用非常广泛&#xff0c;通过其强大的三维图形处理能力&#xff0c;能够为教育培训提供更加生动、互动和沉浸式的学习体验。以下是WebGL在教育培训中的几个主要应用及其具体实现。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xf…

萨科微和金航标

宋仕强说&#xff0c;在现代企业中&#xff0c;员工每天都会花费大量的时间在办公工具上。这些办公工具可以协助员工快速完成工作任务&#xff0c;更潜移默化地规范和影响员工的行为&#xff0c;引导他们的思考方向&#xff0c;促进公司经营目标的达成。对于萨科微kinghelm&…

C# 反射GetProperties和GetFields的坑

有时候使用反射&#xff0c;获取类的所有字段和所有属性&#xff0c;一般情况下是按照我们写的先后顺序返回的。 但是我今天碰到了一次不是按照顺序返回的&#xff01;&#xff01;&#xff01; 翻看文档&#xff1a; GetProperties&#xff1a; https://learn.microsoft.com/…

【Sql Server】随机查询一条表记录,并重重温回顾下自定义函数的封装和使用

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言随机查询语…

56. UE5 RPG 给敌人添加AI实现跟随玩家

在这一篇里&#xff0c;我们要实现一下敌人的AI&#xff0c;敌人也需要一系列的行为&#xff0c;比如朝向英雄攻击&#xff0c;移动&#xff0c;在满足条件时施放技能。这些敌人的行为可以通过使用UE的内置的AI系统去实现。 在UE里&#xff0c;只要是基于Character类创建的蓝图…

螺旋矩阵(算法题)

文章目录 螺旋矩阵解题思路 螺旋矩阵 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]解题思路 模…

YOLOv8+PyQt5动物检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

1.猫狗猴检测YOLOv8&#xff08;https://mbd.pub/o/bread/mbd-ZpaTl51u&#xff09;_哔哩哔哩_bilibili 资源包含可视化的动物检测系统&#xff0c;基于最新的YOLOv8训练的动物检测模型&#xff0c;和基于PyQt5制作的可视化动物检测系统&#xff0c;包含登陆页面、注册页面和检…

Java---Cloneable接口---浅克隆和深克隆

在Java中&#xff0c;我们如何实现一个对象的克隆呢&#xff1f; 在Java中实现对象的克隆&#xff0c;我们要用到Cloneable接口。克隆也分为浅克隆和深克隆。 1.实现浅克隆 1.重写clone方法 当我们想直接通过前面已经建立好的对象来调用Object类中的clone方法时&#xff0c;…

摸鱼大数据——Hive表操作——分区表

1、介绍 特点: 分区表会在HDFS上产生目录。查询数据的时候使用分区字段筛选数据&#xff0c;可以避免全表扫描&#xff0c;从而提升查询效率 注意: 如果是分区表&#xff0c;在查询数据的时候&#xff0c;如果没有使用分区字段&#xff0c;它回去进行全表扫描&#xff0c;会降低…