1 /* 2 * Copyright (c) 2021-2022 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_TAB_BAR_RENDER_TAB_CONTENT_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_TAB_BAR_RENDER_TAB_CONTENT_H 18 19 #include <functional> 20 #include <unordered_map> 21 22 #include "base/memory/ace_type.h" 23 #include "core/animation/animation.h" 24 #include "core/animation/animator.h" 25 #include "core/components/tab_bar/tab_content_component.h" 26 #include "core/gestures/drag_recognizer.h" 27 #include "core/gestures/raw_recognizer.h" 28 #include "core/pipeline/base/render_node.h" 29 30 namespace OHOS::Ace { 31 32 class RenderTabContent : public RenderNode { 33 DECLARE_ACE_TYPE(RenderTabContent, RenderNode) 34 35 public: 36 RenderTabContent(); 37 ~RenderTabContent() override = default; 38 39 static RefPtr<RenderNode> Create(); 40 void Update(const RefPtr<Component>& component) override; 41 void PerformLayout() override; 42 bool IsUseOnly() override; 43 44 using UpdateIndexFunc = std::function<void(int32_t index)>; RegisterCallback(const UpdateIndexFunc & callback)45 void RegisterCallback(const UpdateIndexFunc& callback) 46 { 47 callback_ = callback; 48 } 49 RegisterRequireCallback(const UpdateIndexFunc & callback)50 void RegisterRequireCallback(const UpdateIndexFunc& callback) 51 { 52 requireCallback_ = callback; 53 } 54 55 using UpdateIndicatorFunc = std::function<void(double percent, int32_t newIndex, bool needChange)>; RegisterIndicatorCallback(const UpdateIndicatorFunc & callback)56 void RegisterIndicatorCallback(const UpdateIndicatorFunc& callback) 57 { 58 indicatorCallback_ = callback; 59 } 60 61 void ChangeScroll(int32_t index, bool fromController = false); 62 63 void UpdateDragPosition(int32_t index); 64 AddChildContent(int32_t index,const RefPtr<RenderNode> & child)65 void AddChildContent(int32_t index, const RefPtr<RenderNode>& child) 66 { 67 auto iter = contentMap_.begin(); 68 while (iter != contentMap_.end()) { 69 if (iter->second == child) { 70 if (iter->first != index) { 71 // index has changed, clear map. 72 contentMap_.clear(); 73 } 74 break; 75 } 76 iter++; 77 } 78 contentMap_[index] = child; 79 requestedIndex_ = index; 80 forceUpdate_ = true; 81 } 82 RemoveChildContent(int32_t index)83 void RemoveChildContent(int32_t index) 84 { 85 if (contentMap_.find(index) != contentMap_.end()) { 86 contentMap_.clear(); 87 forceUpdate_ = true; 88 } 89 } 90 RemoveChildContent(const RefPtr<RenderNode> & child)91 void RemoveChildContent(const RefPtr<RenderNode>& child) 92 { 93 auto iter = contentMap_.begin(); 94 while (iter != contentMap_.end()) { 95 if (iter->second == child) { 96 iter->second->SetHidden(true); 97 contentMap_.clear(); 98 forceUpdate_ = true; 99 break; 100 } 101 iter++; 102 } 103 } 104 RemoveChildContentUpdateMap(const RefPtr<RenderNode> & child)105 void RemoveChildContentUpdateMap(const RefPtr<RenderNode>& child) 106 { 107 int32_t idx = -1; 108 109 for (const auto& item : contentMap_) { 110 if (item.second == child) { 111 item.second->SetHidden(true); 112 idx = item.first; 113 break; 114 } 115 } 116 117 if (idx < 0) { 118 return; 119 } 120 121 std::unordered_map<int32_t, RefPtr<RenderNode>> newContentMap; 122 for (const auto& item : contentMap_) { 123 if (item.first < idx) { 124 newContentMap.emplace(item); 125 } else if (item.first > idx) { 126 newContentMap.emplace(std::pair<int32_t, RefPtr<RenderNode>>(item.first - 1, item.second)); 127 } 128 } 129 130 std::swap(contentMap_, newContentMap); 131 } 132 UpdateContentCount(int32_t count)133 void UpdateContentCount(int32_t count) 134 { 135 contentCount_ = count; 136 } 137 138 // Used by declarative element to flush index after performBuild. 139 void FlushIndex(); 140 GetCurrentIndex()141 int32_t GetCurrentIndex() const 142 { 143 return currentIndex_; 144 } 145 GetChildContents()146 const std::unordered_map<int32_t, RefPtr<RenderNode>>& GetChildContents() const 147 { 148 return contentMap_; 149 } 150 151 void FireDomChangeEvent(int32_t index) const; 152 IsScrollable()153 bool IsScrollable() const 154 { 155 return scrollable_; 156 } 157 GetScrollDuration()158 float GetScrollDuration() const 159 { 160 return scrollDuration_; 161 } 162 163 std::string ProvideRestoreInfo() override; 164 165 private: 166 // for handle scroll tabContent 167 void OnTouchTestHit( 168 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result) override; 169 void HandleDragStart(); 170 void HandleDragUpdate(double offset); 171 void HandleDragEnd(); 172 173 void Initialize(const WeakPtr<PipelineContext>& context); 174 void FireContentChangeEvent() const; 175 void HandContentIndicatorEvent(int32_t newIndex, bool needChange) const; 176 177 // used to scroll TabContent and update the position 178 void ScrollContents(int32_t newIndex, bool isLinkBar, bool fromController = false); 179 void UpdateScrollPosition(double dragDelta); 180 void UpdateChildPosition(double offset, int32_t currentIndex, int32_t newIndex, bool needChange); 181 void HandleStopListener(int32_t newIndex, bool needChange, bool FromController = false); 182 void HandleStartListener(int32_t newIndex, bool needChange, bool isLinkBar); 183 void SetHiddenChild(); 184 185 double GetOffset(double offset); 186 187 static double GetFriction(double percentage); 188 189 // if tab is vertical, offset changed on Y axis 190 // if tab is horizontal, offset changed on X axis GetMainAxisOffset(double offset)191 Offset GetMainAxisOffset(double offset) const 192 { 193 return isVertical_ ? Offset(0.0, offset) : Offset(offset, 0.0); 194 } 195 IsRightToLeft()196 bool IsRightToLeft() const 197 { 198 return GetTextDirection() == TextDirection::RTL && !isVertical_; 199 } 200 // used to get the previous index or the next index 201 int32_t GetPrevIndex() const; 202 int32_t GetNextIndex() const; 203 204 void ApplyRestoreInfo(); 205 206 // dragRecognizer and the animation 207 RefPtr<DragRecognizer> dragDetector_; 208 RefPtr<Animation<double>> translate_; 209 RefPtr<Animator> animator_; 210 211 // map for contents 212 std::unordered_map<int32_t, RefPtr<RenderNode>> contentMap_; 213 214 // onChange event 215 std::function<void(const std::string&)> changeEvent_; 216 std::function<void(uint32_t)> domChangeEvent_; 217 std::function<void(const std::shared_ptr<BaseEventInfo>&)> onChangeEvent_; 218 219 bool isAnimationAdded_ = false; // whether the animation is added 220 bool scrollable_ = true; // the default value is true 221 bool isInAnimation_ = false; // whether it is in animation 222 bool isDragging_ = false; // whether it is dragging 223 bool isInitialized_ = false; 224 bool isVertical_ = false; // whether the tab is vertical 225 bool forceUpdate_ = false; 226 227 int32_t contentCount_ = 0; // the count of content 228 int32_t currentIndex_ = 0; // the index of current tab 229 int32_t requestedIndex_ = -1; // the next requested index 230 231 float scrollDuration_ = 0.0f; // the duration of the scroll animation 232 double contentWidth_ = 0.0; // the width of tab content 233 double contentHeight_ = 0.0; // the height of tab content 234 double prevOffset_ = 0.0; // the offset of previous item 235 double nextOffset_ = 0.0; // the offset of next item 236 double scrollOffset_ = 0.0; // the offset when the content is scrolling 237 238 // callbacks when updating the index 239 UpdateIndexFunc callback_; 240 UpdateIndexFunc requireCallback_; 241 UpdateIndicatorFunc indicatorCallback_; 242 243 RefPtr<TabController> controller_; 244 bool useInitialIndex_ = true; 245 }; 246 247 } // namespace OHOS::Ace 248 249 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_TAB_BAR_RENDER_TAB_CONTENT_H 250