本篇wiki将通过新增一个MyCircle组件为例,向大家展示新增一个Ace1.0组件的全流程。
完整的patch链接:http://mgit-tm.rnd.huawei.com/#/c/14477652/
可点击的展示类组件,展示一个圆,支持设置半径、边缘宽度和边缘颜色,可以通过点击事件获得当前圆的半径和边缘宽度。
手机 | 智慧屏 | 智能穿戴 | 轻量级智能穿戴 | 轻车机 |
---|---|---|---|---|
支持 | 支持 | 支持 | 支持 | 支持 |
无
名称 | 属性类型 | 默认值 | 必填 | 描述 |
---|---|---|---|---|
circleradius | 20vp | 否 | 默认半径。 |
名称 | 属性类型 | 默认值 | 必填 | 描述 |
---|---|---|---|---|
circleedge | 2vp red | 否 | 默认边缘颜色和宽度。 |
名称 | 参数类型 | 描述 |
---|---|---|
circleclick | {radius: circle radius, edgewidth: circle edge width} | 点击MyCircle组件时触发该回调,返回当前circle的半径和边缘宽度,单位是px。 |
<!-- xxx.hml -->
<div style="flex-direction: column;align-items: center;">
<text>"MyCircle的半径为:{{radiusOfMyCircle}}"</text>
<text>"MyCircle的边缘宽度为:{{edgeWidthOfMyCircle}}"</text>
<mycircle circleradius="40vp" style="circleedge: 2vp red;" @circleclick="onCircleClick"> </mycircle>
</div>
// xxx.js
export default{
data:{
radiusOfMyCircle: -1,
edgeWidthOfMyCircle: -1,
},
onCircleClick(event) {
this.radiusOfMyCircle = event.radius
this.edgeWidthOfMyCircle = event.edgewidth
}
}
该界面最终效果如下图所示:
js
的界面解析dom_type
中增加新组件的属性定义dom_type.h
中增加MyCircle
的属性定义文件路径为:REPO_ROOT\foundation\ace\ace_engine\frameworks\bridge\common\dom\dom_type.h
// node tag defines
/* .................................... */
/* node tag defines of other components */
/* .................................... */
ACE_EXPORT extern const char DOM_NODE_TAG_MYCIRCLE[];
/* ........................... */
/* defines of other components */
/* ........................... */
// mycircle defines
ACE_EXPORT extern const char DOM_MYCIRCLE_CIRCLE_EDGE[];
ACE_EXPORT extern const char DOM_MYCIRCLE_CIRCLE_RADIUS[];
ACE_EXPORT extern const char DOM_MYCIRCLE_CIRCLE_CLICK[];
dom_type.cpp
中增加MyCircle
的属性值文件路径为:REPO_ROOT\foundation\ace\ace_engine\frameworks\bridge\common\dom\dom_type.cpp
// node tag defines
/* .................................... */
/* node tag defines of other components */
/* .................................... */
const char DOM_NODE_TAG_MYCIRCLE[] = "mycircle";
/* ........................... */
/* defines of other components */
/* ........................... */
// mycircle defines
const char DOM_MYCIRCLE_CIRCLE_EDGE[] = "circleedge";
const char DOM_MYCIRCLE_CIRCLE_RADIUS[] = "circleradius";
const char DOM_MYCIRCLE_CIRCLE_CLICK[] = "circleclick";
MyCircleDeclaration
类MyCircleDeclaration
类负责保存组件属性样式和事件,js
界面中解析出的属性、样式、方法会保存到MyCircleDeclaration
中。
DeclarationConstants
中新增MyCircleDeclaration
的属性、样式、方法定义一、添加到REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\declaration\common\declaration_constants.h
class DeclarationConstants {
public:
/* ............................................. */
/* definition of declaration of other components */
/* ............................................. */
// default value of mycircle
static const std::shared_ptr<MyCircleAttribute> DEFAULT_MYCIRCLE_ATTR;
static const std::shared_ptr<MyCircleStyle> DEFAULT_MYCIRCLE_STYLE;
static const std::shared_ptr<MyCircleEvent> DEFAULT_MYCIRCLE_EVENT;
};
二、添加到REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\declaration\common\declaration_constants.cpp
namespace OHOS::Ace {
/* ................................................. */
/* implementation of declaration of other components */
/* ................................................. */
// default value of mycircle
const std::shared_ptr<MyCircleAttribute> DeclarationConstants::DEFAULT_MYCIRCLE_ATTR =
std::make_shared<MyCircleAttribute>();
const std::shared_ptr<MyCircleStyle> DeclarationConstants::DEFAULT_MYCIRCLE_STYLE = std::make_shared<MyCircleStyle>();
const std::shared_ptr<MyCircleEvent> DeclarationConstants::DEFAULT_MYCIRCLE_EVENT = std::make_shared<MyCircleEvent>();
} // namespace OHOS::Ace
mycircle_declaration.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\declaration\mycircle\mycircle_declaration.h
struct MyCircleAttribute : Attribute {
Dimension circleRadius = 20.0_vp;
};
struct MyCircleStyle : Style {
Dimension edgeWidth = 2.0_vp;
Color edgeColor = Color::RED;
};
struct MyCircleEvent : Event {
EventMarker circleClickEvent;
};
class MyCircleDeclaration : public Declaration {
DECLARE_ACE_TYPE(MyCircleDeclaration, Declaration);
public:
MyCircleDeclaration() = default;
~MyCircleDeclaration() override = default;
void SetCircleRadius(const Dimension& circleRadius);
void SetEdgeWidth(const Dimension& edgeWidth);
void SetEdgeColor(const Color& edgeColor);
void SetCircleClickEvent(const EventMarker& circleClickEvent);
const Dimension& GetCircleRadius() const;
const Dimension& GetEdgeWidth() const;
const Color& GetEdgeColor() const;
const EventMarker& GetCircleClickEvent() const;
protected:
void InitSpecialized() override;
bool SetSpecializedAttr(const std::pair<std::string, std::string>& attr) override;
bool SetSpecializedStyle(const std::pair<std::string, std::string>& style) override;
bool SetSpecializedEvent(int32_t pageId, const std::string& eventId, const std::string& event) override;
};
}
其中, SetSpecializedAttr
/ SetSpecializedStyle
/ SetSpecializedEvent
这三个重写的方法,分别是用于解析组件的属性、样式和事件。
mycircle_declaration.cpp
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\declaration\mycircle\mycircle_declaration.cpp
一、MyCircleDeclaration::InitSpecialized()
void MyCircleDeclaration::InitSpecialized()
{
AddSpecializedAttribute(DeclarationConstants::DEFAULT_MYCIRCLE_ATTR);
AddSpecializedStyle(DeclarationConstants::DEFAULT_MYCIRCLE_STYLE);
AddSpecializedEvent(DeclarationConstants::DEFAULT_MYCIRCLE_EVENT);
}
注意,若是有自定义的Attribute
、Style
或者Event
,必须重写InitSpecialized()
函数,否则会导致crash。
二、组件属性的解析:SetSpecializedAttr
bool MyCircleDeclaration::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
{
if (attr.first == DOM_MYCIRCLE_CIRCLE_RADIUS) { // "circleradius"
auto& mycircleAttr = MaybeResetAttribute<MyCircleAttribute>(AttributeTag::SPECIALIZED_ATTR);
if (mycircleAttr.IsValid()) {
mycircleAttr.circleRadius = StringToDimension(attr.second);
}
return true;
}
return false;
}
这个方法由框架流程调用,我们只需要在这个方法里面实现对应属性的解析,并且保存到MyCircleDeclaration
中。
如上代码中,入参attr
的格式形如<"circleradius", "40vp">
,则我们只需要判断attr.first
为"circleradius"
时,将attr.second
转换为Dimension格式,设置到MyCircleAttribute
中即可。设置完成后,返回true
。
三、组件样式的解析:SetSpecializedStyle
bool MyCircleDeclaration::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
{
if (style.first == DOM_MYCIRCLE_CIRCLE_EDGE) { // "circleedge"
auto& mycircleStyle = MaybeResetStyle<MyCircleStyle>(StyleTag::SPECIALIZED_STYLE);
if (mycircleStyle.IsValid()) {
std::vector<std::string> edgeStyles;
// The value of [circleedge] is like "2vp red" or "2vp". To parse style value like this, we need 3 steps.
// Step1: Split the string value by ' ' to get vectors like ["2vp", "red"].
StringUtils::StringSpliter(style.second, ' ', edgeStyles);
Dimension edgeWidth(1, DimensionUnit::VP);
Color edgeColor(Color::RED);
// Step2: Parse edge color and edge width accordingly.
switch(edgeStyles.size()) {
case 0: // the value is empty
LOGW("Value for circle edge is empty, using default setting.");
break;
case 1: // case when only edge width is set
// It should be guaranteed by the tool chain when generating js-bundle that the only value is a
// number type for edge width rather than a color type for edge color.
edgeWidth = StringUtils::StringToDimension(edgeStyles[0]);
break;
case 2: // case when edge width and edge color are both set
edgeWidth = StringUtils::StringToDimension(edgeStyles[0]);
edgeColor = Color::FromString(edgeStyles[1]);
break;
default:
LOGW("There are more than 2 values for circle edge, please check. The value is %{private}s",
style.second.c_str());
break;
}
// Step3: Set edge color and edge width to [mycircleStyle].
mycircleStyle.edgeWidth = edgeWidth;
mycircleStyle.edgeColor = edgeColor;
}
return true;
}
return false;
}
这个方法由框架流程调用,我们只需要在这个方法里面实现对应样式的解析,并且保存到MyCircleDeclaration
中。
如上代码中,入参style
的格式形如<"circleedge", "2vp red">
,则我们只需要判断style.first
为"circleedge"
时,将style.second
进行解析,设置到MyCircleStyle
中即可。设置完成后,返回true
。
四、组件事件的解析:SetSpecializedEvent
bool MyCircleDeclaration::SetSpecializedEvent(int32_t pageId, const std::string& eventId, const std::string& event)
{
if (event == DOM_MYCIRCLE_CIRCLE_CLICK) { // "circleclick"
auto& mycircleEvent = MaybeResetEvent<MyCircleEvent>(EventTag::SPECIALIZED_EVENT);
if (mycircleEvent.IsValid()) {
mycircleEvent.circleClickEvent = EventMarker(eventId, event, pageId);
}
return true;
}
return false;
}
这个方法由框架流程调用,我们只需要在这个方法里面实现对应事件的解析,并且保存到MyCircleDeclaration
中。
如上代码中,只要判断入参event
的值为"circleclick"
,则我们只需要使用eventId
和pageId
构造一个EventMarker
,并设置到MyCircleEvent
中即可。设置完成后,返回true
。
五、MyCircleAttribute
的Set
和Get
void MyCircleDeclaration::SetCircleRadius(const Dimension& circleRadius)
{
auto& attribute = MaybeResetAttribute<MyCircleAttribute>(AttributeTag::SPECIALIZED_ATTR);
attribute.circleRadius = circleRadius;
}
const Dimension& MyCircleDeclaration::GetCircleRadius() const
{
auto& attribute = static_cast<MyCircleAttribute&>(GetAttribute(AttributeTag::SPECIALIZED_ATTR));
return attribute.circleRadius;
}
六、MyCircleStyle
的Set
和Get
void MyCircleDeclaration::SetEdgeWidth(const Dimension& edgeWidth)
{
auto& style = MaybeResetStyle<MyCircleStyle>(StyleTag::SPECIALIZED_STYLE);
style.edgeWidth = edgeWidth;
}
void MyCircleDeclaration::SetEdgeColor(const Color& edgeColor)
{
auto& style = MaybeResetStyle<MyCircleStyle>(StyleTag::SPECIALIZED_STYLE);
style.edgeColor = edgeColor;
}
const Dimension& MyCircleDeclaration::GetEdgeWidth() const
{
auto& style = static_cast<MyCircleStyle&>(GetStyle(StyleTag::SPECIALIZED_STYLE));
return style.edgeWidth;
}
const Color& MyCircleDeclaration::GetEdgeColor() const
{
auto& style = static_cast<MyCircleStyle&>(GetStyle(StyleTag::SPECIALIZED_STYLE));
return style.edgeColor;
}
七、MyCircleEvent
的Set
和Get
void MyCircleDeclaration::SetCircleClickEvent(const EventMarker& circleClickEvent)
{
auto& event = MaybeResetEvent<MyCircleEvent>(EventTag::SPECIALIZED_EVENT);
event.circleClickEvent = circleClickEvent;
}
const EventMarker& MyCircleDeclaration::GetCircleClickEvent() const
{
auto& event = static_cast<MyCircleEvent&>(GetEvent(EventTag::SPECIALIZED_EVENT));
return event.circleClickEvent;
}
八、添加到declaration_creator_manager.cpp
中
文件路径:REPO_ROOT:\foundation\ace\ace_engine\frameworks\core\components\declaration\common\declaration_creator_manager.cpp
const RefPtr<Declaration> DeclarationCreatorManager::CreateDeclaration(const std::string& tag)
{
static const LinearMapNode<std::function<RefPtr<Declaration>(const std::string&)>> declarationCreators[] = {
/* ..................................................... */
/* declarationCreator of declaration of other components */
/* ..................................................... */
{ DOM_NODE_TAG_LINE, DeclarationCreator<SvgLineDeclaration> },
{ DOM_NODE_TAG_MYCIRCLE, DeclarationCreator<MyCircleDeclaration> },
{ DOM_NODE_TAG_PATH, DeclarationCreator<SvgPathDeclaration> },
/* ..................................................... */
/* declarationCreator of declaration of other components */
/* ..................................................... */
};
// code block
return declaration;
}
这里尤其要注意一点,declarationCreators[]
是一个线性表,添加 { DOM_NODE_TAG_MYCIRCLE, DeclarationCreator<MyCircleDeclaration> }
的地方必须要符合字母序。
DOM_NODE_TAG_LINE[] = "line"
DOM_NODE_TAG_MYCIRCLE[] = "mycircle"
DOM_NODE_TAG_PATH[] = "path"
所以DOM_NODE_TAG_MYCIRCLE
的记录必须添加在"line"
之后,"path"
之前。
DOMMyCircle
类dom_mycircle.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\bridge\common\dom\dom_mycircle.h
class DOMMyCircle final : public DOMNode {
DECLARE_ACE_TYPE(DOMMyCircle, DOMNode);
public:
DOMMyCircle(NodeId nodeId, const std::string& nodeName);
~DOMMyCircle() override = default;
RefPtr<Component> GetSpecializedComponent() override
{
return myCircleChild_;
}
void ResetInitializedStyle() override;
void InitializeStyle() override;
protected:
void PrepareSpecializedComponent() override;
private:
RefPtr<MyCircleComponent> myCircleChild_;
};
DOMMyCircle
继承自DOMNode
,主要功能是解析界面并生成相应的Component
节点。
dom_mycircle.cpp
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\bridge\common\dom\dom_mycircle.cpp
一、 在构造的时候创建MyCircleComponent
DOMMyCircle::DOMMyCircle(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
{
myCircleChild_ = AceType::MakeRefPtr<MyCircleComponent>();
}
二、重写PrepareSpecializedComponent
方法
void DOMMyCircle::PrepareSpecializedComponent()
{
const auto& declaration = AceType::DynamicCast<MyCircleDeclaration>(declaration_);
if (!declaration) {
LOGE("mycircle declaration is null!");
return;
}
myCircleChild_->SetDeclaration(declaration);
}
只要在该方法中将DOMMyCircle
的declaration_
成员变量设给myCircleChild_
即可。
三、重写InitializeStyle
和ResetInitializedStyle
方法
void DOMMyCircle::InitializeStyle()
{
auto declaration = AceType::DynamicCast<MyCircleDeclaration>(declaration_);
if (!declaration) {
LOGE("mycircle declaration is null!");
return;
}
declaration->InitializeStyle();
}
void DOMMyCircle::ResetInitializedStyle()
{
InitializeStyle();
}
dom_document.cpp
里增加mycircle
组件文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\bridge\common\dom\dom_document.cpp
RefPtr<DOMNode> DOMDocument::CreateNodeWithId(const std::string& tag, NodeId nodeId, int32_t itemIndex)
{
// code block
static const LinearMapNode<RefPtr<DOMNode>(*)(NodeId, const std::string&, int32_t)> domNodeCreators[] = {
// DomNodeCreators of other components
{ DOM_NODE_TAG_MENU, &DOMNodeCreator<DOMMenu> },
// "mycircle" must be inserted between "menu" and "navigation-bar"
{ DOM_NODE_TAG_MYCIRCLE, &DOMNodeCreator<DOMMyCircle> },
{ DOM_NODE_TAG_NAVIGATION_BAR, &DOMNodeCreator<DomNavigationBar> },
// DomNodeCreators of other components
};
// code block
return domNode;
}
这里尤其要注意一点,domNodeCreators[]
是一个线性表,添加{ DOM_NODE_TAG_MYCIRCLE, &DOMNodeCreator<DOMMyCircle> }
的地方必须要符合字母序。
DOM_NODE_TAG_MENUp[] = "menu",
DOM_NODE_TAG_NAVIGATION_BAR[] = "navigation-bar",
DOM_NODE_TAG_MYCIRCLE[] = "mycircle"
所以DOM_NODE_TAG_MYCIRCLE
的记录必须添加在"menu"
之后,"navigation-bar"
之前。
组件在后端的布局和绘制,需要相应地新增以下几个类:MyCircleComponent
、MyCircleElement
、RenderMyCircle
、FlutterRenderMyCircle
。
在后端引擎中,Component
树、Element
树和Render
树为后端引擎维持和更新UI最为核心的三棵树。这三棵树之间的更新关系大致如下图所示:
MyCircleComponent
类mycircle_component.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\mycircle_component.h
class ACE_EXPORT MyCircleComponent : public RenderComponent {
DECLARE_ACE_TYPE(MyCircleComponent, RenderComponent);
public:
MyCircleComponent();
~MyCircleComponent() override = default;
RefPtr<RenderNode> CreateRenderNode() override;
RefPtr<Element> CreateElement() override;
void SetCircleRadius(const Dimension& circleRadius);
void SetEdgeWidth(const Dimension& edgeWidth);
void SetEdgeColor(const Color& edgeColor);
void SetCircleClickEvent(const EventMarker& circleClickEvent);
const Dimension& GetCircleRadius() const;
const Dimension& GetEdgeWidth() const;
const Color& GetEdgeColor() const;
const EventMarker& GetCircleClickEvent() const;
void SetDeclaration(const RefPtr<MyCircleDeclaration>& declaration);
const RefPtr<MyCircleDeclaration>& GetDeclaration() const;
private:
RefPtr<MyCircleDeclaration> declaration_;
};
mycircle_component.cpp
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\mycircle_component.cpp
一、构造时初始化declaration
MyCircleComponent::MyCircleComponent()
{
// Init declaration while component is constructing
if (!declaration_) {
declaration_ = AceType::MakeRefPtr<MyCircleDeclaration>();
declaration_->Init();
}
}
二、将MyCircleComponent
的Set
和Get
接口桥接到MyCircleDeclaration
上
void MyCircleComponent::SetCircleRadius(const Dimension& circleRadius)
{
declaration_->SetCircleRadius(circleRadius);
}
void MyCircleComponent::SetEdgeWidth(const Dimension& edgeWidth)
{
declaration_->SetEdgeWidth(edgeWidth);
}
void MyCircleComponent::SetEdgeColor(const Color& edgeColor)
{
declaration_->SetEdgeColor(edgeColor);
}
void MyCircleComponent::SetCircleClickEvent(const EventMarker& circleClickEvent)
{
declaration_->SetCircleClickEvent(circleClickEvent);
}
const Dimension& MyCircleComponent::GetCircleRadius() const
{
return declaration_->GetCircleRadius();
}
const Dimension& MyCircleComponent::GetEdgeWidth() const
{
return declaration_->GetEdgeWidth();
}
const Color& MyCircleComponent::GetEdgeColor() const
{
return declaration_->GetEdgeColor();
}
const EventMarker& MyCircleComponent::GetCircleClickEvent() const
{
return declaration_->GetCircleClickEvent();
}
三、实现CreateRenderNode
和CreateElement
函数
RefPtr<RenderNode> MyCircleComponent::CreateRenderNode()
{
return RenderMyCircle::Create();
}
RefPtr<Element> MyCircleComponent::CreateElement()
{
return AceType::MakeRefPtr<MyCircleElement>();
}
四、提供declaration_
的Set
和Get
接口
const RefPtr<MyCircleDeclaration>& MyCircleComponent::GetDeclaration() const
{
return declaration_;
}
void MyCircleComponent::SetDeclaration(const RefPtr<MyCircleDeclaration>& declaration)
{
declaration_ = declaration;
}
MyCircleElement
类mycircle_element.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\mycircle_element.h
class MyCircleElement : public RenderElement {
DECLARE_ACE_TYPE(MyCircleElement, RenderElement);
public:
MyCircleElement() = default;
~MyCircleElement() override = default;
};
该组件在element
层不涉及更多操作,只需要定义MyCircleElement
类即可。
RenderMyCircle
类render_mycircle.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\render_mycircle.h
using CallbackForDeclarative = std::function<void(const std::shared_ptr<BaseEventInfo>&)>;
using CallbackForJS = std::function<void(const std::string&)>;
class RenderMyCircle : public RenderNode {
DECLARE_ACE_TYPE(RenderMyCircle, RenderNode);
public:
static RefPtr<RenderNode> Create();
void Update(const RefPtr<Component>& component) override;
void PerformLayout() override;
void HandleMyCircleClickEvent(const ClickInfo& info);
protected:
RenderMyCircle();
void OnTouchTestHit(
const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result) override;
Dimension circleRadius_;
Dimension edgeWidth_ = Dimension(1);
Color edgeColor_ = Color::RED;
CallbackForDeclarative callbackForDeclarative_; // callback for declarative frontend
CallbackForJS callbackForJS_; // callback for js frontend
RefPtr<ClickRecognizer> clickRecognizer_;
RefPtr<MyCircleDeclaration> declaration_;
};
注意,我们现在是js
前端和ets
前端共用同一个后端,所以后端要对js
前端事件和ets
前端事件都做响应。因为这两个前端的事件格式不同,所以这里定义了CallbackForDeclarative
和CallbackForJS
分别响应两种前端事件。
在开发js
前端组件时,可以忽略ets
前端事件。
render_mycircle.cpp
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\render_mycircle.cpp
一、处理点击事件
RenderMyCircle::RenderMyCircle()
{
clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
clickRecognizer_->SetOnClick([wp = WeakClaim(this)](const ClickInfo& info) {
auto myCircle = wp.Upgrade();
if (!myCircle) {
LOGE("WeakPtr of RenderMyCircle fails to be upgraded, stop handling click event.");
return;
}
myCircle->HandleMyCircleClickEvent(info);
});
}
void RenderMyCircle::OnTouchTestHit(
const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
{
clickRecognizer_->SetCoordinateOffset(coordinateOffset);
result.emplace_back(clickRecognizer_);
}
void RenderMyCircle::HandleMyCircleClickEvent(const ClickInfo& info)
{
auto pipelineContext = context_.Upgrade();
if (!pipelineContext) {
LOGE("PipelineContext is null!");
return;
}
if (pipelineContext->GetIsDeclarative() && callbackForDeclarative_) {
callbackForDeclarative_(
std::make_shared<MyCircleClickEvent>(NormalizeToPx(circleRadius_), NormalizeToPx(edgeWidth_)));
return;
}
if (callbackForJS_) {
auto result = std::string("\"circleclick\",{\"radius\":")
.append(std::to_string(NormalizeToPx(circleRadius_)))
.append(",\"edgewidth\":")
.append(std::to_string(NormalizeToPx(edgeWidth_)))
.append("}");
callbackForJS_(result);
}
}
1、创建一个ClickRecognizer
;
2、重写OnTouchTestHit
函数,注册RenderMyCircle
的ClickRecognizer
,这样在接收到点击事件时即可触发创建ClickRecognizer
时添加的事件回调;
3、实现在接收到点击事件之后的处理逻辑HandleMyCircleClickEvent
再次说明,示例代码是已经同时支持了js
前端和ets
前端,在单单开发js
前端组件时,可以忽略ets
前端事件。
二、重写Update
函数
void RenderMyCircle::Update(const RefPtr<Component>& component)
{
const auto& myCircleComponent = AceType::DynamicCast<MyCircleComponent>(component);
if (!myCircleComponent) {
LOGE("MyCircleComponent is null!");
return;
}
auto pipelineContext = context_.Upgrade();
if (!pipelineContext) {
LOGE("PipelineContext is null!");
return;
}
declaration_ = myCircleComponent->GetDeclaration();
circleRadius_ = declaration_->GetCircleRadius();
edgeWidth_ = declaration_->GetEdgeWidth();
edgeColor_ = declaration_->GetEdgeColor();
if (pipelineContext->GetIsDeclarative()) {
callbackForDeclarative_ = AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(
declaration_->GetCircleClickEvent(), context_);
} else {
callbackForJS_ =
AceAsyncEvent<void(const std::string&)>::Create(declaration_->GetCircleClickEvent(), context_);
}
// call [MarkNeedLayout] to do [PerformLayout] with new params
MarkNeedLayout();
}
Update
函数负责从MyCircleComponent
获取所有绘制、布局和事件相关的属性更新。
三、重写PerformLayout
函数
void RenderMyCircle::PerformLayout()
{
double realSize = NormalizeToPx(edgeWidth_) + 2 * NormalizeToPx(circleRadius_);
Size layoutSizeAfterConstrain = GetLayoutParam().Constrain(Size(realSize, realSize));
SetLayoutSize(layoutSizeAfterConstrain);
}
PerformLayout
函数负责计算布局信息,并且调用SetLayoutSize
函数设置自己所需要的布局大小。
FlutterRenderMyCircle
类flutter_render_mycircle.h
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\flutter_render_mycircle.h
class FlutterRenderMyCircle final : public RenderMyCircle { DECLARE_ACE_TYPE(FlutterRenderMyCircle, RenderMyCircle);public: FlutterRenderMyCircle() = default; ~FlutterRenderMyCircle() override = default; void Paint(RenderContext& context, const Offset& offset) override;};
flutter_render_mycircle.cpp
文件路径:REPO_ROOT\foundation\ace\ace_engine\frameworks\core\components\mycircle\flutter_render_mycircle.cpp
一、实现RenderMyCircle::Create()
函数
RefPtr<RenderNode> RenderMyCircle::Create()
{
return AceType::MakeRefPtr<FlutterRenderMyCircle>();
}
RenderMyCircle::Create()
在基类RenderMyCircle
中定义,因为我们当前使用的是flutter
引擎,所以在flutter_render_mycircle.cpp
里面实现,返回在flutter
引擎上自渲染的FlutterRenderMyCircle
类。
二、重写Paint
函数
void FlutterRenderMyCircle::Paint(RenderContext& context, const Offset& offset)
{
auto canvas = ScopedCanvas::Create(context);
if (!canvas) {
LOGE("Paint canvas is null");
return;
}
SkPaint skPaint;
skPaint.setAntiAlias(true);
skPaint.setStyle(SkPaint::Style::kStroke_Style);
skPaint.setColor(edgeColor_.GetValue());
skPaint.setStrokeWidth(NormalizeToPx(edgeWidth_));
auto paintRadius = GetLayoutSize().Width() / 2.0;
canvas->canvas()->drawCircle(offset.GetX() + paintRadius, offset.GetY() + paintRadius,
NormalizeToPx(circleRadius_), skPaint);
}
Paint
函数负责调用canvas相应接口去进行绘制,这一步可以认为是新增组件的最后一步,直接决定在屏幕上绘制什么样的UI界面。
到目前为止,上述的代码已经完成mycircle
组件的功能的开发。接下来,我们来对mycircle
组件进行进一步的验证。(以下验证工作都假设在Windows
环境下的IDE
预览器上进行。)
验证工作主要分为以下几个步骤:
1.编译
IDE工具
所需的最新sdk
文件和预览器所需最新dll
文件。(编译命令已放在步骤后)sdk
主要包含js
相关文件的修改,dll
文件包含将代码进行打包后生成的文件。2.将步骤1中编出的
sdk
与dll
文件在IDE
工具所在的目录下进行替换。(具体路径放在步骤后)3.参考示例编写代码,编写完成在右侧工具栏选择
Previewer
选项打开预览器插件观察效果。(建议使用悬浮窗口便于观察,可以采用鼠标对上述组件进行点击。)4.如果需要更改新增的底层代码,首先需要关闭
Previewer
插件防止插件占用导致替换dll
文件失败。重复步骤1
和步骤2
即可。
编译命令:
参考官方指导,下载OpenHarmony完整代码,需要在Linux的环境下执行以下命令进行交叉编译:
# 编译dll文件
./build.sh --product-name m40 --gn-args use_musl=false --gn-args use_custom_libcxx=true --gn-args use_custom_clang=true --build-target ace_for_windows
# 编译sdk命令
./build.sh --product-name ohos-sdk
获取编译产物:
在out\ohos-arm-release\mingw_x86_64\common\common
目录下拷贝所有文件,包含多个exe
及dll
库文件。
在out\release\packages\ohos-sdk\windows
目录下,包含sdk
相关文件。
替换sdk与dll文件:
替换sdk
文件:将out\release\packages\ohos-sdk\windows
下的文件js压缩包解压,将里面的build-tools
,form
文件夹替换至HarmonyOS SDK
所在目录的路径为[Huawei Sdk]\js\[sdk对应版本号]的目录下
,替换完成后进入build-tools\ace-loader\
,执行npm install
即可。
替换dll
文件:将out\ohos-arm-release\mingw_x86_64\common\common
下的libace_engine_windows.dll
文件替换至HarmonyOS SDK
所在目录的路径为[Huawei Sdk]\previewer\[sdk对应版本号]\tv\bin
目录下对应的文件即可。
准备应用程序:
新建IDE
工程,选择Empty Ability
,在文件中加入示例代码。
运行:
在IDE工具
右侧选择Previewer
选项进行预览操作。如若需要修改代码查看效果,编写完代码重复编译命令、获取编译产物、替换sdk
与dll
文件、运行步骤即可。
到这里,新增一个mycircle
组件所需的所有步骤都已经完成,我们可以展示一个圆,支持设置半径、边缘宽度和边缘颜色,可以通过点击事件获得当前圆的半径和边缘宽度。
当然mycircle
组件是比较简单的示例组件,Ace开发框架支持更多更复杂的组件开发,比如提供单行文本输入组件TextInput
、提供日历展示的Calendar
组件等,更多的用法期待你来探索~
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。