Skip to content

reference:

UListView

UListView 是专门处理 以 UObject 作为父类的数据项的列表。可以认为它是一个专门为UObject 类型优化使用的ListView。

其中,它有专门处理子类是 AActor 的类型的情况。

cpp
void UListView::OnItemsChanged(const TArray<UObject*>& AddedItems, const TArray<UObject*>& RemovedItems)
{
	// Allow subclasses to do special things when objects are added or removed from the list.

	// Keep track of references to Actors and make sure to release them when Actors are about to be removed
	for (UObject* AddedItem : AddedItems)
	{
		if (AActor* AddedActor = Cast<AActor>(AddedItem))
		{
			AddedActor->OnEndPlay.AddDynamic(this, &UListView::OnListItemEndPlayed);
		}
		else if (AActor* AddedItemOuterActor = AddedItem->GetTypedOuter<AActor>())
		{
			// Unique so that we don't spam events for shared actor outers but this also means we can't
			// unsubscribe when processing RemovedItems
			AddedItemOuterActor->OnEndPlay.AddUniqueDynamic(this, &UListView::OnListItemOuterEndPlayed);
		}
	}

当Actor 被销毁的时候,会调用 OnListItemEndPlayed

cpp
void UListView::OnListItemOuterEndPlayed(AActor* ItemOuter, EEndPlayReason::Type EndPlayReason)
{
	for (int32 ItemIndex = ListItems.Num() - 1; ItemIndex >= 0; --ItemIndex)
	{
		UObject* Item = ListItems[ItemIndex];
		if (Item->IsIn(ItemOuter))
		{
			RemoveItem(Item);
		}
	}
}

也就是 当Actor 被销毁的时候会自动更新本列表同步数据。


UListViewBase

如果数据项不是UObject类型,那么选择 继承于UListViewBase,自定义一个比较好。如果是基于UListView,而数据项是FMyData的话,那么就得用UObject 来 包裹这个 FMyData。

UListViewBase本身不是模板类,如果要支持模板化,可以实现 ITypedUMGListView 接口

cpp
/**
 * Mirrored SListView<T> API for easier interaction with a bound UListViewBase widget
 * See declarations on SListView for more info on each function and event
 *
 * Note that, being a template class, this is not a UClass and therefore cannot be exposed to Blueprint.
 * If you are using UObject* items, just use (or inherit from) UListView directly
 * Otherwise, it is up to the child class to propagate events and/or expose functions to BP as needed
 *
 * Use the IMPLEMENT_TYPED_UMG_LIST() macro for the implementation boilerplate in your implementing class.
 * @see UListView for an implementation example.
 */
template <typename ItemType>
class ITypedUMGListView

FCommonNativeListItem

如果选择继承UListViewBase并自定义模板,CommonUI 提供一个更好的父类,FCommonNativeListItem

它实现了一个轻量级的运行时类型系统,性能更好。

cpp
/** 
 * Base item class for any UMG ListViews based on native, non-UObject items.
 *
 * Exclusively intended to provide bare-bones RTTI to the items to allow one array of list items to be multiple classes 
 * without needing a different, more awkward identification mechanism or an abstract virtual of every conceivable method in the base list item class
 */
class FCommonNativeListItem : public TSharedFromThis<FCommonNativeListItem>
  • RTTI 的含义:

RTTI 是 C++ 的一个特性,允许程序在运行时确定对象的类型。标准的 C++ RTTI 包括 dynamic_cast 和 typeid 操作符。

  • bare-bones RTTI:

这里的 "bare-bones" 意味着基本的、简化的。它暗示这个 RTTI 系统比标准 C++ RTTI 更加轻量和简单

它提供的一段小 demo

c++
class FMyCustomListItem : public FCommonNativeListItem
{
	DERIVED_LIST_ITEM(FMyCustomListItem, FCommonNativeListItem);
}

class FMyCustomUsualListItem : public FMyCustomListItem
{
	DERIVED_LIST_ITEM(FMyCustomUsualListItem, FMyCustomListItem);
};

class FMyCustomSpecialCaseListItem : public FMyCustomListItem
{
	DERIVED_LIST_ITEM(FMyCustomSpecialCaseListItem, FMyCustomListItem);
}; 

class UMyCustomListView : public UListViewBase, ITypedUMGListView<TSharedPtr<FMyCustomListItem>>
{
	GENERATED_BODY()
	IMPLEMENT_TYPED_UMG_LIST(TSharedPtr<FMyCustomListItem, MyListView>)

public:
	...

private:
	TSharedPtr<SListView<TSharedPtr<FMyCustomListItem>>> MyListView;
}

SListView