!29986 Feat:Checkbox组件支持自定义选中指示内容

Merge pull request !29986 from yangziyong/checkbox_builder
This commit is contained in:
openharmony_ci 2024-04-09 14:51:03 +00:00 committed by Gitee
commit 4f30b2cb53
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 232 additions and 3 deletions

View File

@ -23,8 +23,10 @@
#include "bridge/declarative_frontend/jsview/js_view_common_def.h"
#include "bridge/declarative_frontend/jsview/models/checkbox_model_impl.h"
#include "bridge/declarative_frontend/view_stack_processor.h"
#include "core/common/container.h"
#include "core/components/checkable/checkable_component.h"
#include "core/components_ng/base/view_abstract.h"
#include "core/components_ng/base/view_stack_model.h"
#include "core/components_ng/base/view_stack_processor.h"
#include "core/components_ng/pattern/checkbox/checkbox_model_ng.h"
#include "core/components_v2/inspector/inspector_constants.h"
@ -61,6 +63,7 @@ void JSCheckbox::Create(const JSCallbackInfo& info)
{
auto checkboxName = std::optional<std::string>("");
auto checkboxGroup = std::optional<std::string>("");
std::optional<std::function<void()>> customBuilderFunc;
if ((info.Length() >= 1) && info[0]->IsObject()) {
auto paramObject = JSRef<JSObject>::Cast(info[0]);
auto name = paramObject->GetProperty("name");
@ -71,8 +74,25 @@ void JSCheckbox::Create(const JSCallbackInfo& info)
if (group->IsString()) {
checkboxGroup = group->ToString();
}
auto builderObject = paramObject->GetProperty("indicatorBuilder");
if (builderObject->IsFunction()) {
auto builderFunc = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(builderObject));
CHECK_NULL_VOID(builderFunc);
auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
auto callbackFunc = [execCtx = info.GetExecutionContext(),
func = std::move(builderFunc), node = targetNode]() {
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
ACE_SCORING_EVENT("CheckBox.builder");
PipelineContext::SetCallBackNode(node);
func->Execute();
};
customBuilderFunc = std::move(callbackFunc);
}
}
CheckBoxModel::GetInstance()->Create(checkboxName, checkboxGroup, V2::CHECK_BOX_ETS_TAG);
if (customBuilderFunc.has_value()) {
CheckBoxModel::GetInstance()->SetBuilder(customBuilderFunc);
}
}
void JSCheckbox::JSBind(BindingTarget globalObj)

View File

@ -250,8 +250,13 @@ public:
theme->width_ = checkboxPattern->GetAttr<Dimension>("checkbox_size", 0.0_vp);
theme->height_ = theme->width_;
theme->hotZoneHorizontalPadding_ = checkboxPattern->GetAttr<Dimension>("checkbox_hotzone_padding", 0.0_vp);
theme->hotZoneVerticalPadding_ = theme->hotZoneHorizontalPadding_;
theme->defaultWidth_ = checkboxPattern->GetAttr<Dimension>("checkbox_default_size", 0.0_vp);
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
theme->hotZoneHorizontalPadding_ =
checkboxPattern->GetAttr<Dimension>("checkbox_hotzone_padding_twelve", 2.0_vp);
theme->defaultWidth_ = checkboxPattern->GetAttr<Dimension>("checkbox_default_size_twelve", 24.0_vp);
}
theme->hotZoneVerticalPadding_ = theme->hotZoneHorizontalPadding_;
theme->defaultHeight_ = theme->defaultWidth_;
theme->needFocus_ = static_cast<bool>(checkboxPattern->GetAttr<double>("checkbox_need_focus", 0.0));
theme->backgroundSolid_ =
@ -284,6 +289,12 @@ public:
if (SystemProperties::GetDeviceType() != DeviceType::CAR) {
return;
}
SetCheckboxSize(themeConstants, theme);
}
void SetCheckboxSize(const RefPtr<ThemeConstants>& themeConstants, const RefPtr<CheckboxTheme>& theme) const
{
RefPtr<ThemeStyle> checkboxPattern = themeConstants->GetPatternByName(THEME_PATTERN_CHECKBOX);
// width/height/borderRadius not exist in theme
theme->width_ = checkboxPattern->GetAttr<Dimension>("width", 26.0_vp);
theme->height_ = theme->width_;
@ -291,6 +302,11 @@ public:
theme->hotZoneHorizontalPadding_ =
checkboxPattern->GetAttr<Dimension>("hotzone_padding_horizontal", 11.0_vp);
theme->hotZoneVerticalPadding_ = theme->hotZoneHorizontalPadding_;
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
theme->hotZoneHorizontalPadding_ =
checkboxPattern->GetAttr<Dimension>("checkbox_hotzone_padding_twelve", 2.0_vp);
theme->hotZoneVerticalPadding_ = theme->hotZoneHorizontalPadding_;
}
}
};

