From d506881b2126da28688dc7a85732d449d0acc397 Mon Sep 17 00:00:00 2001 From: chensi10 Date: Tue, 28 Mar 2023 13:22:13 +0800 Subject: [PATCH] menu ux 2 Change-Id: I2e1daac66c68faad9ed87f7c168daeeea13423bc Signed-off-by: chensi10 --- .../menu_item/menu_item_layout_algorithm.cpp | 3 +- .../menu/menu_item/menu_item_pattern.cpp | 166 +++++++++++------- .../menu/menu_item/menu_item_pattern.h | 13 +- .../pattern/menu/menu_layout_algorithm.cpp | 7 + .../pattern/menu/menu_pattern.cpp | 27 ++- .../components_ng/pattern/menu/menu_pattern.h | 11 ++ .../components_ng/pattern/menu/menu_view.cpp | 5 + .../menu/wrapper/menu_wrapper_pattern.cpp | 17 +- .../pattern/option/option_pattern.cpp | 2 +- 9 files changed, 183 insertions(+), 68 deletions(-) diff --git a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_layout_algorithm.cpp index 26634c6742f..147aad54a61 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_layout_algorithm.cpp @@ -30,7 +30,8 @@ void MenuItemLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) auto theme = pipeline->GetTheme(); CHECK_NULL_VOID(theme); verInterval_ = static_cast(VERTICAL_INTERVAL.ConvertToPx()); - horInterval_ = static_cast(theme->GetMenuIconPadding().ConvertToPx()); + horInterval_ = static_cast(theme->GetMenuIconPadding().ConvertToPx()) - + static_cast(theme->GetOutPadding().ConvertToPx()); auto props = layoutWrapper->GetLayoutProperty(); CHECK_NULL_VOID(props); auto layoutConstraint = props->GetLayoutConstraint(); diff --git a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.cpp b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.cpp index edc9f8f527f..4e6c8132362 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.cpp @@ -109,18 +109,6 @@ void MenuItemPattern::OnModifyDone() CHECK_NULL_VOID(focusHub); RegisterOnKeyEvent(focusHub); - auto eventHub = host->GetEventHub(); - CHECK_NULL_VOID(eventHub); - if (!eventHub->IsEnabled()) { - CHECK_NULL_VOID(content_); - auto context = PipelineBase::GetCurrentContext(); - CHECK_NULL_VOID(context); - auto theme = context->GetTheme(); - CHECK_NULL_VOID(theme); - auto contentProperty = content_->GetLayoutProperty(); - CHECK_NULL_VOID(contentProperty); - contentProperty->UpdateTextColor(theme->GetDisabledMenuFontColor()); - } /* * The structure of menu item is designed as follows : * |--menu_item @@ -181,32 +169,55 @@ void MenuItemPattern::ShowSubMenu() CHECK_NULL_VOID(host); LOGI("MenuItemPattern::ShowSubMenu menu item id is %{public}d", host->GetId()); auto buildFunc = GetSubBuilder(); - if (buildFunc && !isSubMenuShowed_) { - isSubMenuShowed_ = true; - - NG::ScopedViewStackProcessor builderViewStackProcessor; - buildFunc(); - auto customNode = NG::ViewStackProcessor::GetInstance()->Finish(); - auto subMenu = MenuView::Create(customNode, host->GetId(), MenuType::SUB_MENU); - auto menuPattern = subMenu->GetPattern(); - menuPattern->SetParentMenuItem(host); - subMenuId_ = subMenu->GetId(); - AddSelfHoverRegion(host); - - auto menuWrapper = GetMenuWrapper(); - CHECK_NULL_VOID(menuWrapper); - auto menuWrapperPattern = menuWrapper->GetPattern(); - CHECK_NULL_VOID(menuWrapperPattern); - menuWrapperPattern->AddSubMenuId(host->GetId()); - subMenu->MountToParent(menuWrapper); - - OffsetF offset = GetSubMenuPostion(host); - auto menuProps = subMenu->GetLayoutProperty(); - CHECK_NULL_VOID(menuProps); - menuProps->UpdateMenuOffset(offset); - menuWrapper->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD); - RegisterWrapperMouseEvent(); + if (!buildFunc || isSubMenuShowed_) { + return; + } + + // Hide SubMenu of parent Menu node + auto parentMenu = GetMenu(); + CHECK_NULL_VOID(parentMenu); + auto parentMenuPattern = parentMenu->GetPattern(); + CHECK_NULL_VOID(parentMenuPattern); + auto showedSubMenu = parentMenuPattern->GetShowedSubMenu(); + if (showedSubMenu) { + auto showedSubMenuPattern = showedSubMenu->GetPattern(); + CHECK_NULL_VOID(showedSubMenuPattern); + auto showedMenuItem = showedSubMenuPattern->GetParentMenuItem(); + CHECK_NULL_VOID(showedMenuItem); + if (showedMenuItem->GetId() != host->GetId()) { + parentMenuPattern->HideSubMenu(); + } } + + isSubMenuShowed_ = true; + + NG::ScopedViewStackProcessor builderViewStackProcessor; + buildFunc(); + auto customNode = NG::ViewStackProcessor::GetInstance()->Finish(); + auto subMenu = MenuView::Create(customNode, host->GetId(), MenuType::SUB_MENU); + auto menuPattern = subMenu->GetPattern(); + menuPattern->SetParentMenuItem(host); + subMenuId_ = subMenu->GetId(); + AddSelfHoverRegion(host); + + auto menuWrapper = GetMenuWrapper(); + CHECK_NULL_VOID(menuWrapper); + auto menuWrapperPattern = menuWrapper->GetPattern(); + CHECK_NULL_VOID(menuWrapperPattern); + menuWrapperPattern->AddSubMenuId(host->GetId()); + subMenu->MountToParent(menuWrapper); + + OffsetF offset = GetSubMenuPostion(host); + auto menuProps = subMenu->GetLayoutProperty(); + CHECK_NULL_VOID(menuProps); + menuProps->UpdateMenuOffset(offset); + menuWrapper->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD); + RegisterWrapperMouseEvent(); + + auto focusHub = subMenu->GetOrCreateFocusHub(); + CHECK_NULL_VOID(focusHub); + focusHub->RequestFocus(); + parentMenuPattern->SetShowedSubMenu(subMenu); } void MenuItemPattern::CloseMenu() @@ -277,7 +288,6 @@ void MenuItemPattern::RegisterOnHover() }; auto mouseEvent = MakeRefPtr(std::move(mouseTask)); inputHub->AddOnHoverEvent(mouseEvent); - inputHub->SetHoverAnimation(HoverEffectType::BOARD); } void MenuItemPattern::RegisterOnKeyEvent(const RefPtr& focusHub) @@ -300,16 +310,21 @@ void MenuItemPattern::OnPress(const TouchEventInfo& info) if (touchType == TouchType::DOWN) { // change background color, update press status - auto clickedColor = theme->GetClickedColor(); - UpdateBackgroundColor(clickedColor); + SetBgBlendColor(GetSubBuilder() ? theme->GetHoverColor() : theme->GetClickedColor()); } else if (touchType == TouchType::UP) { - auto bgColor = theme->GetBackgroundColor(); - UpdateBackgroundColor(bgColor); + SetBgBlendColor(isHovered_ ? theme->GetHoverColor() : Color::TRANSPARENT); + } else { + return; } + PlayBgColorAnimation(false); + auto host = GetHost(); + CHECK_NULL_VOID(host); + host->MarkDirtyNode(PROPERTY_UPDATE_RENDER); } void MenuItemPattern::OnHover(bool isHover) { + isHovered_ = isHover; auto pipeline = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(pipeline); auto theme = pipeline->GetTheme(); @@ -317,14 +332,15 @@ void MenuItemPattern::OnHover(bool isHover) if (isHover || isSubMenuShowed_) { // keep hover color when subMenu showed - auto hoverColor = theme->GetHoverColor(); - UpdateBackgroundColor(hoverColor); - + SetBgBlendColor(theme->GetHoverColor()); ShowSubMenu(); } else { - auto bgColor = theme->GetBackgroundColor(); - UpdateBackgroundColor(bgColor); + SetBgBlendColor(Color::TRANSPARENT); } + PlayBgColorAnimation(); + auto host = GetHost(); + CHECK_NULL_VOID(host); + host->MarkDirtyNode(PROPERTY_UPDATE_RENDER); } bool MenuItemPattern::OnKeyEvent(const KeyEvent& event) @@ -332,9 +348,15 @@ bool MenuItemPattern::OnKeyEvent(const KeyEvent& event) if (event.action != KeyAction::DOWN) { return false; } - if ((event.code == KeyCode::KEY_DPAD_RIGHT || event.code == KeyCode::KEY_ENTER || - event.code == KeyCode::KEY_SPACE) && - !isSubMenuShowed_) { + auto host = GetHost(); + CHECK_NULL_RETURN(host, false); + auto focusHub = host->GetOrCreateFocusHub(); + CHECK_NULL_RETURN(focusHub, false); + if (event.code == KeyCode::KEY_ENTER) { + focusHub->OnClick(event); + return true; + } + if ((event.code == KeyCode::KEY_DPAD_RIGHT && GetSubBuilder() && !isSubMenuShowed_)) { ShowSubMenu(); return true; } @@ -400,14 +422,30 @@ bool MenuItemPattern::IsInHoverRegions(double x, double y) return false; } -void MenuItemPattern::UpdateBackgroundColor(const Color& color) +void MenuItemPattern::PlayBgColorAnimation(bool isHoverChange) { - auto host = GetHost(); - CHECK_NULL_VOID(host); - auto renderContext = host->GetRenderContext(); - CHECK_NULL_VOID(renderContext); - renderContext->UpdateBackgroundColor(color); - host->MarkDirtyNode(PROPERTY_UPDATE_RENDER); + auto pipeline = PipelineBase::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto theme = pipeline->GetTheme(); + CHECK_NULL_VOID(theme); + AnimationOption option = AnimationOption(); + if (isHoverChange) { + option.SetDuration(theme->GetHoverAnimationDuration()); + option.SetCurve(Curves::FRICTION); + } else { + option.SetDuration(theme->GetPressAnimationDuration()); + option.SetCurve(Curves::SHARP); + } + + AnimationUtils::Animate(option, [weak = WeakClaim(this)]() { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID_NOLOG(pattern); + auto host = pattern->GetHost(); + CHECK_NULL_VOID_NOLOG(host); + auto renderContext = host->GetRenderContext(); + CHECK_NULL_VOID_NOLOG(renderContext); + renderContext->BlendBgColor(pattern->GetBgBlendColor()); + }); } void MenuItemPattern::AddSelectIcon(RefPtr& row) @@ -504,9 +542,17 @@ void MenuItemPattern::UpdateText(RefPtr& row, RefPtrGetMenuFontSize()); auto fontWeight = isLabel ? itemProperty->GetLabelFontWeight() : itemProperty->GetFontWeight(); UpdateFontWeight(textProperty, menuProperty, fontWeight); - auto fontColor = isLabel ? itemProperty->GetLabelFontColor() : itemProperty->GetFontColor(); - UpdateFontColor( - textProperty, menuProperty, fontColor, isLabel ? theme->GetSecondaryFontColor() : theme->GetMenuFontColor()); + + auto eventHub = GetEventHub(); + CHECK_NULL_VOID(eventHub); + if (eventHub->IsEnabled()) { + auto fontColor = isLabel ? itemProperty->GetLabelFontColor() : itemProperty->GetFontColor(); + UpdateFontColor(textProperty, menuProperty, fontColor, + isLabel ? theme->GetSecondaryFontColor() : theme->GetMenuFontColor()); + } else { + textProperty->UpdateTextColor(theme->GetDisabledMenuFontColor()); + } + textProperty->UpdateContent(content); node->MountToParent(row, isLabel ? 0 : DEFAULT_NODE_SLOT); node->MarkModifyDone(); diff --git a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.h b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.h index 45691808187..e613c548c78 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.h +++ b/frameworks/core/components_ng/pattern/menu/menu_item/menu_item_pattern.h @@ -136,7 +136,15 @@ public: return label_; } - void UpdateBackgroundColor(const Color& color); + void PlayBgColorAnimation(bool isHoverChange = true); + void SetBgBlendColor(const Color& color) + { + bgBlendColor_ = color; + } + Color GetBgBlendColor() const + { + return bgBlendColor_; + } RefPtr GetMenu(); void UpdateTextNodes(); @@ -179,6 +187,7 @@ private: bool isSubMenuHovered_ = false; bool isChanged_ = false; + bool isHovered_ = false; std::function subBuilderFunc_ = nullptr; @@ -190,6 +199,8 @@ private: RefPtr endIcon_ = nullptr; RefPtr selectIcon_ = nullptr; + Color bgBlendColor_ = Color::TRANSPARENT; + ACE_DISALLOW_COPY_AND_MOVE(MenuItemPattern); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/menu/menu_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/menu/menu_layout_algorithm.cpp index 976e291ff76..38f6ffc54d3 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_layout_algorithm.cpp @@ -358,6 +358,13 @@ float MenuLayoutAlgorithm::VerticalLayoutSubMenu(const SizeF& size, float positi if (bottomSpace >= size.Height()) { return position; } + + // line up bottom of submenu with bottom of the menuItem + float topSpace = position + menuItemSize.Height(); + if (topSpace >= size.Height()) { + return topSpace - size.Height(); + } + // line up bottom of menu with bottom of the screen if (size.Height() < wrapperHeight) { return wrapperHeight - size.Height(); diff --git a/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp b/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp index af31a8cfc3e..01c6175e988 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp @@ -202,7 +202,8 @@ void MenuPattern::RemoveParentHoverStyle() CHECK_NULL_VOID(pipeline); auto theme = pipeline->GetTheme(); CHECK_NULL_VOID(theme); - menuItemPattern->UpdateBackgroundColor(theme->GetBackgroundColor()); + menuItemPattern->SetBgBlendColor(Color::TRANSPARENT); + menuItemPattern->PlayBgColorAnimation(); } void MenuPattern::UpdateMenuItemChildren(RefPtr& host) @@ -287,6 +288,30 @@ void MenuPattern::HideMenu() const LOGI("MenuPattern closing menu %{public}d", targetId_); } +void MenuPattern::HideSubMenu() +{ + if (!showedSubMenu_) { + return; + } + auto subMenuPattern = showedSubMenu_->GetPattern(); + CHECK_NULL_VOID(subMenuPattern); + subMenuPattern->RemoveParentHoverStyle(); + + auto menuItem = subMenuPattern->GetParentMenuItem(); + CHECK_NULL_VOID(menuItem); + auto menuItemPattern = menuItem->GetPattern(); + CHECK_NULL_VOID(menuItemPattern); + menuItemPattern->SetIsSubMenuShowed(false); + menuItemPattern->ClearHoverRegions(); + menuItemPattern->ResetWrapperMouseEvent(); + + auto wrapper = GetMenuWrapper(); + CHECK_NULL_VOID(wrapper); + wrapper->RemoveChild(showedSubMenu_); + wrapper->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD); + showedSubMenu_.Reset(); +} + RefPtr MenuPattern::GetMenuWrapper() const { auto host = GetHost(); diff --git a/frameworks/core/components_ng/pattern/menu/menu_pattern.h b/frameworks/core/components_ng/pattern/menu/menu_pattern.h index 732e2e438ca..c65d071d4b5 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_pattern.h +++ b/frameworks/core/components_ng/pattern/menu/menu_pattern.h @@ -151,6 +151,16 @@ public: RefPtr GetMenuColumn() const; + void SetShowedSubMenu(const RefPtr& subMenu) + { + showedSubMenu_ = subMenu; + } + const RefPtr& GetShowedSubMenu() const + { + return showedSubMenu_; + } + void HideSubMenu(); + private: void OnModifyDone() override; void RegisterOnTouch(); @@ -170,6 +180,7 @@ private: MenuType type_ = MenuType::MENU; RefPtr parentMenuItem_; + RefPtr showedSubMenu_; std::vector> options_; bool isSelectMenu_ = false; diff --git a/frameworks/core/components_ng/pattern/menu/menu_view.cpp b/frameworks/core/components_ng/pattern/menu/menu_view.cpp index ec33b789dfa..f63e1dfd001 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_view.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_view.cpp @@ -136,6 +136,11 @@ RefPtr MenuView::Create( auto [wrapperNode, menuNode] = CreateMenu(targetId, type); auto column = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr(true)); + auto columnProps = column->GetLayoutProperty(); + CHECK_NULL_RETURN(columnProps, nullptr); + columnProps->UpdateMainAxisAlign(FlexAlign::CENTER); + columnProps->UpdateCrossAxisAlign(FlexAlign::FLEX_START); + if (!menuParam.title.empty()) { CreateTitleNode(menuParam.title, column); } diff --git a/frameworks/core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.cpp b/frameworks/core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.cpp index 2d1149ee15c..00f907e71e9 100644 --- a/frameworks/core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.cpp +++ b/frameworks/core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.cpp @@ -87,15 +87,24 @@ void MenuWrapperPattern::OnModifyDone() } OffsetF position = OffsetF(touch.GetGlobalLocation().GetX(), touch.GetGlobalLocation().GetY()); position -= GetPageOffset(); - for (const auto& child : host->GetChildren()) { + auto children = host->GetChildren(); + for (auto child = children.rbegin(); child != children.rend(); ++child) { // get menu frame node (child of menu wrapper) - auto menuNode = DynamicCast(child); + auto menuNode = DynamicCast(*child); CHECK_NULL_VOID(menuNode); // get menuNode's touch region auto menuZone = menuNode->GetGeometryNode()->GetFrameRect(); - // if DOWN-touched outside the menu region, then hide menu - if (!menuZone.IsInRegion(PointF(position.GetX(), position.GetY()))) { + // if DOWN-touched inside the top menu, top menu will handle touch event. + if (menuZone.IsInRegion(PointF(position.GetX(), position.GetY()))) { + return; + } + // if DOWN-touched outside the top menu region, then hide menu + auto menuPattern = menuNode->GetPattern(); + CHECK_NULL_VOID(menuPattern); + if (menuPattern->IsSubMenu()) { + pattern->HideSubMenu(); + } else { pattern->HideMenu(menuNode); } } diff --git a/frameworks/core/components_ng/pattern/option/option_pattern.cpp b/frameworks/core/components_ng/pattern/option/option_pattern.cpp index 86df9493494..54051ac4916 100644 --- a/frameworks/core/components_ng/pattern/option/option_pattern.cpp +++ b/frameworks/core/components_ng/pattern/option/option_pattern.cpp @@ -177,7 +177,7 @@ bool OptionPattern::OnKeyEvent(const KeyEvent& event) if (event.action != KeyAction::DOWN) { return false; } - if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_SPACE) { + if (event.code == KeyCode::KEY_ENTER) { OnSelectProcess(); return true; } -- Gitee