diff --git a/frameworks/bridge/declarative_frontend/ark_component/export/arkComponent.d.ts b/frameworks/bridge/declarative_frontend/ark_component/export/arkComponent.d.ts index 1603eb8711288d368c17cb2bc917018e54b29e7c..d00c0e6eddbeb62fe77d59d7031ae0fb706563a8 100644 --- a/frameworks/bridge/declarative_frontend/ark_component/export/arkComponent.d.ts +++ b/frameworks/bridge/declarative_frontend/ark_component/export/arkComponent.d.ts @@ -1742,6 +1742,7 @@ declare class ArkListComponent extends ArkComponent implements ListAttribute { onScrollFrameBegin(event: (offset: number, state: ScrollState) => { offsetRemain: number; }): this; + fadingEdge(value: boolean): this; } declare class ArkListItemComponent extends ArkComponent implements ListItemAttribute { constructor(nativePtr: KNode, classType?: ModifierType); diff --git a/frameworks/bridge/declarative_frontend/ark_component/src/ArkList.ts b/frameworks/bridge/declarative_frontend/ark_component/src/ArkList.ts index 5eb8ce65981dca4c5342053f9dec905ece15074c..b3b205004b182fea5a6c6d72a1cc59843c219a8f 100644 --- a/frameworks/bridge/declarative_frontend/ark_component/src/ArkList.ts +++ b/frameworks/bridge/declarative_frontend/ark_component/src/ArkList.ts @@ -315,6 +315,20 @@ class ListClipModifier extends ModifierWithKey { } } +class ListFadingEdgeModifier extends ModifierWithKey { + constructor(value: boolean) { + super(value); + } + static identity: Symbol = Symbol('fadingEdge'); + applyPeer(node: KNode, reset: boolean): void { + if (reset) { + getUINativeModule().list.resetFadingEdge(node); + } else { + getUINativeModule().list.setFadingEdge(node, this.value!); + } + } +} + class ArkListComponent extends ArkComponent implements ListAttribute { constructor(nativePtr: KNode, classType?: ModifierType) { super(nativePtr, classType); @@ -451,6 +465,10 @@ class ArkListComponent extends ArkComponent implements ListAttribute { onScrollFrameBegin(event: (offset: number, state: ScrollState) => { offsetRemain: number; }): this { throw new Error('Method not implemented.'); } + fadingEdge(value: boolean): this { + modifierWithKey(this._modifiersWithKeys, ListFadingEdgeModifier.identity, ListFadingEdgeModifier, value); + return this; + } } // @ts-ignore diff --git a/frameworks/bridge/declarative_frontend/engine/arkComponent.js b/frameworks/bridge/declarative_frontend/engine/arkComponent.js index be59817098eb682f43af471e6e6ae66227e03ec5..0c5a37feb8b2127dceddd36b8912a01b74edf449 100644 --- a/frameworks/bridge/declarative_frontend/engine/arkComponent.js +++ b/frameworks/bridge/declarative_frontend/engine/arkComponent.js @@ -18995,6 +18995,20 @@ class ListClipModifier extends ModifierWithKey { } } ListClipModifier.identity = Symbol('listClip'); +class ListFadingEdgeModifier extends ModifierWithKey { + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset) { + getUINativeModule().list.resetFadingEdge(node); + } + else { + getUINativeModule().list.setFadingEdge(node, this.value); + } + } +} +ListFadingEdgeModifier.identity = Symbol('fadingEdge'); class ArkListComponent extends ArkComponent { constructor(nativePtr, classType) { super(nativePtr, classType); @@ -19133,6 +19147,10 @@ class ArkListComponent extends ArkComponent { onScrollFrameBegin(event) { throw new Error('Method not implemented.'); } + fadingEdge(value) { + modifierWithKey(this._modifiersWithKeys, ListFadingEdgeModifier.identity, ListFadingEdgeModifier, value); + return this; + } } // @ts-ignore if (globalThis.List !== undefined) { diff --git a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_api_impl_bridge.cpp b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_api_impl_bridge.cpp index 3b8baa79ee9faf67bbcfc7ac7876d4fdde41ebdd..b760858b2fa5b92a438bca9b527836ab67cf7b0b 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_api_impl_bridge.cpp +++ b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_api_impl_bridge.cpp @@ -3420,6 +3420,10 @@ void ArkUINativeModule::RegisterListAttributes(Local object, E panda::FunctionRef::New(const_cast(vm), ListBridge::SetListLanes)); list->Set(vm, panda::StringRef::NewFromUtf8(vm, "resetListLanes"), panda::FunctionRef::New(const_cast(vm), ListBridge::ResetListLanes)); + list->Set(vm, panda::StringRef::NewFromUtf8(vm, "setFadingEdge"), + panda::FunctionRef::New(const_cast(vm), ListBridge::SetFadingEdge)); + list->Set(vm, panda::StringRef::NewFromUtf8(vm, "resetFadingEdge"), + panda::FunctionRef::New(const_cast(vm), ListBridge::ResetFadingEdge)); object->Set(vm, panda::StringRef::NewFromUtf8(vm, "list"), list); } diff --git a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.cpp b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.cpp index 638b68efb025ce6b3f935e506817ad5fa21bf8ac..9d2c96476fb9e85b124334f7a40e516ef2af2980 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.cpp +++ b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.cpp @@ -661,4 +661,31 @@ ArkUINativeModuleValue ListBridge::ResetChainAnimationOptions(ArkUIRuntimeCallIn return panda::JSValueRef::Undefined(vm); } +ArkUINativeModuleValue ListBridge::SetFadingEdge(ArkUIRuntimeCallInfo* runtimeCallInfo) +{ + EcmaVM* vm = runtimeCallInfo->GetVM(); + CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr)); + Local firstArg = runtimeCallInfo->GetCallArgRef(LIST_ARG_INDEX_0); + Local secondArg = runtimeCallInfo->GetCallArgRef(LIST_ARG_INDEX_1); + auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value()); + if (secondArg->IsUndefined()) { + GetArkUINodeModifiers()->getListModifier()->resetFadingEdge(nativeNode); + } else { + bool fadingEdge = secondArg->ToBoolean(vm)->Value(); + GetArkUINodeModifiers()->getListModifier()->setFadingEdge(nativeNode, fadingEdge); + } + + return panda::JSValueRef::Undefined(vm); +} + +ArkUINativeModuleValue ListBridge::ResetFadingEdge(ArkUIRuntimeCallInfo* runtimeCallInfo) +{ + EcmaVM* vm = runtimeCallInfo->GetVM(); + CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr)); + Local firstArg = runtimeCallInfo->GetCallArgRef(0); + auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value()); + GetArkUINodeModifiers()->getListModifier()->resetFadingEdge(nativeNode); + + return panda::JSValueRef::Undefined(vm); +} } // namespace OHOS::Ace::NG \ No newline at end of file diff --git a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.h b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.h index 08fd5493c35e0f7c3d7adc22cb319d7cb961a7c1..633c46d55b8400c1e7485097e47c3b02271e5e9a 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.h +++ b/frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_list_bridge.h @@ -57,6 +57,8 @@ public: static ArkUINativeModuleValue ResetDivider(ArkUIRuntimeCallInfo* runtimeCallInfo); static ArkUINativeModuleValue SetChainAnimationOptions(ArkUIRuntimeCallInfo* runtimeCallInfo); static ArkUINativeModuleValue ResetChainAnimationOptions(ArkUIRuntimeCallInfo* runtimeCallInfo); + static ArkUINativeModuleValue SetFadingEdge(ArkUIRuntimeCallInfo* runtimeCallInfo); + static ArkUINativeModuleValue ResetFadingEdge(ArkUIRuntimeCallInfo* runtimeCallInfo); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/bridge/declarative_frontend/jsview/js_list.cpp b/frameworks/bridge/declarative_frontend/jsview/js_list.cpp index 6f14c7bef2a6a3b7637fd1fbae7e3b72592198f6..72ed2a45b0458671cbf25e1f4f896b238c22f964 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_list.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_list.cpp @@ -679,11 +679,15 @@ void JSList::ScrollFrameBeginCallback(const JSCallbackInfo& args) } } +void JSList::SetFadingEdge(bool fadingEdge) +{ + ListModel::GetInstance()->SetFadingEdge(fadingEdge); +} + void JSList::JSBind(BindingTarget globalObj) { JSClass::Declare("List"); JSClass::StaticMethod("create", &JSList::Create); - JSClass::StaticMethod("width", &JSList::JsWidth); JSClass::StaticMethod("height", &JSList::JsHeight); JSClass::StaticMethod("clip", &JSScrollable::JsClip); @@ -707,7 +711,6 @@ void JSList::JSBind(BindingTarget globalObj) JSClass::StaticMethod("enableScrollInteraction", &JSList::SetScrollEnabled); JSClass::StaticMethod("scrollSnapAlign", &JSList::SetScrollSnapAlign); JSClass::StaticMethod("friction", &JSList::SetFriction); - JSClass::StaticMethod("onScroll", &JSList::ScrollCallback); JSClass::StaticMethod("onReachStart", &JSList::ReachStartCallback); JSClass::StaticMethod("onReachEnd", &JSList::ReachEndCallback); @@ -719,7 +722,19 @@ void JSList::JSBind(BindingTarget globalObj) JSClass::StaticMethod("onScrollVisibleContentChange", &JSList::ScrollVisibleContentChangeCallback); JSClass::StaticMethod("onScrollBegin", &JSList::ScrollBeginCallback); JSClass::StaticMethod("onScrollFrameBegin", &JSList::ScrollFrameBeginCallback); + JSClass::StaticMethod("onItemDragStart", &JSList::ItemDragStartCallback); + JSClass::StaticMethod("onItemDragEnter", &JSList::ItemDragEnterCallback); + JSClass::StaticMethod("onItemDragMove", &JSList::ItemDragMoveCallback); + JSClass::StaticMethod("onItemDragLeave", &JSList::ItemDragLeaveCallback); + JSClass::StaticMethod("onItemDrop", &JSList::ItemDropCallback); + JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); + JSClass::StaticMethod("fadingEdge", &JSList::SetFadingEdge); + BindInteractableViewMethods(); + JSClass::InheritAndBind(globalObj); +} +void JSList::BindInteractableViewMethods() +{ JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); @@ -727,15 +742,6 @@ void JSList::JSBind(BindingTarget globalObj) JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); - - JSClass::StaticMethod("onItemDragStart", &JSList::ItemDragStartCallback); - JSClass::StaticMethod("onItemDragEnter", &JSList::ItemDragEnterCallback); - JSClass::StaticMethod("onItemDragMove", &JSList::ItemDragMoveCallback); - JSClass::StaticMethod("onItemDragLeave", &JSList::ItemDragLeaveCallback); - JSClass::StaticMethod("onItemDrop", &JSList::ItemDropCallback); - JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); - - JSClass::InheritAndBind(globalObj); } void JSListScroller::JSBind(BindingTarget globalObj) diff --git a/frameworks/bridge/declarative_frontend/jsview/js_list.h b/frameworks/bridge/declarative_frontend/jsview/js_list.h index d916e3f49d03a723c2507c139112473d45ed0f08..35b3c34380e43ccea7f73eca2f267f0783184005 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_list.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_list.h @@ -36,6 +36,7 @@ public: class JSList : public JSScrollableBase { public: static void JSBind(BindingTarget globalObj); + static void BindInteractableViewMethods(); static void SetScroller(RefPtr scroller); static void Create(const JSCallbackInfo& args); @@ -79,6 +80,7 @@ public: static void ItemDragMoveCallback(const JSCallbackInfo& info); static void ItemDragLeaveCallback(const JSCallbackInfo& info); static void ItemDropCallback(const JSCallbackInfo& info); + static void SetFadingEdge(bool fadingEdge); static void SetListItemIndex(JSRef listItemInfo, ListItemIndex indexInfo); }; diff --git a/frameworks/bridge/declarative_frontend/jsview/models/list_model_impl.h b/frameworks/bridge/declarative_frontend/jsview/models/list_model_impl.h index 8b06cf9689d01b09f0617a796ccda814f35f3568..ba341ac0341787a4ee825f68862720623687e9ee 100644 --- a/frameworks/bridge/declarative_frontend/jsview/models/list_model_impl.h +++ b/frameworks/bridge/declarative_frontend/jsview/models/list_model_impl.h @@ -71,6 +71,7 @@ public: void SetOnItemDragLeave(OnItemDragLeaveFunc&& onItemDragLeave) override; void SetOnItemDragMove(OnItemDragMoveFunc&& onItemDragMove) override; void SetOnItemDrop(OnItemDropFunc&& onItemDrop) override; + void SetFadingEdge(bool fadingEdge) override {}; DisplayMode GetDisplayMode() const override { diff --git a/frameworks/core/components/list/list_theme.h b/frameworks/core/components/list/list_theme.h index b48e2b356e135c06af4092430833f8b87e9d0db2..d899f378af3785f6cd8a3d4f001931a9511cdbde 100644 --- a/frameworks/core/components/list/list_theme.h +++ b/frameworks/core/components/list/list_theme.h @@ -62,6 +62,8 @@ public: theme->chainIntensity_ = pattern->GetAttr("chain_intensity", 0.3f); theme->chainStiffness_ = pattern->GetAttr("chain_stiffness", 228.0f); theme->chainDamping_ = pattern->GetAttr("chain_damping", 30.0f); + std::string fadingEdge = pattern->GetAttr("list_fadeout_enable", ""); + theme->fadingEdge_ = (fadingEdge == "true"); } }; @@ -111,6 +113,10 @@ public: { return chainDamping_; } + bool GetFadingEdge() const + { + return fadingEdge_; + } protected: ListTheme() = default; @@ -126,6 +132,7 @@ private: double chainIntensity_ = 0.0; double chainStiffness_ = 0.0; double chainDamping_ = 0.0; + bool fadingEdge_ = false; }; } // namespace OHOS::Ace diff --git a/frameworks/core/components_ng/pattern/list/list_layout_property.cpp b/frameworks/core/components_ng/pattern/list/list_layout_property.cpp index 5435f7e669944b03b226d6c0be98c48287a7f411..ab26fc45703aa019279ff9bd71edc3e0cc004ea5 100644 --- a/frameworks/core/components_ng/pattern/list/list_layout_property.cpp +++ b/frameworks/core/components_ng/pattern/list/list_layout_property.cpp @@ -76,6 +76,7 @@ void ListLayoutProperty::ToJsonValue(std::unique_ptr& json) const } else { json->Put("sticky", "StickyStyle.None"); } + json->Put("fadingEdge", propFadingEdge_.value_or(false)); ScrollSnapPropToJsonValue(json); } diff --git a/frameworks/core/components_ng/pattern/list/list_layout_property.h b/frameworks/core/components_ng/pattern/list/list_layout_property.h index fa823e6ce22b53b70312e06fe3fb85910bc32920..14833b194e4c637a2854c70a558379b595fd807c 100644 --- a/frameworks/core/components_ng/pattern/list/list_layout_property.h +++ b/frameworks/core/components_ng/pattern/list/list_layout_property.h @@ -56,6 +56,7 @@ public: value->propScrollSnapAlign_ = CloneScrollSnapAlign(); value->propEditMode_ = CloneEditMode(); value->propScrollEnabled_ = CloneScrollEnabled(); + value->propFadingEdge_ = CloneFadingEdge(); return value; } @@ -78,6 +79,7 @@ public: ResetScrollSnapAlign(); ResetEditMode(); ResetScrollEnabled(); + ResetFadingEdge(); } void ToJsonValue(std::unique_ptr& json) const override; @@ -103,6 +105,7 @@ public: ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(ContentEndOffset, float, PROPERTY_UPDATE_MEASURE); ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(EditMode, bool, PROPERTY_UPDATE_MEASURE); ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(ScrollEnabled, bool, PROPERTY_UPDATE_MEASURE); + ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(FadingEdge, bool, PROPERTY_UPDATE_MEASURE); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/list/list_model.h b/frameworks/core/components_ng/pattern/list/list_model.h index 45a11cd758cdad0d44e6d32e16cf84bea6f13518..d7032304d2f73042da9b3a4203897eb7b991918f 100644 --- a/frameworks/core/components_ng/pattern/list/list_model.h +++ b/frameworks/core/components_ng/pattern/list/list_model.h @@ -79,6 +79,7 @@ public: virtual void SetOnItemDragMove(OnItemDragMoveFunc&& onItemDragMove) = 0; virtual void SetOnItemDrop(OnItemDropFunc&& onItemDrop) = 0; virtual void SetScrollSnapAlign(V2::ScrollSnapAlign scrollSnapAlign) {}; + virtual void SetFadingEdge(bool fadingEdge) = 0; virtual DisplayMode GetDisplayMode() const = 0; diff --git a/frameworks/core/components_ng/pattern/list/list_model_ng.cpp b/frameworks/core/components_ng/pattern/list/list_model_ng.cpp index 4cba8705b481618e396b01a78e8be3072130d93d..7f900dd187cd44deb71e1e184f84d7c2c23037e9 100644 --- a/frameworks/core/components_ng/pattern/list/list_model_ng.cpp +++ b/frameworks/core/components_ng/pattern/list/list_model_ng.cpp @@ -632,6 +632,16 @@ void ListModelNG::SetChainAnimationOptions(FrameNode* frameNode, const ChainAnim pattern->SetChainAnimationOptions(options); } +void ListModelNG::SetFadingEdge(bool fadingEdge) +{ + ACE_UPDATE_LAYOUT_PROPERTY(ListLayoutProperty, FadingEdge, fadingEdge); +} + +void ListModelNG::SetFadingEdge(FrameNode* frameNode, bool fadingEdge) +{ + ACE_UPDATE_NODE_LAYOUT_PROPERTY(ListLayoutProperty, FadingEdge, fadingEdge, frameNode); +} + void ListModelNG::SetOnScroll(FrameNode* frameNode, OnScrollEvent&& onScroll) { CHECK_NULL_VOID(frameNode); diff --git a/frameworks/core/components_ng/pattern/list/list_model_ng.h b/frameworks/core/components_ng/pattern/list/list_model_ng.h index 752960039a622d3eca80f4f5dee9d7030a138b69..919542d6f348523a504d6f598637990ab28d55ad 100644 --- a/frameworks/core/components_ng/pattern/list/list_model_ng.h +++ b/frameworks/core/components_ng/pattern/list/list_model_ng.h @@ -69,6 +69,7 @@ public: void SetOnItemDragLeave(OnItemDragLeaveFunc&& onItemDragLeave) override; void SetOnItemDragMove(OnItemDragMoveFunc&& onItemDragMove) override; void SetOnItemDrop(OnItemDropFunc&& onItemDrop) override; + void SetFadingEdge(bool fadingEdge) override; DisplayMode GetDisplayMode() const override; static RefPtr CreateFrameNode(int32_t nodeId); @@ -108,6 +109,7 @@ public: static void SetContentEndOffset(FrameNode* frameNode, float endOffset); static void SetDivider(FrameNode* frameNode, const V2::ItemDivider& divider); static void SetChainAnimationOptions(FrameNode* frameNode, const ChainAnimationOptions& options); + static void SetFadingEdge(FrameNode* frameNode, bool fadingEdge); static int32_t GetEdgeEffect(FrameNode* frameNode); static void SetOnScroll(FrameNode* frameNode, OnScrollEvent&& onScroll); static void SetOnScrollFrameBegin(FrameNode* frameNode, OnScrollFrameBeginEvent&& onScrollFrameBegin); diff --git a/frameworks/core/components_ng/pattern/list/list_paint_method.cpp b/frameworks/core/components_ng/pattern/list/list_paint_method.cpp index f6664d47411e87d89666811a6ab79532b5b1605e..d94a45e3479f194439d8cec102f59e0fec633bbf 100644 --- a/frameworks/core/components_ng/pattern/list/list_paint_method.cpp +++ b/frameworks/core/components_ng/pattern/list/list_paint_method.cpp @@ -19,6 +19,18 @@ #include "core/components_ng/render/divider_painter.h" namespace OHOS::Ace::NG { +constexpr double PERCENT_100 = 100.0; +constexpr float LINEAR_GRADIENT_ANGLE = 90.0f; + +namespace { + GradientColor CreatePercentGradientColor(float percent, Color color) + { + NG::GradientColor gredient = GradientColor(color); + gredient.SetDimension(CalcDimension(percent * PERCENT_100, DimensionUnit::PERCENT)); + return gredient; + } +} // namespace + void ListPaintMethod::PaintEdgeEffect(PaintWrapper* paintWrapper, RSCanvas& canvas) { auto edgeEffect = edgeEffect_.Upgrade(); @@ -45,6 +57,7 @@ void ListPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper) auto frameSize = geometryNode->GetPaddingSize(); OffsetF paddingOffset = geometryNode->GetPaddingOffset() - geometryNode->GetFrameOffset(); auto renderContext = paintWrapper->GetRenderContext(); + UpdateFadingGradient(renderContext); bool clip = !renderContext || renderContext->GetClipEdge().value_or(true); listContentModifier_->SetClipOffset(paddingOffset); listContentModifier_->SetClipSize(frameSize); @@ -184,4 +197,34 @@ void ListPaintMethod::UpdateOverlayModifier(PaintWrapper* paintWrapper) scrollBarOverlayModifier->SetBarColor(scrollBar->GetForegroundColor()); scrollBar->SetOpacityAnimationType(OpacityAnimationType::NONE); } + +void ListPaintMethod::UpdateFadingGradient(const RefPtr& listRenderContext) +{ + if ((!isFadingTop_ && !isFadingBottom_) || Negative(percentFading_)) { + return; + } + CHECK_NULL_VOID(listRenderContext); + CHECK_NULL_VOID(overlayRenderContext_); + NG::Gradient gradient; + gradient.CreateGradientWithType(NG::GradientType::LINEAR); + if (isFadingTop_) { + gradient.AddColor(CreatePercentGradientColor(0, Color::TRANSPARENT)); + gradient.AddColor(CreatePercentGradientColor(percentFading_, Color::WHITE)); + } + if (isFadingBottom_) { + gradient.AddColor(CreatePercentGradientColor(1 - percentFading_, Color::WHITE)); + gradient.AddColor(CreatePercentGradientColor(1, Color::TRANSPARENT)); + } + Axis axis = vertical_ ? Axis::HORIZONTAL : Axis::VERTICAL; + if (axis == Axis::HORIZONTAL) { + gradient.GetLinearGradient()->angle = CalcDimension(LINEAR_GRADIENT_ANGLE, DimensionUnit::PX); + } + listRenderContext->UpdateBackBlendMode(BlendMode::SRC_OVER); + listRenderContext->UpdateBackBlendApplyType(BlendApplyType::OFFSCREEN); + + overlayRenderContext_->UpdateZIndex(INT32_MAX); + overlayRenderContext_->UpdateLinearGradient(gradient); + overlayRenderContext_->UpdateBackBlendMode(BlendMode::DST_IN); + overlayRenderContext_->UpdateBackBlendApplyType(BlendApplyType::OFFSCREEN); +} } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/list/list_paint_method.h b/frameworks/core/components_ng/pattern/list/list_paint_method.h index 7550974e153076fe4a4ddc97e50be9dd1fc4daec..fd6444754231b4838f042ee106f3c15f81cd6a1b 100644 --- a/frameworks/core/components_ng/pattern/list/list_paint_method.h +++ b/frameworks/core/components_ng/pattern/list/list_paint_method.h @@ -118,6 +118,20 @@ public: void UpdateOverlayModifier(PaintWrapper* paintWrapper) override; + void SetOverlayRenderContext(const RefPtr& overlayRenderContext) + { + overlayRenderContext_ = overlayRenderContext; + } + + void SetFadingInfo(bool isFadingTop, bool isFadingBottom, float percentFading) + { + isFadingTop_ = isFadingTop; + isFadingBottom_ = isFadingBottom; + percentFading_ = percentFading; + } + + void UpdateFadingGradient(const RefPtr& listRenderContext); + private: V2::ItemDivider divider_; bool vertical_ = false; @@ -131,6 +145,11 @@ private: WeakPtr scrollBar_; WeakPtr edgeEffect_; WeakPtr scrollBarOverlayModifier_; + + RefPtr overlayRenderContext_; + bool isFadingTop_ = false; + bool isFadingBottom_ = false; + float percentFading_ = 0.0f; }; } // namespace OHOS::Ace::NG #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_PAINT_METHOD_H \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/list/list_pattern.cpp b/frameworks/core/components_ng/pattern/list/list_pattern.cpp index b9945c22ce40752f9045b30b2076bdf6f2fe37f0..0e2068a692405000c2b4c9543ff3277e4d5662d4 100644 --- a/frameworks/core/components_ng/pattern/list/list_pattern.cpp +++ b/frameworks/core/components_ng/pattern/list/list_pattern.cpp @@ -41,6 +41,7 @@ #include "core/components_ng/property/measure_utils.h" #include "core/components_ng/property/property.h" #include "core/components_v2/inspector/inspector_constants.h" +#include "core/components/list/list_theme.h" namespace OHOS::Ace::NG { namespace { @@ -50,6 +51,8 @@ constexpr double CHAIN_SPRING_DAMPING = 30.0; constexpr double CHAIN_SPRING_STIFFNESS = 228; constexpr float DEFAULT_MIN_SPACE_SCALE = 0.75f; constexpr float DEFAULT_MAX_SPACE_SCALE = 2.0f; +constexpr float LIST_FADINGEDGE_DEFAULT = 32.0f; +constexpr float LIST_START_MAIN_POS = 0.0f; } // namespace void ListPattern::OnModifyDone() @@ -91,6 +94,16 @@ void ListPattern::OnModifyDone() if (IsNeedInitClickEventRecorder()) { Pattern::InitClickEventRecorder(); } + auto conlist = PipelineBase::GetCurrentContextSafely(); + CHECK_NULL_VOID(conlist); + auto listTheme = conlist->GetTheme(); + CHECK_NULL_VOID(listTheme); + auto listThemeFadingEdge = listTheme->GetFadingEdge(); + isFadingEdge_ = listLayoutProperty->GetFadingEdge().value_or(listThemeFadingEdge); + auto overlayNode = host->GetOverlayNode(); + if (!overlayNode && isFadingEdge_) { + CreateAnalyzerOverlay(host); + } } void ListPattern::ChangeAxis(RefPtr node) @@ -296,6 +309,35 @@ float ListPattern::CalculateTargetPos(float startPos, float endPos) return 0.0f; } +void ListPattern::CreateAnalyzerOverlay(const RefPtr listNode) +{ + auto builderFunc = []() -> RefPtr { + auto uiNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG, + ElementRegister::GetInstance()->MakeUniqueId(), []() { + return AceType::MakeRefPtr(true); + }); + return uiNode; + }; + auto overlayNode = AceType::DynamicCast(builderFunc()); + CHECK_NULL_VOID(overlayNode); + listNode->SetOverlayNode(overlayNode); + overlayNode->SetParent(AceType::WeakClaim(AceType::RawPtr(listNode))); + overlayNode->SetActive(true); + overlayNode->SetHitTestMode(HitTestMode::HTMTRANSPARENT); + auto overlayProperty = AceType::DynamicCast(overlayNode->GetLayoutProperty()); + CHECK_NULL_VOID(overlayProperty); + overlayProperty->SetIsOverlayNode(true); + overlayProperty->UpdateMeasureType(MeasureType::MATCH_PARENT); + overlayProperty->UpdateAlignment(Alignment::CENTER); + auto overlayOffsetX = std::make_optional(Dimension::FromString("0px")); + auto overlayOffsetY = std::make_optional(Dimension::FromString("0px")); + overlayProperty->SetOverlayOffset(overlayOffsetX, overlayOffsetY); + auto focusHub = overlayNode->GetOrCreateFocusHub(); + CHECK_NULL_VOID(focusHub); + focusHub->SetFocusable(false); + overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE); +} + RefPtr ListPattern::CreateNodePaintMethod() { auto listLayoutProperty = GetLayoutProperty(); @@ -325,9 +367,38 @@ RefPtr ListPattern::CreateNodePaintMethod() paint->SetLaneGutter(laneGutter_); paint->SetItemsPosition(itemPosition_, pressedItem_); paint->SetContentModifier(listContentModifier_); + + UpdateFadingEdge(paint); return paint; } +void ListPattern::UpdateFadingEdge(const RefPtr paint) +{ + if (!isFadingEdge_ || LIST_START_MAIN_POS == contentMainSize_) { + return; + } + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto overlayNode = host->GetOverlayNode(); + CHECK_NULL_VOID(overlayNode); + auto overlayRenderContext = overlayNode->GetRenderContext(); + CHECK_NULL_VOID(overlayRenderContext); + if (Negative(startMainPos_) || GreatNotEqual(endMainPos_, contentMainSize_)) { + auto isTopEdgeFadingUpdate = isTopEdgeFading_ != (startMainPos_ < LIST_START_MAIN_POS); + auto isLowerEdgeFadingUpdate = isLowerEdgeFading_ != (endMainPos_ > contentMainSize_); + if (isTopEdgeFadingUpdate || isLowerEdgeFadingUpdate) { + auto isFadingTop = startMainPos_ < LIST_START_MAIN_POS; + auto isFadingBottom = endMainPos_ > contentMainSize_; + auto percentFading = CalcDimension(LIST_FADINGEDGE_DEFAULT, DimensionUnit::VP).ConvertToPx() / + std::abs(contentMainSize_ - LIST_START_MAIN_POS); + paint->SetOverlayRenderContext(overlayRenderContext); + paint->SetFadingInfo(isFadingTop, isFadingBottom, percentFading); + } + } + isTopEdgeFading_ = (startMainPos_ < LIST_START_MAIN_POS); + isLowerEdgeFading_ = (endMainPos_ > contentMainSize_); +} + bool ListPattern::UpdateStartListItemIndex() { auto host = GetHost(); diff --git a/frameworks/core/components_ng/pattern/list/list_pattern.h b/frameworks/core/components_ng/pattern/list/list_pattern.h index 1dbaaef7a4dcdb7d5942d857dda0691cf85d8063..50ffa63681b821c478edffe84ae0a6201f7227d8 100644 --- a/frameworks/core/components_ng/pattern/list/list_pattern.h +++ b/frameworks/core/components_ng/pattern/list/list_pattern.h @@ -46,6 +46,8 @@ public: ListPattern() : ScrollablePattern(EdgeEffect::SPRING, false) {} ~ListPattern() override = default; + void CreateAnalyzerOverlay(const RefPtr listNode); + RefPtr CreateNodePaintMethod() override; RefPtr CreateLayoutProperty() override @@ -323,6 +325,11 @@ private: RefPtr listContentModifier_; std::vector> listenerVector_; + void UpdateFadingEdge(const RefPtr paint); + bool isFadingEdge_ = false; + bool isTopEdgeFading_ = false; + bool isLowerEdgeFading_ = false; + int32_t maxListItemIndex_ = 0; int32_t startIndex_ = -1; int32_t endIndex_ = -1; diff --git a/frameworks/core/interfaces/arkoala/arkoala_api.h b/frameworks/core/interfaces/arkoala/arkoala_api.h index 9973e91de95cb9e1577be15997a3b575a98b5291..a07e7020dd707c46c37c1fd4ac0346df2279af2b 100644 --- a/frameworks/core/interfaces/arkoala/arkoala_api.h +++ b/frameworks/core/interfaces/arkoala/arkoala_api.h @@ -1542,6 +1542,8 @@ struct ArkUIListModifier { ArkUI_Float32 (*getListSpace)(ArkUINodeHandle node); void (*setListSpace)(ArkUINodeHandle node, ArkUI_Float32 space); void (*resetListSpace)(ArkUINodeHandle node); + void (*setFadingEdge)(ArkUINodeHandle node, ArkUI_Bool fadingEdge); + void (*resetFadingEdge)(ArkUINodeHandle node); ArkUI_Int32 (*setNodeAdapter)(ArkUINodeHandle node, ArkUINodeAdapterHandle handle); void (*resetNodeAdapter)(ArkUINodeHandle node); ArkUINodeAdapterHandle (*getNodeAdapter)(ArkUINodeHandle node); diff --git a/frameworks/core/interfaces/native/node/node_list_modifier.cpp b/frameworks/core/interfaces/native/node/node_list_modifier.cpp index 792a166b11c5cef0b8c49f9e76a9f454113a175f..374c33dac1339d449b14d72e6f766d43d19d74b0 100644 --- a/frameworks/core/interfaces/native/node/node_list_modifier.cpp +++ b/frameworks/core/interfaces/native/node/node_list_modifier.cpp @@ -485,6 +485,20 @@ void ResetChainAnimationOptions(ArkUINodeHandle node) ListModelNG::SetChainAnimationOptions(frameNode, options); } +void SetFadingEdge(ArkUINodeHandle node, ArkUI_Bool fadingEdge) +{ + auto* frameNode = reinterpret_cast(node); + CHECK_NULL_VOID(frameNode); + ListModelNG::SetFadingEdge(frameNode, fadingEdge); +} + +void ResetFadingEdge(ArkUINodeHandle node) +{ + auto* frameNode = reinterpret_cast(node); + CHECK_NULL_VOID(frameNode); + ListModelNG::SetFadingEdge(frameNode, false); +} + ArkUI_Int32 SetNodeAdapter(ArkUINodeHandle node, ArkUINodeAdapterHandle handle) { auto* frameNode = reinterpret_cast(node); @@ -529,7 +543,8 @@ const ArkUIListModifier* GetListModifier() SetListScrollBarColor, ResetListScrollBarColor, GetAlignListItem, SetAlignListItem, ResetAlignListItem, SetScrollSnapAlign, ResetScrollSnapAlign, SetContentStartOffset, ResetContentStartOffset, SetContentEndOffset, ResetContentEndOffset, ListSetDivider, ListResetDivider, SetChainAnimationOptions, ResetChainAnimationOptions, - GetListSpace, SetListSpace, ResetListSpace, SetNodeAdapter, ResetNodeAdapter, GetNodeAdapter, GetCachedCount }; + GetListSpace, SetListSpace, ResetListSpace, SetFadingEdge, ResetFadingEdge, SetNodeAdapter, ResetNodeAdapter, + GetNodeAdapter, GetCachedCount }; return &modifier; }