View File

@ -105,4 +105,34 @@ void CheckBoxLayoutAlgorithm::InitializeParam()
verticalPadding_ = checkBoxTheme->GetHotZoneVerticalPadding().ConvertToPx();
}
void CheckBoxLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
{
CHECK_NULL_VOID(layoutWrapper);
BoxLayoutAlgorithm::Layout(layoutWrapper);
auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
MinusPaddingToSize(padding, size);
auto left = padding.left.value_or(0);
auto top = padding.top.value_or(0);
auto paddingOffset = OffsetF(left, top);
auto align = Alignment::CENTER;
auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
CHECK_NULL_VOID(childWrapper);
SizeF childSize = childWrapper->GetGeometryNode()->GetMarginFrameSize();
NG::OffsetF child_offset;
child_offset.SetX((1.0 + align.GetHorizontal()) * (size.Width() - childSize.Width()) / 2.0);
child_offset.SetY((1.0 + align.GetVertical()) * (size.Height() - childSize.Height()) / 2.0);
auto translate = child_offset + paddingOffset;
childWrapper->GetGeometryNode()->SetMarginFrameOffset(translate);
childWrapper->Layout();
const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
if (content) {
NG::OffsetF offset;
offset.SetX((1.0 + align.GetHorizontal()) * (size.Width() - content->GetRect().GetSize().Width()) / 2.0);
offset.SetY((1.0 + align.GetVertical()) * (size.Height() - content->GetRect().GetSize().Height()) / 2.0);
auto translate = offset + paddingOffset;
content->SetOffset(translate);
}
}
} // namespace OHOS::Ace::NG

View File

@ -33,6 +33,8 @@ public:
void OnReset() override {}
void Layout(LayoutWrapper* layoutWrapper) override;
std::optional<SizeF> MeasureContent(
const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper) override;
@ -43,7 +45,6 @@ private:
float defaultHeight_ = 0.0f;
float horizontalPadding_ = 0.0f;
float verticalPadding_ = 0.0f;
void InitializeParam();
ACE_DISALLOW_COPY_AND_MOVE(CheckBoxLayoutAlgorithm);

View File

@ -33,6 +33,7 @@ public:
virtual void SetSelect(bool isSelected);
virtual void SetSelectedColor(const Color& color);
virtual void SetUnSelectedColor(const Color& color) {}
virtual void SetBuilder(std::optional<std::function<void(void)>>& buildFunc) {};
virtual void SetCheckMarkColor(const Color& color) {}
virtual void SetCheckMarkSize(const Dimension& size) {}
virtual void SetCheckMarkWidth(const Dimension& width) {}

View File

