1 /* 2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_PATTERN_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_PATTERN_H 18 19 #include <tuple> 20 #include "core/animation/chain_animation.h" 21 #include "core/components_ng/pattern/list/list_accessibility_property.h" 22 #include "core/components_ng/pattern/list/list_children_main_size.h" 23 #include "core/components_ng/pattern/list/list_content_modifier.h" 24 #include "core/components_ng/pattern/list/list_event_hub.h" 25 #include "core/components_ng/pattern/list/list_item_pattern.h" 26 #include "core/components_ng/pattern/list/list_layout_algorithm.h" 27 #include "core/components_ng/pattern/list/list_layout_property.h" 28 #include "core/components_ng/pattern/list/list_paint_method.h" 29 #include "core/components_ng/pattern/list/list_position_map.h" 30 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h" 31 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h" 32 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h" 33 #include "core/components_ng/render/render_context.h" 34 #include "core/pipeline_ng/pipeline_context.h" 35 36 namespace OHOS::Ace::NG { 37 class InspectorFilter; 38 39 struct ListItemGroupPara { 40 int32_t lanes = -1; 41 int32_t itemEndIndex = -1; 42 int32_t displayStartIndex = -1; 43 int32_t displayEndIndex = -1; 44 }; 45 46 struct ListScrollTarget { 47 int32_t index = -1; 48 float extraOffset = 0.0f; 49 ScrollAlign align = ScrollAlign::START; 50 float targetOffset; 51 }; 52 53 class ListPattern : public ScrollablePattern { 54 DECLARE_ACE_TYPE(ListPattern, ScrollablePattern); 55 56 public: ListPattern()57 ListPattern() : ScrollablePattern(EdgeEffect::SPRING, false) {} 58 ~ListPattern() override = default; 59 60 RefPtr<NodePaintMethod> CreateNodePaintMethod() override; 61 CreateLayoutProperty()62 RefPtr<LayoutProperty> CreateLayoutProperty() override 63 { 64 return MakeRefPtr<ListLayoutProperty>(); 65 } 66 CreateEventHub()67 RefPtr<EventHub> CreateEventHub() override 68 { 69 return MakeRefPtr<ListEventHub>(); 70 } 71 CreateAccessibilityProperty()72 RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override 73 { 74 return MakeRefPtr<ListAccessibilityProperty>(); 75 } 76 UsResRegion()77 bool UsResRegion() override 78 { 79 return false; 80 } 81 82 RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override; 83 84 void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override; 85 86 void FromJson(const std::unique_ptr<JsonValue>& json) override; 87 88 bool UpdateCurrentOffset(float offset, int32_t source) override; 89 90 DisplayMode GetDefaultScrollBarDisplayMode() const override; 91 GetStartIndex()92 int32_t GetStartIndex() const 93 { 94 return startIndex_; 95 } 96 GetEndIndex()97 int32_t GetEndIndex() const 98 { 99 return endIndex_; 100 } 101 GetMaxListItemIndex()102 int32_t GetMaxListItemIndex() const 103 { 104 return maxListItemIndex_; 105 } 106 IsScrollable()107 bool IsScrollable() const override 108 { 109 return isScrollable_; 110 } 111 SetMaintainVisibleContentPosition(bool enabled)112 void SetMaintainVisibleContentPosition(bool enabled) 113 { 114 maintainVisibleContentPosition_ = enabled; 115 } 116 GetMaintainVisibleContentPosition()117 bool GetMaintainVisibleContentPosition() 118 { 119 return maintainVisibleContentPosition_; 120 } 121 MarkNeedReEstimateOffset()122 void MarkNeedReEstimateOffset() 123 { 124 needReEstimateOffset_ = true; 125 } 126 127 void NotifyDataChange(int32_t index, int32_t count) override; 128 129 bool IsAtTop() const override; 130 bool IsAtBottom() const override; 131 void OnTouchDown(const TouchEventInfo& info) override; 132 OverScrollOffset GetOutBoundaryOffset(bool useCurrentDelta) const; 133 OverScrollOffset GetOverScrollOffset(double delta) const override; 134 float GetOffsetWithLimit(float offset) const override; 135 void HandleScrollBarOutBoundary(); 136 GetFocusPattern()137 FocusPattern GetFocusPattern() const override 138 { 139 return { FocusType::SCOPE, true }; 140 } 141 GetScopeFocusAlgorithm()142 ScopeFocusAlgorithm GetScopeFocusAlgorithm() override 143 { 144 auto property = GetLayoutProperty<ListLayoutProperty>(); 145 if (!property) { 146 return {}; 147 } 148 return ScopeFocusAlgorithm(property->GetListDirection().value_or(Axis::VERTICAL) == Axis::VERTICAL, true, 149 ScopeType::OTHERS, 150 [wp = WeakClaim(this)]( 151 FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) { 152 auto list = wp.Upgrade(); 153 if (list) { 154 nextFocusNode = list->GetNextFocusNode(step, currFocusNode); 155 } 156 }); 157 } 158 159 std::pair<std::function<bool(float)>, Axis> GetScrollOffsetAbility() override; 160 161 std::function<bool(int32_t)> GetScrollIndexAbility() override; 162 163 bool ScrollToNode(const RefPtr<FrameNode>& focusFrameNode) override; 164 GetItemPosition()165 const ListLayoutAlgorithm::PositionMap& GetItemPosition() const 166 { 167 return itemPosition_; 168 } 169 GetTotalOffset()170 float GetTotalOffset() const override 171 { 172 return currentOffset_; 173 } 174 GetPositionController()175 RefPtr<ScrollControllerBase> GetPositionController() const 176 { 177 return positionController_; 178 } 179 180 void TriggerModifyDone(); 181 182 float GetTotalHeight() const override; 183 184 // scroller 185 void ScrollTo(float position) override; 186 void ScrollToIndex(int32_t index, bool smooth = false, ScrollAlign align = ScrollAlign::START, 187 std::optional<float> extraOffset = std::nullopt) override; 188 void ScrollToItemInGroup(int32_t index, int32_t indexInGroup, bool smooth = false, 189 ScrollAlign align = ScrollAlign::START); 190 bool CheckTargetValid(int32_t index, int32_t indexInGroup); 191 bool ScrollPage(bool reverse, AccessibilityScrollType scrollType = AccessibilityScrollType::SCROLL_FULL); 192 void ScrollBy(float offset); 193 bool AnimateToTarget(int32_t index, std::optional<int32_t> indexInGroup, ScrollAlign align); 194 Offset GetCurrentOffset() const; 195 Rect GetItemRect(int32_t index) const override; 196 Rect GetItemRectInGroup(int32_t index, int32_t indexInGroup) const; 197 void OnAnimateStop() override; GetMainContentSize()198 float GetMainContentSize() const override 199 { 200 return contentMainSize_; 201 } GetLanes()202 int32_t GetLanes() const 203 { 204 return lanes_; 205 } 206 207 void UpdatePosMapStart(float delta); 208 void UpdatePosMapEnd(); 209 void CalculateCurrentOffset(float delta, const ListLayoutAlgorithm::PositionMap& recycledItemPosition); 210 void UpdateScrollBarOffset() override; 211 // chain animation 212 void SetChainAnimation(); 213 void SetChainAnimationOptions(const ChainAnimationOptions& options); 214 float FlushChainAnimation(float dragOffset); 215 void ProcessDragStart(float startPosition); 216 void ProcessDragUpdate(float dragOffset, int32_t source); 217 float GetChainDelta(int32_t index) const; 218 219 // multiSelectable SetMultiSelectable(bool multiSelectable)220 void SetMultiSelectable(bool multiSelectable) 221 { 222 multiSelectable_ = multiSelectable; 223 } 224 225 void SetSwiperItem(WeakPtr<ListItemPattern> swiperItem); GetSwiperItem()226 WeakPtr<ListItemPattern> GetSwiperItem() 227 { 228 if (!swiperItem_.Upgrade()) { 229 return nullptr; 230 } 231 return swiperItem_; 232 } SetSwiperItemEnd(WeakPtr<ListItemPattern> swiperItem)233 void SetSwiperItemEnd(WeakPtr<ListItemPattern> swiperItem) 234 { 235 if (swiperItem == swiperItem_) { 236 canReplaceSwiperItem_ = true; 237 } 238 } IsCurrentSwiperItem(WeakPtr<ListItemPattern> swiperItem)239 bool IsCurrentSwiperItem(WeakPtr<ListItemPattern> swiperItem) 240 { 241 if (!swiperItem_.Upgrade()) { 242 return true; 243 } 244 return swiperItem == swiperItem_; 245 } CanReplaceSwiperItem()246 bool CanReplaceSwiperItem() 247 { 248 auto listItemPattern = swiperItem_.Upgrade(); 249 if (!listItemPattern) { 250 canReplaceSwiperItem_ = true; 251 return canReplaceSwiperItem_; 252 } 253 auto host = listItemPattern->GetHost(); 254 if (!host || !host->IsOnMainTree()) { 255 canReplaceSwiperItem_ = true; 256 return canReplaceSwiperItem_; 257 } 258 return canReplaceSwiperItem_; 259 } 260 SetPredictSnapOffset(float predictSnapOffset)261 void SetPredictSnapOffset(float predictSnapOffset) 262 { 263 predictSnapOffset_ = predictSnapOffset; 264 } 265 bool OnScrollSnapCallback(double targetOffset, double velocity) override; 266 267 int32_t GetItemIndexByPosition(float xOffset, float yOffset); 268 SetPredictLayoutParam(std::optional<ListPredictLayoutParam> param)269 void SetPredictLayoutParam(std::optional<ListPredictLayoutParam> param) 270 { 271 predictLayoutParam_ = param; 272 } GetPredictLayoutParam()273 std::optional<ListPredictLayoutParam> GetPredictLayoutParam() const 274 { 275 return predictLayoutParam_; 276 } 277 SetPredictLayoutParamV2(std::optional<ListPredictLayoutParamV2> param)278 void SetPredictLayoutParamV2(std::optional<ListPredictLayoutParamV2> param) 279 { 280 predictLayoutParamV2_ = param; 281 } 282 GetPredictLayoutParamV2()283 std::optional<ListPredictLayoutParamV2> GetPredictLayoutParamV2() const 284 { 285 return predictLayoutParamV2_; 286 } 287 288 void CloseAllSwipeActions(OnFinishFunc&&); 289 290 std::string ProvideRestoreInfo() override; 291 void OnRestoreInfo(const std::string& restoreInfo) override; 292 void DumpAdvanceInfo() override; 293 SetNeedToUpdateListDirectionInCardStyle(bool isNeedToUpdateListDirection)294 void SetNeedToUpdateListDirectionInCardStyle(bool isNeedToUpdateListDirection) 295 { 296 isNeedToUpdateListDirection_ = isNeedToUpdateListDirection; 297 } 298 IsNeedToUpdateListDirectionInCardStyle()299 bool IsNeedToUpdateListDirectionInCardStyle() const 300 { 301 return isNeedToUpdateListDirection_; 302 } 303 304 std::vector<RefPtr<FrameNode>> GetVisibleSelectedItems() override; 305 SetItemPressed(bool isPressed,int32_t id)306 void SetItemPressed(bool isPressed, int32_t id) 307 { 308 if (isPressed) { 309 pressedItem_.emplace(id); 310 } else { 311 pressedItem_.erase(id); 312 } 313 } 314 315 RefPtr<ListChildrenMainSize> GetOrCreateListChildrenMainSize(); 316 void SetListChildrenMainSize(float defaultSize, const std::vector<float>& mainSize); 317 void OnChildrenSizeChanged(std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag); 318 void ResetChildrenSize(); ListChildrenSizeExist()319 bool ListChildrenSizeExist() 320 { 321 return static_cast<bool>(childrenSize_); 322 } CanOverScroll(int32_t source)323 bool CanOverScroll(int32_t source) override 324 { 325 auto canOverScroll = (IsScrollableSpringEffect() && source != SCROLL_FROM_AXIS && source != SCROLL_FROM_BAR && 326 IsScrollable() && (!ScrollableIdle() || animateOverScroll_ || animateCanOverScroll_) && 327 (IsAtBottom() || IsAtTop())); 328 if (canOverScroll != lastCanOverScroll_) { 329 lastCanOverScroll_ = canOverScroll; 330 AddScrollableFrameInfo(source); 331 } 332 return canOverScroll; 333 } 334 private: 335 IsNeedInitClickEventRecorder()336 bool IsNeedInitClickEventRecorder() const override 337 { 338 return true; 339 } 340 341 void OnScrollEndCallback() override; 342 void FireOnReachStart(const OnReachEvent& onReachStart) override; 343 void FireOnReachEnd(const OnReachEvent& onReachEnd) override; 344 void FireOnScrollIndex(bool indexChanged, const OnScrollIndexEvent& onScrollIndex); 345 void OnModifyDone() override; 346 void ChangeAxis(RefPtr<UINode> node); 347 bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override; 348 float CalculateTargetPos(float startPos, float endPos); 349 350 void InitOnKeyEvent(const RefPtr<FocusHub>& focusHub); 351 bool OnKeyEvent(const KeyEvent& event); 352 bool HandleDirectionKey(const KeyEvent& event); 353 WeakPtr<FocusHub> GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode); 354 WeakPtr<FocusHub> GetChildFocusNodeByIndex(int32_t tarMainIndex, int32_t tarGroupIndex); 355 WeakPtr<FocusHub> ScrollAndFindFocusNode(int32_t nextIndex, int32_t curIndex, int32_t& nextIndexInGroup, 356 int32_t curIndexInGroup, int32_t moveStep, FocusStep step); 357 bool ScrollListForFocus(int32_t nextIndex, int32_t curIndex, int32_t nextIndexInGroup); 358 bool ScrollListItemGroupForFocus(int32_t nextIndex, int32_t& nextIndexInGroup, int32_t curIndexInGroup, 359 int32_t moveStep, FocusStep step, bool isScrollIndex); 360 361 void MarkDirtyNodeSelf(); 362 SizeF GetContentSize() const; 363 void ProcessEvent(bool indexChanged, float finalOffset, bool isJump); 364 void CheckScrollable(); 365 bool IsOutOfBoundary(bool useCurrentDelta = true) override; 366 bool OnScrollCallback(float offset, int32_t source) override; 367 void SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect) override; 368 void HandleScrollEffect(float offset); 369 void StartDefaultOrCustomSpringMotion(float start, float end, const RefPtr<InterpolatingSpring>& curve); 370 bool IsScrollSnapAlignCenter() const; 371 void SetChainAnimationCallback(); 372 void SetChainAnimationToPosMap(); 373 void SetChainAnimationLayoutAlgorithm( 374 RefPtr<ListLayoutAlgorithm> listLayoutAlgorithm, RefPtr<ListLayoutProperty> listLayoutProperty); 375 bool NeedScrollSnapAlignEffect() const; 376 ScrollAlign GetScrollAlignByScrollSnapAlign() const; 377 bool GetListItemAnimatePos(float startPos, float endPos, ScrollAlign align, float& targetPos); 378 bool GetListItemGroupAnimatePosWithoutIndexInGroup(int32_t index, float startPos, float endPos, 379 ScrollAlign align, float& targetPos); 380 bool GetListItemGroupAnimatePosWithIndexInGroup(int32_t index, int32_t indexInGroup, float startPos, 381 ScrollAlign align, float& targetPos); 382 383 // multiSelectable 384 void ClearMultiSelect() override; 385 bool IsItemSelected(const GestureEvent& info) override; 386 void MultiSelectWithoutKeyboard(const RectF& selectedZone) override; 387 void HandleCardModeSelectedEvent( 388 const RectF& selectedZone, const RefPtr<FrameNode>& itemGroupNode, float itemGroupTop); 389 390 void DrivenRender(const RefPtr<LayoutWrapper>& layoutWrapper); 391 ListItemGroupPara GetListItemGroupParameter(const RefPtr<FrameNode>& node); 392 bool IsListItemGroup(int32_t listIndex, RefPtr<FrameNode>& node); 393 void GetListItemGroupEdge(bool& groupAtStart, bool& groupAtEnd) const; 394 void RefreshLanesItemRange(); 395 void UpdateListDirectionInCardStyle(); 396 bool UpdateStartListItemIndex(); 397 bool UpdateEndListItemIndex(); 398 float GetStartOverScrollOffset(float offset, float startMainPos) const; 399 float GetEndOverScrollOffset(float offset, float endMainPos, float startMainPos) const; 400 float UpdateTotalOffset(const RefPtr<ListLayoutAlgorithm>& listLayoutAlgorithm, bool isJump); 401 RefPtr<ListContentModifier> listContentModifier_; 402 403 int32_t maxListItemIndex_ = 0; 404 int32_t startIndex_ = -1; 405 int32_t endIndex_ = -1; 406 int32_t centerIndex_ = -1; 407 float startMainPos_ = 0.0f; 408 float endMainPos_ = 0.0f; 409 float prevStartOffset_ = 0.f; 410 float prevEndOffset_ = 0.f; 411 float currentOffset_ = 0.0f; 412 float spaceWidth_ = 0.0f; 413 float contentMainSize_ = 0.0f; 414 float contentStartOffset_ = 0.0f; 415 float contentEndOffset_ = 0.0f; 416 bool maintainVisibleContentPosition_ = false; 417 418 float currentDelta_ = 0.0f; 419 bool crossMatchChild_ = false; 420 bool smooth_ = false; 421 float scrollSnapVelocity_ = 0.0f; 422 bool snapTrigOnScrollStart_ = false; 423 424 std::optional<int32_t> jumpIndex_; 425 std::optional<int32_t> jumpIndexInGroup_; 426 std::optional<int32_t> targetIndex_; 427 std::optional<int32_t> targetIndexInGroup_; 428 std::optional<ListScrollTarget> scrollTarget_; 429 std::optional<float> predictSnapOffset_; 430 std::optional<float> predictSnapEndPos_; 431 ScrollAlign scrollAlign_ = ScrollAlign::START; 432 bool isScrollable_ = true; 433 bool paintStateFlag_ = false; 434 bool isFramePaintStateValid_ = false; 435 bool isNeedCheckOffset_ = false; 436 437 ListLayoutAlgorithm::PositionMap itemPosition_; 438 RefPtr<ListPositionMap> posMap_; 439 RefPtr<ListChildrenMainSize> childrenSize_; 440 float listTotalHeight_ = 0.0f; 441 442 std::map<int32_t, int32_t> lanesItemRange_; 443 std::set<int32_t> pressedItem_; 444 int32_t lanes_ = 1; 445 float laneGutter_ = 0.0f; 446 // chain animation 447 RefPtr<ChainAnimation> chainAnimation_; 448 bool dragFromSpring_ = false; 449 RefPtr<SpringProperty> springProperty_; 450 std::optional<ChainAnimationOptions> chainAnimationOptions_; 451 452 bool isOritationListenerRegisted_ = false; 453 454 // ListItem swiperAction 455 WeakPtr<ListItemPattern> swiperItem_; 456 bool canReplaceSwiperItem_ = true; 457 458 RefPtr<SpringMotion> scrollToIndexMotion_; 459 RefPtr<SpringMotion> scrollSnapMotion_; 460 RefPtr<Scrollable> scrollable_; 461 462 bool isScrollEnd_ = false; 463 bool needReEstimateOffset_ = false; 464 std::optional<ListPredictLayoutParam> predictLayoutParam_; 465 std::optional<ListPredictLayoutParamV2> predictLayoutParamV2_; 466 467 bool isNeedToUpdateListDirection_ = false; 468 bool startIndexChanged_ = false; 469 bool endIndexChanged_ = false; 470 471 ListItemIndex startInfo_ = {-1, -1, -1}; 472 ListItemIndex endInfo_ = {-1, -1, -1}; 473 }; 474 } // namespace OHOS::Ace::NG 475 476 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_PATTERN_H 477