• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "core/components_ng/pattern/radio/radio_pattern.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components/checkable/checkable_theme.h"
20 #include "core/components/common/layout/constants.h"
21 #include "core/components_ng/base/view_stack_processor.h"
22 #include "core/components_ng/pattern/radio/radio_layout_algorithm.h"
23 #include "core/components_ng/pattern/radio/radio_paint_property.h"
24 #include "core/components_ng/pattern/stage/page_event_hub.h"
25 #include "core/components_ng/property/property.h"
26 #include "core/event/touch_event.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 
29 namespace OHOS::Ace::NG {
30 
31 namespace {
32 constexpr int DEFAULT_RADIO_ANIMATION_DURATION = 300;
33 constexpr float DEFAULT_MID_TIME_SLOT = 0.5;
34 constexpr float DEFAULT_END_TIME_SLOT = 1.0;
35 constexpr float DEFAULT_SHRINK_TIME_SLOT = 0.9;
36 } // namespace
37 
OnAttachToFrameNode()38 void RadioPattern::OnAttachToFrameNode()
39 {
40     auto host = GetHost();
41     CHECK_NULL_VOID(host);
42     host->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER);
43 }
44 
OnDetachFromFrameNode(FrameNode * frameNode)45 void RadioPattern::OnDetachFromFrameNode(FrameNode* frameNode)
46 {
47     CHECK_NULL_VOID(frameNode);
48     auto pipelineContext = PipelineContext::GetCurrentContext();
49     CHECK_NULL_VOID(pipelineContext);
50     auto stageManager = pipelineContext->GetStageManager();
51     CHECK_NULL_VOID(stageManager);
52     auto pageNode = stageManager->GetLastPage();
53     CHECK_NULL_VOID(pageNode);
54     auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
55     CHECK_NULL_VOID(pageEventHub);
56     auto radioEventHub = frameNode->GetEventHub<NG::RadioEventHub>();
57     CHECK_NULL_VOID(radioEventHub);
58     pageEventHub->RemoveRadioFromGroup(radioEventHub->GetGroup(), frameNode->GetId());
59 }
60 
OnModifyDone()61 void RadioPattern::OnModifyDone()
62 {
63     UpdateState();
64     auto host = GetHost();
65     CHECK_NULL_VOID(host);
66     auto pipeline = PipelineBase::GetCurrentContext();
67     CHECK_NULL_VOID(pipeline);
68     auto radioTheme = pipeline->GetTheme<RadioTheme>();
69     CHECK_NULL_VOID(radioTheme);
70     auto layoutProperty = host->GetLayoutProperty();
71     CHECK_NULL_VOID(layoutProperty);
72     if (!layoutProperty->GetMarginProperty()) {
73         MarginProperty margin;
74         margin.left = CalcLength(radioTheme->GetHotZoneHorizontalPadding().Value());
75         margin.right = CalcLength(radioTheme->GetHotZoneHorizontalPadding().Value());
76         margin.top = CalcLength(radioTheme->GetHotZoneVerticalPadding().Value());
77         margin.bottom = CalcLength(radioTheme->GetHotZoneVerticalPadding().Value());
78         layoutProperty->UpdateMargin(margin);
79     }
80     hotZoneHorizontalPadding_ = radioTheme->GetHotZoneHorizontalPadding();
81     hotZoneVerticalPadding_ = radioTheme->GetHotZoneVerticalPadding();
82     InitClickEvent();
83     InitTouchEvent();
84     InitMouseEvent();
85     auto focusHub = host->GetFocusHub();
86     CHECK_NULL_VOID(focusHub);
87     InitOnKeyEvent(focusHub);
88 }
89 
InitClickEvent()90 void RadioPattern::InitClickEvent()
91 {
92     if (clickListener_) {
93         return;
94     }
95     auto host = GetHost();
96     CHECK_NULL_VOID(host);
97     auto gesture = host->GetOrCreateGestureEventHub();
98     CHECK_NULL_VOID(gesture);
99     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
100         auto radioPattern = weak.Upgrade();
101         CHECK_NULL_VOID(radioPattern);
102         radioPattern->OnClick();
103     };
104     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
105     gesture->AddClickEvent(clickListener_);
106 }
107 
InitTouchEvent()108 void RadioPattern::InitTouchEvent()
109 {
110     if (touchListener_) {
111         return;
112     }
113     auto host = GetHost();
114     CHECK_NULL_VOID(host);
115     auto gesture = host->GetOrCreateGestureEventHub();
116     CHECK_NULL_VOID(gesture);
117     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
118         auto radioPattern = weak.Upgrade();
119         CHECK_NULL_VOID(radioPattern);
120         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
121             radioPattern->OnTouchDown();
122         }
123         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
124             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
125             radioPattern->OnTouchUp();
126         }
127     };
128     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
129     gesture->AddTouchEvent(touchListener_);
130 }
131 
InitMouseEvent()132 void RadioPattern::InitMouseEvent()
133 {
134     if (mouseEvent_) {
135         return;
136     }
137     auto host = GetHost();
138     CHECK_NULL_VOID(host);
139     auto gesture = host->GetOrCreateGestureEventHub();
140     CHECK_NULL_VOID(gesture);
141     auto eventHub = host->GetEventHub<RadioEventHub>();
142     auto inputHub = eventHub->GetOrCreateInputEventHub();
143 
144     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
145         auto pattern = weak.Upgrade();
146         if (pattern) {
147             pattern->HandleMouseEvent(isHover);
148         }
149     };
150     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
151     inputHub->AddOnHoverEvent(mouseEvent_);
152 }
153 
HandleMouseEvent(bool isHover)154 void RadioPattern::HandleMouseEvent(bool isHover)
155 {
156     isHover_ = isHover;
157     if (isHover) {
158         touchHoverType_ = TouchHoverAnimationType::HOVER;
159     } else {
160         touchHoverType_ = TouchHoverAnimationType::NONE;
161     }
162     auto host = GetHost();
163     CHECK_NULL_VOID(host);
164     host->MarkNeedRenderOnly();
165 }
166 
OnClick()167 void RadioPattern::OnClick()
168 {
169     auto host = GetHost();
170     CHECK_NULL_VOID(host);
171     auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
172     CHECK_NULL_VOID(paintProperty);
173     bool check = false;
174     if (paintProperty->HasRadioCheck()) {
175         check = paintProperty->GetRadioCheckValue();
176     } else {
177         paintProperty->UpdateRadioCheck(false);
178     }
179 
180     if (!preCheck_ && !check) {
181         paintProperty->UpdateRadioCheck(true);
182         UpdateState();
183     }
184 }
185 
OnTouchDown()186 void RadioPattern::OnTouchDown()
187 {
188     if (isHover_) {
189         touchHoverType_ = TouchHoverAnimationType::HOVER_TO_PRESS;
190     } else {
191         touchHoverType_ = TouchHoverAnimationType::PRESS;
192     }
193     auto host = GetHost();
194     CHECK_NULL_VOID(host);
195     host->MarkNeedRenderOnly();
196 }
197 
OnTouchUp()198 void RadioPattern::OnTouchUp()
199 {
200     if (isHover_) {
201         touchHoverType_ = TouchHoverAnimationType::PRESS_TO_HOVER;
202     } else {
203         touchHoverType_ = TouchHoverAnimationType::NONE;
204     }
205     auto host = GetHost();
206     CHECK_NULL_VOID(host);
207     host->MarkNeedRenderOnly();
208 }
209 
UpdateState()210 void RadioPattern::UpdateState()
211 {
212     auto host = GetHost();
213     CHECK_NULL_VOID(host);
214     auto pattern = host->GetPattern<RadioPattern>();
215     CHECK_NULL_VOID(pattern);
216     auto eventHub = host->GetEventHub<RadioEventHub>();
217     CHECK_NULL_VOID(eventHub);
218 
219     auto preGroup = pattern->GetPreGroup();
220     auto group = eventHub->GetGroup();
221     if (!preGroup.has_value()) {
222         auto pipelineContext = PipelineContext::GetCurrentContext();
223         CHECK_NULL_VOID(pipelineContext);
224         auto stageManager = pipelineContext->GetStageManager();
225         CHECK_NULL_VOID(stageManager);
226         auto pageNode = stageManager->GetLastPage();
227         CHECK_NULL_VOID(pageNode);
228         auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
229         CHECK_NULL_VOID(pageEventHub);
230         pageEventHub->AddRadioToGroup(group, host->GetId());
231     } else {
232         if (preGroup.value() != group) {
233             auto pipelineContext = PipelineContext::GetCurrentContext();
234             CHECK_NULL_VOID(pipelineContext);
235             auto stageManager = pipelineContext->GetStageManager();
236             CHECK_NULL_VOID(stageManager);
237             auto pageNode = stageManager->GetLastPage();
238             CHECK_NULL_VOID(pageNode);
239             auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
240             CHECK_NULL_VOID(pageEventHub);
241 
242             pageEventHub->RemoveRadioFromGroup(preGroup.value(), host->GetId());
243             pageEventHub->AddRadioToGroup(group, host->GetId());
244         }
245     }
246     pattern->SetPreGroup(group);
247 
248     auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
249     CHECK_NULL_VOID(paintProperty);
250 
251     bool check = false;
252     if (paintProperty->HasRadioCheck()) {
253         check = paintProperty->GetRadioCheckValue();
254         /*
255          * Do not set isFirstCreated_ to false if the radio is set to true at creation time. The isFirstCreated_ is set
256          * to false in UpdateGroupCheckStatus because isFirstCreated_ is also required to determine if an onChange event
257          * needs to be triggered.
258          */
259         if (check) {
260             UpdateUIStatus(true);
261             if (!isFirstCreated_) {
262                 PlayAnimation(true);
263             }
264         } else {
265             // If the radio is set to false, set isFirstCreated_ to false.
266             isFirstCreated_ = false;
267         }
268     } else {
269         paintProperty->UpdateRadioCheck(false);
270         // If the radio check is not set, set isFirstCreated_ to false.
271         isFirstCreated_ = false;
272     }
273     if (preCheck_ != check) {
274         UpdateGroupCheckStatus(host, check);
275     }
276     preCheck_ = check;
277 }
278 
UpdateUncheckStatus(const RefPtr<FrameNode> & frameNode)279 void RadioPattern::UpdateUncheckStatus(const RefPtr<FrameNode>& frameNode)
280 {
281     auto radioPaintProperty = frameNode->GetPaintProperty<RadioPaintProperty>();
282     CHECK_NULL_VOID(radioPaintProperty);
283     radioPaintProperty->UpdateRadioCheck(false);
284     frameNode->MarkNeedRenderOnly();
285 
286     if (preCheck_) {
287         auto radioEventHub = GetEventHub<RadioEventHub>();
288         CHECK_NULL_VOID(radioEventHub);
289         radioEventHub->UpdateChangeEvent(false);
290         PlayAnimation(false);
291     }
292     preCheck_ = false;
293 }
294 
UpdateGroupCheckStatus(const RefPtr<FrameNode> & frameNode,bool check)295 void RadioPattern::UpdateGroupCheckStatus(const RefPtr<FrameNode>& frameNode, bool check)
296 {
297     frameNode->MarkNeedRenderOnly();
298 
299     auto pipelineContext = PipelineContext::GetCurrentContext();
300     CHECK_NULL_VOID(pipelineContext);
301     auto stageManager = pipelineContext->GetStageManager();
302     CHECK_NULL_VOID(stageManager);
303     auto pageNode = stageManager->GetLastPage();
304     CHECK_NULL_VOID(pageNode);
305     auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
306     CHECK_NULL_VOID(pageEventHub);
307 
308     auto radioEventHub = GetEventHub<RadioEventHub>();
309     CHECK_NULL_VOID(radioEventHub);
310     if (check) {
311         pageEventHub->UpdateRadioGroupValue(radioEventHub->GetGroup(), frameNode->GetId());
312     } else {
313         auto radioPaintProperty = frameNode->GetPaintProperty<RadioPaintProperty>();
314         CHECK_NULL_VOID(radioPaintProperty);
315         radioPaintProperty->UpdateRadioCheck(check);
316         PlayAnimation(false);
317     }
318 
319     if (!isFirstCreated_) {
320         radioEventHub->UpdateChangeEvent(check);
321     }
322     // If the radio is set to true at creation time, set isFirstCreated_ to false here.
323     isFirstCreated_ = false;
324 }
325 
PlayAnimation(bool isOn)326 void RadioPattern::PlayAnimation(bool isOn)
327 {
328     auto host = GetHost();
329     CHECK_NULL_VOID(host);
330     if (!onController_) {
331         onController_ = AceType::MakeRefPtr<Animator>(host->GetContext());
332         onController_->AddStopListener(Animator::StatusCallback([weak = AceType::WeakClaim(this)]() {
333             auto radio = weak.Upgrade();
334             if (radio) {
335                 radio->UpdateUIStatus(true);
336             }
337         }));
338     }
339     if (!offController_) {
340         offController_ = AceType::MakeRefPtr<Animator>(host->GetContext());
341         offController_->AddStopListener(Animator::StatusCallback([weak = AceType::WeakClaim(this)]() {
342             auto radio = weak.Upgrade();
343             if (radio) {
344                 radio->UpdateUIStatus(false);
345             }
346         }));
347     }
348     StopTranslateAnimation();
349     RefPtr<KeyframeAnimation<float>> shrinkEngine = AceType::MakeRefPtr<KeyframeAnimation<float>>();
350     RefPtr<KeyframeAnimation<float>> selectEngine = AceType::MakeRefPtr<KeyframeAnimation<float>>();
351     RefPtr<KeyframeAnimation<float>> selectRingEngine = AceType::MakeRefPtr<KeyframeAnimation<float>>();
352     onController_->ClearInterpolators();
353     offController_->ClearInterpolators();
354     auto shrinkFrameStart = AceType::MakeRefPtr<Keyframe<float>>(0.0, 1.0);
355     auto shrinkFrameMid = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_MID_TIME_SLOT, DEFAULT_SHRINK_TIME_SLOT);
356     auto shrinkFrameEnd = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_END_TIME_SLOT, 1.0);
357     shrinkEngine->AddKeyframe(shrinkFrameStart);
358     shrinkEngine->AddKeyframe(shrinkFrameMid);
359     shrinkEngine->AddKeyframe(shrinkFrameEnd);
360     shrinkEngine->SetCurve(Curves::FRICTION);
361     shrinkEngine->AddListener(Animation<float>::ValueCallback([weak = AceType::WeakClaim(this)](float value) {
362         auto radio = weak.Upgrade();
363         if (radio) {
364             radio->UpdateTotalScale(value);
365         }
366     }));
367 
368     auto selectFrameStart = AceType::MakeRefPtr<Keyframe<float>>(0.0, isOn ? 0.0 : 0.5);
369     auto selectFrameMid = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_MID_TIME_SLOT, 0.0);
370     auto selectFrameEnd = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_END_TIME_SLOT, isOn ? 0.5 : 0.0);
371     selectEngine->AddKeyframe(selectFrameStart);
372     selectEngine->AddKeyframe(selectFrameMid);
373     selectEngine->AddKeyframe(selectFrameEnd);
374     selectEngine->SetCurve(Curves::FRICTION);
375     selectEngine->AddListener(Animation<float>::ValueCallback([weak = AceType::WeakClaim(this)](float value) {
376         auto radio = weak.Upgrade();
377         if (radio) {
378             radio->UpdatePointScale(value);
379         }
380     }));
381 
382     auto selectRingFrameStart = AceType::MakeRefPtr<Keyframe<float>>(0.0, isOn ? 1.0 : 0.0);
383     auto selectRingFrameMid = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_MID_TIME_SLOT, 0.0);
384     auto selectRingFrameEnd = AceType::MakeRefPtr<Keyframe<float>>(DEFAULT_END_TIME_SLOT, isOn ? 0.0 : 1.0);
385     selectRingEngine->AddKeyframe(selectRingFrameStart);
386     selectRingEngine->AddKeyframe(selectRingFrameMid);
387     selectRingEngine->AddKeyframe(selectRingFrameEnd);
388     selectRingEngine->SetCurve(Curves::FRICTION);
389     selectRingEngine->AddListener(Animation<float>::ValueCallback([weak = AceType::WeakClaim(this)](float value) {
390         auto radio = weak.Upgrade();
391         if (radio) {
392             radio->UpdateRingPointScale(value);
393         }
394     }));
395 
396     if (isOn) {
397         onController_->AddInterpolator(shrinkEngine);
398         onController_->AddInterpolator(selectEngine);
399         onController_->AddInterpolator(selectRingEngine);
400         onController_->SetDuration(DEFAULT_RADIO_ANIMATION_DURATION);
401         onController_->Play();
402     } else {
403         offController_->AddInterpolator(shrinkEngine);
404         offController_->AddInterpolator(selectEngine);
405         offController_->AddInterpolator(selectRingEngine);
406         offController_->SetDuration(DEFAULT_RADIO_ANIMATION_DURATION);
407         offController_->Play();
408     }
409 }
410 
StopTranslateAnimation()411 void RadioPattern::StopTranslateAnimation()
412 {
413     if (offController_ && !offController_->IsStopped()) {
414         offController_->Stop();
415     }
416     if (onController_ && !onController_->IsStopped()) {
417         onController_->Stop();
418     }
419 }
420 
UpdateUIStatus(bool check)421 void RadioPattern::UpdateUIStatus(bool check)
422 {
423     uiStatus_ = check ? UIStatus::SELECTED : UIStatus::UNSELECTED;
424     auto host = GetHost();
425     CHECK_NULL_VOID(host);
426     host->MarkNeedRenderOnly();
427 }
428 
UpdateTotalScale(float scale)429 void RadioPattern::UpdateTotalScale(float scale)
430 {
431     totalScale_ = scale;
432     auto host = GetHost();
433     CHECK_NULL_VOID(host);
434     host->MarkNeedRenderOnly();
435 }
436 
UpdatePointScale(float scale)437 void RadioPattern::UpdatePointScale(float scale)
438 {
439     pointScale_ = scale;
440     auto host = GetHost();
441     CHECK_NULL_VOID(host);
442     host->MarkNeedRenderOnly();
443 }
444 
UpdateRingPointScale(float scale)445 void RadioPattern::UpdateRingPointScale(float scale)
446 {
447     ringPointScale_ = scale;
448     auto host = GetHost();
449     CHECK_NULL_VOID(host);
450     host->MarkNeedRenderOnly();
451 }
452 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)453 void RadioPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
454 {
455     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
456         auto pattern = wp.Upgrade();
457         if (!pattern) {
458             return false;
459         }
460         return pattern->OnKeyEvent(event);
461     };
462     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
463 
464     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
465         auto pattern = wp.Upgrade();
466         if (pattern) {
467             pattern->GetInnerFocusPaintRect(paintRect);
468         }
469     };
470     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
471 }
472 
OnKeyEvent(const KeyEvent & event)473 bool RadioPattern::OnKeyEvent(const KeyEvent& event)
474 {
475     if (event.action != KeyAction::DOWN) {
476         return false;
477     }
478     if (event.code == KeyCode::KEY_ENTER) {
479         OnClick();
480         return true;
481     }
482     return false;
483 }
484 
GetInnerFocusPaintRect(RoundRect & paintRect)485 void RadioPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
486 {
487     auto pipeline = PipelineBase::GetCurrentContext();
488     CHECK_NULL_VOID(pipeline);
489     auto radioTheme = pipeline->GetTheme<RadioTheme>();
490     CHECK_NULL_VOID(radioTheme);
491     auto focusPaintPadding = radioTheme->GetFocusPaintPadding().ConvertToPx();
492     float outCircleRadius = size_.Width() / 2 + focusPaintPadding;
493     float originX = offset_.GetX() - focusPaintPadding;
494     float originY = offset_.GetY() - focusPaintPadding;
495     float width = size_.Width() + 2 * focusPaintPadding;
496     float height = size_.Height() + 2 * focusPaintPadding;
497     paintRect.SetRect({ originX, originY, width, height });
498     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, outCircleRadius, outCircleRadius);
499     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, outCircleRadius, outCircleRadius);
500     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, outCircleRadius, outCircleRadius);
501     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, outCircleRadius, outCircleRadius);
502 }
503 
GetFocusPattern() const504 FocusPattern RadioPattern::GetFocusPattern() const
505 {
506     auto pipeline = PipelineBase::GetCurrentContext();
507     CHECK_NULL_RETURN(pipeline, FocusPattern());
508     auto radioTheme = pipeline->GetTheme<RadioTheme>();
509     CHECK_NULL_RETURN(radioTheme, FocusPattern());
510     auto activeColor = radioTheme->GetActiveColor();
511     FocusPaintParam focusPaintParam;
512     focusPaintParam.SetPaintColor(activeColor);
513     return { FocusType::NODE, true, FocusStyleType::CUSTOM_REGION, focusPaintParam };
514 }
515 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig &)516 bool RadioPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& /*config*/)
517 {
518     auto geometryNode = dirty->GetGeometryNode();
519     offset_ = geometryNode->GetContentOffset();
520     size_ = geometryNode->GetContentSize();
521 
522     auto offset = geometryNode->GetContentOffset();
523     auto size = geometryNode->GetContentSize();
524     if (offset != offset_ || size != size_) {
525         offset_ = offset;
526         size_ = size;
527         AddHotZoneRect();
528     }
529 
530     return true;
531 }
532 
533 // Set the default hot zone for the component.
AddHotZoneRect()534 void RadioPattern::AddHotZoneRect()
535 {
536     hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalPadding_.ConvertToPx());
537     hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalPadding_.ConvertToPx());
538     hotZoneSize_.SetWidth(size_.Width() + 2 * hotZoneHorizontalPadding_.ConvertToPx());
539     hotZoneSize_.SetHeight(size_.Height() + 2 * hotZoneVerticalPadding_.ConvertToPx());
540     DimensionRect hotZoneRegion;
541     hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
542     hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
543     auto host = GetHost();
544     CHECK_NULL_VOID(host);
545     host->AddHotZoneRect(hotZoneRegion);
546 }
547 
RemoveLastHotZoneRect() const548 void RadioPattern::RemoveLastHotZoneRect() const
549 {
550     auto host = GetHost();
551     CHECK_NULL_VOID(host);
552     host->RemoveLastHotZoneRect();
553 }
554 
555 } // namespace OHOS::Ace::NG
556