@ -71,6 +71,16 @@ void CheckBoxModelNG::SetUnSelectedColor(const Color& color)
{
ACE_UPDATE_PAINT_PROPERTY(CheckBoxPaintProperty, CheckBoxUnSelectedColor, color);
}
void CheckBoxModelNG::SetBuilder(std::optional<std::function<void(void)>>& buildFunc)
{
const auto& frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
CHECK_NULL_VOID(frameNode);
auto checkBoxPattern = frameNode->GetPattern<CheckBoxPattern>();
CHECK_NULL_VOID(checkBoxPattern);
checkBoxPattern->SetIndicatorBuilder(buildFunc);
}
void CheckBoxModelNG::SetCheckboxStyle(CheckBoxStyle checkboxStyle)
{
ACE_UPDATE_PAINT_PROPERTY(CheckBoxPaintProperty, CheckBoxSelectedStyle, checkboxStyle);

View File

@ -38,6 +38,7 @@ public:
void SetSelect(bool isSelected) override;
void SetSelectedColor(const Color& color) override;
void SetUnSelectedColor(const Color& color) override;
void SetBuilder(std::optional<std::function<void(void)>>& buildFunc) override;
void SetCheckMarkColor(const Color& color) override;
void SetCheckMarkSize(const Dimension& size) override;
void SetCheckMarkWidth(const Dimension& width) override;

View File

@ -31,6 +31,7 @@
#include "core/components_ng/render/paint_wrapper.h"
namespace OHOS::Ace::NG {
class CheckBoxModifier : public ContentModifier {
DECLARE_ACE_TYPE(CheckBoxModifier, ContentModifier);
@ -78,6 +79,8 @@ public:
isSelect_->Get() ? LinearColor(Color::TRANSPARENT) : LinearColor(inactiveColor_));
animatableShadowColor_->Set(
isSelect_->Get() ? LinearColor(shadowColor_) : LinearColor(shadowColor_.BlendOpacity(0)));
opacityScale_->Set(isSelect_->Get() ? 1.0f : 0.0f);
borderOpacityScale_->Set(isSelect_->Get() ? 0.0f : 1.0f);
});
}
@ -194,6 +197,11 @@ public:
hoverEffectType_ = hoverEffectType;
}
void SetHasBuilder(bool hasBuilder)
{
hasBuilder_ = hasBuilder;
}
private:
void DrawRectOrCircle(RSCanvas& canvas, const RSRoundRect& rrect) const;
@ -220,6 +228,7 @@ private:
float hoverToTouchDuration_ = 0.0f;
float touchDuration_ = 0.0f;
float colorAnimationDuration_ = 0.0f;
bool hasBuilder_ = false;
OffsetF hotZoneOffset_;
SizeF hotZoneSize_;
TouchHoverAnimationType touchHoverType_ = TouchHoverAnimationType::NONE;
@ -239,6 +248,8 @@ private:
RefPtr<PropertyBool> isFocused_;
RefPtr<AnimatablePropertyOffsetF> offset_;
RefPtr<AnimatablePropertySizeF> size_;
RefPtr<AnimatablePropertyFloat> opacityScale_;
RefPtr<AnimatablePropertyFloat> borderOpacityScale_;
ACE_DISALLOW_COPY_AND_MOVE(CheckBoxModifier);
};

View File

@ -56,6 +56,8 @@ CheckBoxModifier::CheckBoxModifier(
animatableCheckColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(checkColor));
animatableBorderColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(borderColor));
animatableShadowColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(shadowColor));
opacityScale_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(1.0f);
borderOpacityScale_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
checkStroke_ =
AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(checkBoxTheme->GetCheckStroke().ConvertToPx()));
strokeSize_ =
@ -73,6 +75,8 @@ CheckBoxModifier::CheckBoxModifier(
AttachProperty(animatableBorderColor_);
AttachProperty(animatableShadowColor_);
AttachProperty(animateTouchHoverColor_);
AttachProperty(opacityScale_);
AttachProperty(borderOpacityScale_);
AttachProperty(checkStroke_);
AttachProperty(strokeSize_);
AttachProperty(isSelect_);
@ -126,6 +130,9 @@ void CheckBoxModifier::PaintCheckBox(RSCanvas& canvas, const OffsetF& paintOffse
RSPen shadowPen = RSPen(pen);
RSBrush brush;
brush.SetColor(ToRSColor(animatableBoardColor_->Get()));
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
brush.SetColor(ToRSColor(animatableBoardColor_->Get().BlendOpacity(opacityScale_->Get())));
}
brush.SetAntiAlias(true);
if (!enabled_->Get()) {
brush.SetColor(
@ -138,6 +145,9 @@ void CheckBoxModifier::PaintCheckBox(RSCanvas& canvas, const OffsetF& paintOffse
// draw border
pen.SetColor(ToRSColor(animatableBorderColor_->Get()));
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
pen.SetColor(ToRSColor(animatableBorderColor_->Get().BlendOpacity(borderOpacityScale_->Get())));
}
if (!enabled_->Get()) {
pen.SetColor(
ToRSColor(animatableBorderColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
@ -151,8 +161,13 @@ void CheckBoxModifier::PaintCheckBox(RSCanvas& canvas, const OffsetF& paintOffse
// draw check
pen.SetColor(ToRSColor(animatableCheckColor_->Get()));
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
pen.SetColor(ToRSColor(animatableCheckColor_->Get().BlendOpacity(opacityScale_->Get())));
}
shadowPen.SetColor(ToRSColor(animatableShadowColor_->Get()));
DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
if (!hasBuilder_) {
DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
}
}
void CheckBoxModifier::DrawFocusBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const

View File

@ -33,6 +33,7 @@
namespace OHOS::Ace::NG {
namespace {
const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
constexpr int32_t DEFAULT_CHECKBOX_ANIMATION_DURATION = 100;
}
void CheckBoxPattern::OnAttachToFrameNode()
@ -42,9 +43,39 @@ void CheckBoxPattern::OnAttachToFrameNode()
host->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER);
}
void CheckBoxPattern::SetBuilderNodeHidden()
{
CHECK_NULL_VOID(builderNode_);
auto layoutProperty = builderNode_->GetLayoutProperty();
CHECK_NULL_VOID(layoutProperty);
layoutProperty->UpdateVisibility(VisibleType::GONE);
}
void CheckBoxPattern::UpdateIndicator()
{
if (builder_.has_value()) {
LoadBuilder();
auto host = GetHost();
CHECK_NULL_VOID(host);
auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
CHECK_NULL_VOID(paintProperty);
bool isSelected = false;
if (paintProperty->HasCheckBoxSelect()) {
isSelected = paintProperty->GetCheckBoxSelectValue();
if (!isSelected) {
SetBuilderNodeHidden();
}
} else {
paintProperty->UpdateCheckBoxSelect(false);
SetBuilderNodeHidden();
}
}
}
void CheckBoxPattern::OnModifyDone()
{
Pattern::OnModifyDone();
UpdateIndicator();
UpdateState();
auto host = GetHost();
CHECK_NULL_VOID(host);
@ -441,9 +472,87 @@ void CheckBoxPattern::ChangeSelfStatusAndNotify(const RefPtr<CheckBoxPaintProper
FireBuilder();
}
void CheckBoxPattern::StartEnterAnimation()
{
AnimationOption option;
option.SetCurve(Curves::FAST_OUT_SLOW_IN);
option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
CHECK_NULL_VOID(builderNode_);
const auto& renderContext = builderNode_->GetRenderContext();
CHECK_NULL_VOID(renderContext);
renderContext->UpdateOpacity(0);
const auto& layoutProperty = builderNode_->GetLayoutProperty();
CHECK_NULL_VOID(layoutProperty);
layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
const auto& eventHub = builderNode_->GetEventHub<EventHub>();
if (eventHub) {
eventHub->SetEnabled(true);
}
AnimationUtils::Animate(
option,
[&]() {
renderContext->UpdateOpacity(1);
},
nullptr);
}
void CheckBoxPattern::StartExitAnimation()
{
AnimationOption option;
option.SetCurve(Curves::FAST_OUT_SLOW_IN);
option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
CHECK_NULL_VOID(builderNode_);
const auto& renderContext = builderNode_->GetRenderContext();
CHECK_NULL_VOID(renderContext);
AnimationUtils::Animate(
option,
[&]() {
renderContext->UpdateOpacity(0);
},
nullptr);
const auto& eventHub = builderNode_->GetEventHub<EventHub>();
if (eventHub) {
eventHub->SetEnabled(false);
}
}
void CheckBoxPattern::LoadBuilder()
{
RefPtr<UINode> customNode;
if (builder_.has_value()) {
auto host = GetHost();
CHECK_NULL_VOID(host);
auto childNode = DynamicCast<FrameNode>(host->GetFirstChild());
if (!childNode) {
NG::ScopedViewStackProcessor builderViewStackProcessor;
builder_.value()();
customNode = NG::ViewStackProcessor::GetInstance()->Finish();
CHECK_NULL_VOID(customNode);
childNode = AceType::DynamicCast<FrameNode>(customNode);
CHECK_NULL_VOID(childNode);
builderNode_ = childNode;
}
childNode->MountToParent(host);
host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
}
}
void CheckBoxPattern::StartCustomNodeAnimation(bool select)
{
if (!isFirstCreated_ && builder_.has_value()) {
if (select) {
StartEnterAnimation();
} else {
StartExitAnimation();
}
}
}
void CheckBoxPattern::UpdateCheckBoxGroupStatus(const RefPtr<FrameNode>& checkBoxFrameNode,
std::unordered_map<std::string, std::list<WeakPtr<FrameNode>>>& checkBoxGroupMap, bool select)
{
StartCustomNodeAnimation(select);
checkBoxFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
auto group = GetGroupNameWithNavId();
std::vector<std::string> vec;

View File

@ -86,6 +86,7 @@ public:
checkboxStyle = paintProperty->GetCheckBoxSelectedStyleValue(CheckBoxStyle::CIRCULAR_STYLE);
}
checkboxModifier_->SetCheckboxStyle(checkboxStyle);
checkboxModifier_->SetHasBuilder(builder_.has_value());
host->SetCheckboxFlag(true);
auto paintMethod = MakeRefPtr<CheckBoxPaintMethod>(checkboxModifier_);
auto eventHub = host->GetEventHub<EventHub>();
@ -171,6 +172,11 @@ public:
isUserSetResponseRegion_ = isUserSetResponseRegion;
}
void SetIndicatorBuilder(const std::optional<std::function<void()>>& buildFunc)
{
builder_ = buildFunc.value_or(nullptr);
}
void ToJsonValue(std::unique_ptr<JsonValue>& json) const override
{
Pattern::ToJsonValue(json);
@ -221,6 +227,12 @@ private:
void HandleFocusEvent();
void HandleBlurEvent();
void CheckPageNode();
void StartCustomNodeAnimation(bool select);
void LoadBuilder();
void UpdateIndicator();
void SetBuilderNodeHidden();
void StartEnterAnimation();
void StartExitAnimation();
void UpdateState();
void UpdateUnSelect();
void UpdateCheckBoxGroupStatus(const RefPtr<FrameNode>& frameNode,
@ -271,6 +283,9 @@ private:
SizeF hotZoneSize_;
TouchHoverAnimationType touchHoverType_ = TouchHoverAnimationType::NONE;
OriginalCheckBoxStyle originalStyle_ = OriginalCheckBoxStyle::CIRCULAR_STYLE;
RefPtr<FrameNode> builderNode_;
std::optional<std::function<void()>> builder_;
RefPtr<CheckBoxModifier> checkboxModifier_;
WeakPtr<GroupManager> groupManager_;