mirror of
https://gitee.com/openharmony/arkui_ace_engine
synced 2024-11-27 01:03:08 +00:00
!4484 【UI组件重构】grid组件支持columnsTemplate、rowsTemplate以及grid item组件不带任何属性
Merge pull request !4484 from chenxuankai1/poor_grid_and_grid_item
This commit is contained in:
commit
cdb2755ed7
@ -18,6 +18,9 @@
|
||||
#include "bridge/declarative_frontend/jsview/js_view_common_def.h"
|
||||
#include "core/common/ace_application_info.h"
|
||||
#include "core/common/container.h"
|
||||
#include "core/components_ng/base/view_abstract.h"
|
||||
#include "core/components_ng/base/view_stack_processor.h"
|
||||
#include "core/components_ng/pattern/grid/grid_view.h"
|
||||
#include "core/components_v2/grid/render_grid_scroll.h"
|
||||
#include "frameworks/bridge/declarative_frontend/engine/functions/js_drag_function.h"
|
||||
#include "frameworks/bridge/declarative_frontend/jsview/js_interactable_view.h"
|
||||
@ -34,8 +37,20 @@ const std::vector<FlexDirection> LAYOUT_DIRECTION = { FlexDirection::ROW, FlexDi
|
||||
|
||||
} // namespace
|
||||
|
||||
#define SET_PROP_FOR_NG(propName, propType, propValue) \
|
||||
do { \
|
||||
if (Container::IsCurrentUseNewPipeline()) { \
|
||||
NG::GridView::Set##propName(static_cast<propType>(propValue)); \
|
||||
return; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
void JSGrid::Create(const JSCallbackInfo& info)
|
||||
{
|
||||
if (Container::IsCurrentUseNewPipeline()) {
|
||||
NG::GridView::Create();
|
||||
return;
|
||||
}
|
||||
LOGD("Create component: Grid");
|
||||
std::list<RefPtr<OHOS::Ace::Component>> componentChildren;
|
||||
|
||||
@ -69,6 +84,10 @@ void JSGrid::Create(const JSCallbackInfo& info)
|
||||
|
||||
void JSGrid::PopGrid(const JSCallbackInfo& info)
|
||||
{
|
||||
if (Container::IsCurrentUseNewPipeline()) {
|
||||
NG::ViewStackProcessor::GetInstance()->PopContainer();
|
||||
return;
|
||||
}
|
||||
ViewStackProcessor::GetInstance()->PopGrid();
|
||||
}
|
||||
|
||||
@ -89,6 +108,7 @@ void JSGrid::UseProxy(const JSCallbackInfo& args)
|
||||
|
||||
void JSGrid::SetColumnsTemplate(const std::string& value)
|
||||
{
|
||||
SET_PROP_FOR_NG(ColumnsTemplate, std::string, value);
|
||||
auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
|
||||
auto grid = AceType::DynamicCast<GridLayoutComponent>(component);
|
||||
if (grid) {
|
||||
@ -98,6 +118,7 @@ void JSGrid::SetColumnsTemplate(const std::string& value)
|
||||
|
||||
void JSGrid::SetRowsTemplate(const std::string& value)
|
||||
{
|
||||
SET_PROP_FOR_NG(RowsTemplate, std::string, value);
|
||||
auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
|
||||
auto grid = AceType::DynamicCast<GridLayoutComponent>(component);
|
||||
if (grid) {
|
||||
@ -145,6 +166,19 @@ void JSGrid::JsGridHeight(const JSCallbackInfo& info)
|
||||
LOGE("The arg is wrong, it is supposed to have at least 1 argument");
|
||||
return;
|
||||
}
|
||||
if (Container::IsCurrentUseNewPipeline()) {
|
||||
Dimension value;
|
||||
if (!ParseJsDimensionVp(info[0], value)) {
|
||||
LOGE("parse height fail for grid, please check.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (LessNotEqual(value.Value(), 0.0)) {
|
||||
value.SetValue(0.0);
|
||||
}
|
||||
NG::ViewAbstract::SetHeight(NG::CalcLength(value));
|
||||
return;
|
||||
}
|
||||
JSViewAbstract::JsHeight(info);
|
||||
Dimension height;
|
||||
if (!ParseJsDimensionVp(info[0], height)) {
|
||||
@ -157,7 +191,6 @@ void JSGrid::JsGridHeight(const JSCallbackInfo& info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JSGrid::JsOnScrollIndex(const JSCallbackInfo& info)
|
||||
{
|
||||
if (info[0]->IsFunction()) {
|
||||
@ -367,7 +400,7 @@ void JSGrid::JsOnGridDragEnter(const JSCallbackInfo& info)
|
||||
|
||||
RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
|
||||
auto onItemDragEnterId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc)](
|
||||
const ItemDragInfo& dragInfo) {
|
||||
const ItemDragInfo& dragInfo) {
|
||||
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
|
||||
ACE_SCORING_EVENT("Grid.onItemDragEnter");
|
||||
func->ItemDragEnterExecute(dragInfo);
|
||||
@ -389,7 +422,7 @@ void JSGrid::JsOnGridDragMove(const JSCallbackInfo& info)
|
||||
|
||||
RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
|
||||
auto onItemDragMoveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
|
||||
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
|
||||
ACE_SCORING_EVENT("Grid.onItemDragMove");
|
||||
func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
|
||||
@ -411,7 +444,7 @@ void JSGrid::JsOnGridDragLeave(const JSCallbackInfo& info)
|
||||
|
||||
RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
|
||||
auto onItemDragLeaveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex) {
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex) {
|
||||
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
|
||||
ACE_SCORING_EVENT("Grid.onItemDragLeave");
|
||||
func->ItemDragLeaveExecute(dragInfo, itemIndex);
|
||||
@ -433,7 +466,7 @@ void JSGrid::JsOnGridDragStart(const JSCallbackInfo& info)
|
||||
|
||||
RefPtr<JsDragFunction> jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
|
||||
auto onItemDragStartId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc)](
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex) -> RefPtr<Component> {
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex) -> RefPtr<Component> {
|
||||
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, nullptr);
|
||||
auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
|
||||
if (!ret->IsObject()) {
|
||||
@ -482,7 +515,7 @@ void JSGrid::JsOnGridDrop(const JSCallbackInfo& info)
|
||||
|
||||
RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
|
||||
auto onItemDropId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
|
||||
const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
|
||||
JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
|
||||
ACE_SCORING_EVENT("Grid.onItemDrop");
|
||||
func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "frameworks/bridge/declarative_frontend/jsview/js_grid_item.h"
|
||||
|
||||
#include "core/common/container.h"
|
||||
#include "core/components_ng/pattern/grid/grid_item_view.h"
|
||||
#include "frameworks/bridge/declarative_frontend/engine/functions/js_mouse_function.h"
|
||||
#include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
|
||||
#include "frameworks/core/pipeline/base/element_register.h"
|
||||
@ -24,6 +25,10 @@ namespace OHOS::Ace::Framework {
|
||||
|
||||
void JSGridItem::Create(const JSCallbackInfo& args)
|
||||
{
|
||||
if (Container::IsCurrentUseNewPipeline()) {
|
||||
NG::GridItemView::Create();
|
||||
return;
|
||||
}
|
||||
auto container = Container::Current();
|
||||
if (!container) {
|
||||
LOGE("fail to get container");
|
||||
|
@ -27,6 +27,10 @@ build_component_ng("pattern_ng") {
|
||||
"divider/divider_view.cpp",
|
||||
"flex/flex_layout_algorithm.cpp",
|
||||
"flex/flex_view.cpp",
|
||||
"grid/grid_item_view.cpp",
|
||||
"grid/grid_layout_algorithm.cpp",
|
||||
"grid/grid_pattern.cpp",
|
||||
"grid/grid_view.cpp",
|
||||
"image/image_layout_algorithm.cpp",
|
||||
"image/image_pattern.cpp",
|
||||
"image/image_view.cpp",
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_PATTERN_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_PATTERN_H
|
||||
|
||||
#include "base/memory/referenced.h"
|
||||
#include "base/utils/noncopyable.h"
|
||||
#include "core/components_ng/pattern/pattern.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
class ACE_EXPORT GridItemPattern : public Pattern {
|
||||
DECLARE_ACE_TYPE(GridItemPattern, Pattern);
|
||||
|
||||
public:
|
||||
GridItemPattern() = default;
|
||||
~GridItemPattern() override = default;
|
||||
|
||||
bool IsAtomicNode() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
ACE_DISALLOW_COPY_AND_MOVE(GridItemPattern);
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_PATTERN_H
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "core/components_ng/pattern/grid/grid_item_view.h"
|
||||
|
||||
#include "core/components_ng/base/view_stack_processor.h"
|
||||
#include "core/components_ng/pattern/grid/grid_item_pattern.h"
|
||||
#include "core/components_v2/inspector/inspector_constants.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
void GridItemView::Create()
|
||||
{
|
||||
auto* stack = ViewStackProcessor::GetInstance();
|
||||
auto nodeId = stack->ClaimNodeId();
|
||||
auto frameNode = FrameNode::GetOrCreateFrameNode(
|
||||
V2::GRID_ITEM_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<GridItemPattern>(); });
|
||||
stack->Push(frameNode);
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
28
frameworks/core/components_ng/pattern/grid/grid_item_view.h
Normal file
28
frameworks/core/components_ng/pattern/grid/grid_item_view.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_VIEW_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_VIEW_H
|
||||
|
||||
#include "base/utils/macros.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
class ACE_EXPORT GridItemView {
|
||||
public:
|
||||
static void Create();
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_ITEM_VIEW_H
|
@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "core/components_ng/pattern/grid/grid_layout_algorithm.h"
|
||||
|
||||
#include "base/geometry/ng/offset_t.h"
|
||||
#include "base/utils/utils.h"
|
||||
#include "core/components_ng/property/layout_constraint.h"
|
||||
#include "core/components_ng/property/measure_utils.h"
|
||||
|
||||
#ifdef NG_BUILD
|
||||
#include "ace_shell/shell/common/window_manager.h"
|
||||
#endif
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
void GridLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
|
||||
{
|
||||
auto gridLayoutProperty = AceType::DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
|
||||
CHECK_NULL_VOID(gridLayoutProperty);
|
||||
|
||||
// Step1: Decide size of Grid
|
||||
Axis axis = gridLayoutInfo_.axis_;
|
||||
auto idealSize = CreateIdealSize(
|
||||
gridLayoutProperty->GetLayoutConstraint().value(), axis, gridLayoutProperty->GetMeasureType(), true);
|
||||
if (GreatOrEqual(GetMainAxisSize(idealSize, axis), Infinity<float>())) {
|
||||
// TODO: use total height of all children as grid's main size when main size of ideal is infinite
|
||||
LOGE("size of main axis value is infinity, please check");
|
||||
return;
|
||||
}
|
||||
layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
|
||||
MinusPaddingToSize(gridLayoutProperty->CreatePaddingAndBorder(), idealSize);
|
||||
|
||||
// Step2: Measure children that can be displayed in viewport of Grid
|
||||
float mainSize = GetMainAxisSize(idealSize, axis);
|
||||
float crossSize = GetCrossAxisSize(idealSize, axis);
|
||||
FillGridViewportAndMeasureChildren(mainSize, crossSize, gridLayoutProperty, layoutWrapper);
|
||||
StripItemsOutOfViewport();
|
||||
layoutWrapper->SetForceSyncRenderTree();
|
||||
}
|
||||
|
||||
void GridLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
|
||||
{
|
||||
auto gridLayoutProperty = AceType::DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
|
||||
CHECK_NULL_VOID(gridLayoutProperty);
|
||||
auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
|
||||
auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
|
||||
MinusPaddingToSize(padding, size);
|
||||
auto childFrameOffset = OffsetF(padding.left.value_or(0.0f), padding.top.value_or(0.0f));
|
||||
childFrameOffset += gridLayoutProperty->IsVertical() ? OffsetF(0.0f, gridLayoutInfo_.currentOffset_)
|
||||
: OffsetF(gridLayoutInfo_.currentOffset_, 0.0f);
|
||||
auto parentOffset =
|
||||
layoutWrapper->GetGeometryNode()->GetParentGlobalOffset() + layoutWrapper->GetGeometryNode()->GetFrameOffset();
|
||||
float crossFrWidth = GetCrossAxisSize(size, gridLayoutInfo_.axis_) / static_cast<float>(crossCount_);
|
||||
|
||||
// For e.g, when a vertical grid has two [GridItem] in first row, [gridMatrix_] is like {[0: {[0: 1fr], [1: 2fr]}]}
|
||||
// TODO: Support horizontal Grid
|
||||
float prevLineHeight = 0.0f;
|
||||
for (const auto& line : gridLayoutInfo_.gridMatrix_) {
|
||||
auto offset = childFrameOffset + OffsetF(0.0, prevLineHeight);
|
||||
if (line.second.empty()) {
|
||||
LOGE("line %{public}d should not be empty, please check.", line.first);
|
||||
break;
|
||||
}
|
||||
float prevItemCrossSize = 0.0f;
|
||||
for (auto iter = line.second.begin(); iter != line.second.end(); iter++) {
|
||||
offset +=
|
||||
gridLayoutProperty->IsVertical() ? OffsetF(prevItemCrossSize, 0.0) : OffsetF(0.0, prevItemCrossSize);
|
||||
auto wrapper = layoutWrapper->GetOrCreateChildByIndex(iter->first);
|
||||
if (!wrapper) {
|
||||
LOGE("item wrapper of index: %{public}d is null, please check.", iter->first);
|
||||
continue;
|
||||
}
|
||||
wrapper->GetGeometryNode()->SetFrameOffset(offset);
|
||||
wrapper->Layout(parentOffset);
|
||||
prevItemCrossSize = static_cast<float>(iter->second) * crossFrWidth;
|
||||
}
|
||||
prevLineHeight += gridLayoutInfo_.lineHeightMap_[line.first];
|
||||
}
|
||||
}
|
||||
|
||||
void GridLayoutAlgorithm::FillGridViewportAndMeasureChildren(
|
||||
float mainSize, float crossSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper)
|
||||
{
|
||||
float mainLength = gridLayoutInfo_.currentOffset_;
|
||||
|
||||
// Step1: Measure [GridItem] that has been recorded to [gridMatrix_]
|
||||
MeasureRecordedItems(mainSize, crossSize, gridLayoutProperty, layoutWrapper, mainLength);
|
||||
|
||||
// Step2: When done measure items in record, request new items to fill blank at end
|
||||
FillBlankAtEnd(mainSize, crossSize, gridLayoutProperty, layoutWrapper, mainLength);
|
||||
if (gridLayoutInfo_.reachEnd_) { // If it reaches end when [FillBlankAtEnd], modify [currentOffset_]
|
||||
ModifyCurrentOffsetWhenReachEnd(mainSize);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step3: Check if need to fill blank at start (in situation of grid items moving down)
|
||||
FillBlankAtStart(mainSize, crossSize, gridLayoutProperty, layoutWrapper, mainLength);
|
||||
if (gridLayoutInfo_.reachStart_) {
|
||||
gridLayoutInfo_.currentOffset_ = 0.0;
|
||||
gridLayoutInfo_.prevOffset_ = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void GridLayoutAlgorithm::FillBlankAtStart(float mainSize, float crossSize,
|
||||
const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper, float& mainLength)
|
||||
{
|
||||
if (LessOrEqual(
|
||||
gridLayoutInfo_.currentOffset_, 0.0)) { // If [currentOffset_] is none-positive, it means no blank at start
|
||||
return;
|
||||
}
|
||||
auto blankAtStart = gridLayoutInfo_.currentOffset_;
|
||||
while (GreatNotEqual(blankAtStart, 0.0)) {
|
||||
float lineHeight = FillNewLineForward(crossSize, mainSize, gridLayoutProperty, layoutWrapper);
|
||||
if (GreatNotEqual(lineHeight, 0.0)) {
|
||||
gridLayoutInfo_.lineHeightMap_[gridLayoutInfo_.startMainLineIndex_] = lineHeight;
|
||||
blankAtStart -= lineHeight;
|
||||
continue;
|
||||
}
|
||||
gridLayoutInfo_.reachStart_ = true;
|
||||
break;
|
||||
}
|
||||
gridLayoutInfo_.currentOffset_ = blankAtStart;
|
||||
gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
|
||||
}
|
||||
|
||||
// When a moving up event comes, the [currrentOffset_] may have been reduced too much than the items really need to
|
||||
// be moved up, so we need to modify [currrentOffset_] accrording to previous position.
|
||||
void GridLayoutAlgorithm::ModifyCurrentOffsetWhenReachEnd(float mainSize)
|
||||
{
|
||||
// Step1. Calculate total length of all items in viewport. [lengthOfItemsInViewport] must be greater than or equal
|
||||
// to viewport height
|
||||
float lengthOfItemsInViewport = 0.0f;
|
||||
for (auto i = gridLayoutInfo_.startMainLineIndex_; i <= gridLayoutInfo_.endMainLineIndex_; i++) {
|
||||
lengthOfItemsInViewport += gridLayoutInfo_.lineHeightMap_[i];
|
||||
}
|
||||
|
||||
// Step2. Calculate real offset that items can only be moved up by.
|
||||
float realOffsetToMoveUp =
|
||||
lengthOfItemsInViewport - mainSize + gridLayoutInfo_.prevOffset_; // Hint: [prevOffset_] is a non-positive value
|
||||
|
||||
// Step3. modify [currentOffset_]
|
||||
gridLayoutInfo_.currentOffset_ = gridLayoutInfo_.prevOffset_ - realOffsetToMoveUp;
|
||||
gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
|
||||
}
|
||||
|
||||
void GridLayoutAlgorithm::FillBlankAtEnd(float mainSize, float crossSize,
|
||||
const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper, float& mainLength)
|
||||
{
|
||||
// When [mainLength] is still less than [mainSize], do [FillNewLineBackward] repeatedly until filling up the lower
|
||||
// part of the viewport
|
||||
while (LessNotEqual(mainLength, mainSize)) {
|
||||
float lineHeight = FillNewLineBackward(crossSize, mainSize, gridLayoutProperty, layoutWrapper);
|
||||
if (GreatNotEqual(lineHeight, 0.0)) {
|
||||
mainLength += lineHeight;
|
||||
continue;
|
||||
}
|
||||
gridLayoutInfo_.reachEnd_ = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void GridLayoutAlgorithm::MeasureRecordedItems(float mainSize, float crossSize,
|
||||
const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper, float& mainLength)
|
||||
{
|
||||
currentMainLineIndex_ = gridLayoutInfo_.startMainLineIndex_ - 1;
|
||||
bool runOutOfRecord = false;
|
||||
while (LessNotEqual(mainLength, mainSize)) { // Measure grid items row by row
|
||||
auto gridMatrixIter = gridLayoutInfo_.gridMatrix_.find(++currentMainLineIndex_);
|
||||
if (gridMatrixIter == gridLayoutInfo_.gridMatrix_.end()) {
|
||||
runOutOfRecord = true;
|
||||
break; // If [gridMatrix_] does not contain record of line [currentMainLineIndex_], do [FillNewLineBackward]
|
||||
}
|
||||
float lineHeight = -1.0f;
|
||||
int32_t currentIndex = 0;
|
||||
// One record is like [0: 1fr] or [1: 2fr]
|
||||
for (const auto& gridItemRecord : gridMatrixIter->second) {
|
||||
currentIndex = gridItemRecord.first;
|
||||
auto itemWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
|
||||
if (!itemWrapper) {
|
||||
LOGE("GridItem wrapper of index %{public}u null", currentIndex);
|
||||
break;
|
||||
}
|
||||
itemWrapper->Measure(
|
||||
MakeMeasureConstraintForGridItem(mainSize, crossSize, gridItemRecord.second, gridLayoutProperty));
|
||||
auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize();
|
||||
lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight);
|
||||
// Record end index. When fill new line, the [endIndex_] will be the first item index to request
|
||||
gridLayoutInfo_.endIndex_ = gridItemRecord.first;
|
||||
}
|
||||
if (lineHeight > 0) { // Means at least one item has been measured
|
||||
gridLayoutInfo_.lineHeightMap_[currentMainLineIndex_] = lineHeight;
|
||||
mainLength += lineHeight;
|
||||
}
|
||||
// If a line moves up out of viewport, update [startIndex_], [currentOffset_] and [startMainLineIndex_], and
|
||||
// delete record in [gridMatrix_] and [lineHeightMap_]. The strip operation of [gridMatrix_] and
|
||||
// [lineHeightMap_] will take place in [StripItemsOutOfViewport].
|
||||
// TODO: inactive items
|
||||
if (LessOrEqual(mainLength, 0.0)) {
|
||||
gridLayoutInfo_.currentOffset_ = mainLength;
|
||||
gridLayoutInfo_.startMainLineIndex_ = currentMainLineIndex_ + 1;
|
||||
gridLayoutInfo_.startIndex_ = currentIndex + 1;
|
||||
}
|
||||
}
|
||||
// Case 1. if this while-loop breaks due to running out of records, the [currentMainLineIndex_] is larger by 1 than
|
||||
// real main line index, so reduce 1.
|
||||
// Case 2. if this while-loop stops due to false result of [LessNotEqual(mainLength, mainSize)], the
|
||||
// [currentMainLineIndex_] is exactly the real main line index. Update [endMainLineIndex_] when the recorded items
|
||||
// are done measured.
|
||||
gridLayoutInfo_.endMainLineIndex_ = runOutOfRecord ? --currentMainLineIndex_ : currentMainLineIndex_;
|
||||
}
|
||||
|
||||
float GridLayoutAlgorithm::FillNewLineForward(
|
||||
float crossSize, float mainSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper)
|
||||
{
|
||||
// To make the code more convinient to read, we name a param in situation of vertical, for exacmple:
|
||||
// 1. [lineHight] means height of a row when the Grid is vertical;
|
||||
// 2. [lineHight] means width of a column when the Grid is horizontal;
|
||||
// Other params are also named according to this principle.
|
||||
float lineHeight = -1.0f;
|
||||
float measuredItemsWidth = 0.0f;
|
||||
auto currentIndex = gridLayoutInfo_.startIndex_;
|
||||
// TODO: need to consider [colunmStart]\[columsEnd] of [GridItem]
|
||||
// TODO: shoule we use policy of adaptive layout according to size of [GridItem] ?
|
||||
if (gridLayoutInfo_.startMainLineIndex_ - 1 < 0) {
|
||||
LOGI("startMainLineIndex: %{public}d is alreay the first line, no forward line to make",
|
||||
gridLayoutInfo_.startMainLineIndex_);
|
||||
return -1.0f;
|
||||
}
|
||||
gridLayoutInfo_.startMainLineIndex_--;
|
||||
bool doneCreateNewLine = false;
|
||||
for (uint32_t i = 0; i < crossCount_; i++) {
|
||||
if (currentIndex-- < 0) {
|
||||
break;
|
||||
}
|
||||
// Step1. Get wrapper of [GridItem]
|
||||
auto itemWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
|
||||
if (!itemWrapper) {
|
||||
LOGE("GridItem wrapper of index %{public}u null", currentIndex);
|
||||
break;
|
||||
}
|
||||
// Step2. Make constraint and measure child
|
||||
// TODO: need to consider [colunmStart]\[columsEnd] of [GridItem]
|
||||
// TODO: need to use [isScrollable_]
|
||||
itemWrapper->Measure(MakeMeasureConstraintForGridItem(mainSize, crossSize, 1, gridLayoutProperty));
|
||||
|
||||
// Step3. Measure [GridItem]
|
||||
auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize();
|
||||
measuredItemsWidth += GetCrossAxisSize(itemSize, gridLayoutInfo_.axis_);
|
||||
lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight);
|
||||
// TODO: get [colunmStart]\[columsEnd] of [GridItem]
|
||||
gridLayoutInfo_.gridMatrix_[gridLayoutInfo_.startMainLineIndex_][currentIndex] = 1;
|
||||
gridLayoutInfo_.startIndex_ = currentIndex;
|
||||
doneCreateNewLine = true;
|
||||
}
|
||||
// If it fails to create new line when [FillNewLineForward] is called, it means that it reaches start
|
||||
if (!doneCreateNewLine) {
|
||||
gridLayoutInfo_.reachStart_ = true;
|
||||
}
|
||||
return lineHeight;
|
||||
}
|
||||
|
||||
float GridLayoutAlgorithm::FillNewLineBackward(
|
||||
float crossSize, float mainSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper)
|
||||
{
|
||||
// To make the code more convinient to read, we name a param in situation of vertical, for exacmple:
|
||||
// 1. [lineHight] means height of a row when the Grid is vertical;
|
||||
// 2. [lineHight] means width of a column when the Grid is horizontal;
|
||||
// Other params are also named according to this principle.
|
||||
float lineHeight = -1.0f;
|
||||
float measuredItemsWidth = 0.0f;
|
||||
auto currentIndex = gridLayoutInfo_.endIndex_ + 1;
|
||||
currentMainLineIndex_++; // if it fails to fill a new line backward, do [currentMainLineIndex_--]
|
||||
// TODO: need to consider [colunmStart]\[columsEnd] of [GridItem]
|
||||
// TODO: shoule we use policy of adaptive layout according to size of [GridItem] ?
|
||||
bool doneFillLine = false;
|
||||
for (uint32_t i = 0; i < crossCount_; i++) {
|
||||
// Step1. Get wrapper of [GridItem]
|
||||
auto itemWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
|
||||
if (!itemWrapper) {
|
||||
LOGE("GridItem wrapper of index %{public}u null", currentIndex);
|
||||
break;
|
||||
}
|
||||
// Step2. Make constraint and measure child
|
||||
// TODO: need to consider [colunmStart]\[columsEnd] of [GridItem]
|
||||
// TODO: need to use [isScrollable_]
|
||||
itemWrapper->Measure(MakeMeasureConstraintForGridItem(mainSize, crossSize, 1, gridLayoutProperty));
|
||||
|
||||
// Step3. Measure [GridItem]
|
||||
auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize();
|
||||
measuredItemsWidth += GetCrossAxisSize(itemSize, gridLayoutInfo_.axis_);
|
||||
lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight);
|
||||
// TODO: get [colunmStart]\[columsEnd] of [GridItem]
|
||||
gridLayoutInfo_.gridMatrix_[currentMainLineIndex_][currentIndex] = 1;
|
||||
gridLayoutInfo_.endIndex_ = currentIndex;
|
||||
currentIndex++;
|
||||
doneFillLine = true;
|
||||
}
|
||||
if (!doneFillLine) {
|
||||
// If it fails to fill a new line backward, do [currentMainLineIndex_--]
|
||||
currentMainLineIndex_--;
|
||||
} else {
|
||||
gridLayoutInfo_.lineHeightMap_[currentMainLineIndex_] = lineHeight;
|
||||
gridLayoutInfo_.endMainLineIndex_ = currentMainLineIndex_;
|
||||
}
|
||||
return lineHeight;
|
||||
}
|
||||
void GridLayoutAlgorithm::StripItemsOutOfViewport()
|
||||
{
|
||||
// Erase records that are out of viewport
|
||||
// TODO: add cache and inactive item
|
||||
// 1. Erase records that are on top of viewport
|
||||
if (gridLayoutInfo_.lineHeightMap_.empty() || gridLayoutInfo_.gridMatrix_.empty()) {
|
||||
return;
|
||||
}
|
||||
int32_t startIndexInMap = gridLayoutInfo_.lineHeightMap_.begin()->first;
|
||||
for (int32_t i = startIndexInMap; i < gridLayoutInfo_.startMainLineIndex_; i++) {
|
||||
gridLayoutInfo_.lineHeightMap_.erase(i);
|
||||
gridLayoutInfo_.gridMatrix_.erase(i);
|
||||
}
|
||||
|
||||
// 2. Erase records that are under viewport
|
||||
if (gridLayoutInfo_.lineHeightMap_.empty() || gridLayoutInfo_.gridMatrix_.empty()) {
|
||||
return;
|
||||
}
|
||||
for (int32_t i = gridLayoutInfo_.endMainLineIndex_ + 1;
|
||||
i < static_cast<int32_t>(gridLayoutInfo_.lineHeightMap_.size()); i++) {
|
||||
gridLayoutInfo_.lineHeightMap_.erase(i);
|
||||
gridLayoutInfo_.gridMatrix_.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
LayoutConstraintF GridLayoutAlgorithm::MakeMeasureConstraintForGridItem(float mainSize, float crossSize,
|
||||
uint32_t itemFractionCount, const RefPtr<GridLayoutProperty>& gridLayoutProperty) const
|
||||
{
|
||||
float itemMainSize =
|
||||
gridLayoutProperty->IsConfiguredScrollable() ? Infinity<float>() : mainSize / static_cast<float>(mainCount_);
|
||||
float fractionWidth = crossSize / static_cast<float>(crossCount_);
|
||||
float itemCrossSize = fractionWidth * static_cast<float>(itemFractionCount);
|
||||
SizeF itemIdealSize =
|
||||
gridLayoutProperty->IsVertical() ? SizeF(itemCrossSize, itemMainSize) : SizeF(itemMainSize, itemCrossSize);
|
||||
auto itemConstraint = gridLayoutProperty->CreateChildConstraint();
|
||||
|
||||
// The percent size of GridItem is based on the fraction size, for e.g., if a GridItem has width of "50%" in Grid
|
||||
// configured with columnsTemplate = "1fr 1fr", rowsTemplate = "1fr 1fr", then tht GridItem width = [width of 1fr] *
|
||||
// 50%
|
||||
// [itemFractionCount] is now only in direction of cross axis
|
||||
// TODO: consider rowStart/rowEnd
|
||||
float widthPercentBase =
|
||||
GreatOrEqual(crossCount_, Infinity<uint32_t>())
|
||||
? itemConstraint.percentReference.Width()
|
||||
: itemConstraint.percentReference.Width() / static_cast<float>(crossCount_ * itemFractionCount);
|
||||
float heightPercentBase = GreatOrEqual(mainCount_, Infinity<uint32_t>())
|
||||
? itemConstraint.percentReference.Height()
|
||||
: itemConstraint.percentReference.Height() / static_cast<float>(mainCount_);
|
||||
itemConstraint.percentReference = SizeF(widthPercentBase, heightPercentBase);
|
||||
itemConstraint.maxSize = itemIdealSize;
|
||||
return itemConstraint;
|
||||
}
|
||||
|
||||
GridLayoutInfo GridLayoutAlgorithm::GetGridLayoutInfo()
|
||||
{
|
||||
return std::move(gridLayoutInfo_);
|
||||
}
|
||||
|
||||
// only for debug use
|
||||
void GridLayoutAlgorithm::PrintGridMatrix(const std::map<int32_t, std::map<int32_t, uint32_t>>& gridMatrix)
|
||||
{
|
||||
for (const auto& record : gridMatrix) {
|
||||
for (const auto& item : record.second) {
|
||||
LOGD("grid matrix -- line: %{public}d, item: %{public}d, fr: %{public}d", record.first, item.first,
|
||||
item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only for debug use
|
||||
void GridLayoutAlgorithm::PrintLineHeightMap(const std::map<int32_t, float>& lineHeightMap)
|
||||
{
|
||||
for (const auto& record : lineHeightMap) {
|
||||
LOGD("line height -- line: %{public}d, lineHeight: %{public}f", record.first, record.second);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_ALGORITHM_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_ALGORITHM_H
|
||||
|
||||
#include "core/components_ng/layout/box_layout_algorithm.h"
|
||||
#include "core/components_ng/layout/layout_wrapper.h"
|
||||
#include "core/components_ng/pattern/grid/grid_layout_property.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
// Try not to add more variables in [GridLayoutInfo] because the more state variables, the more problematic and the
|
||||
// harder it is to maintain
|
||||
struct GridLayoutInfo {
|
||||
Axis axis_ = Axis::VERTICAL;
|
||||
|
||||
float currentOffset_ = 0.0f;
|
||||
float prevOffset_ = 0.0f;
|
||||
|
||||
// index of first and last GridItem in viewport
|
||||
int32_t startIndex_ = 0;
|
||||
int32_t endIndex_ = -1;
|
||||
|
||||
// index of first row and last row in viewport (assuming it's a vertical Grid)
|
||||
int32_t startMainLineIndex_ = 0;
|
||||
int32_t endMainLineIndex_ = 0;
|
||||
|
||||
bool reachEnd_ = false;
|
||||
bool reachStart_ = false;
|
||||
|
||||
// in vertical grid, this map is like: [rowIndex: [itemIndex: fractionCount], [itemIndex: fractionCount]]
|
||||
// for e.g, when a vertical grid has two [GridItem]s in first row, [gridMatrix_] is like [0: [0: 1fr], [1: 2fr]]
|
||||
std::map<int32_t, std::map<int32_t, uint32_t>> gridMatrix_;
|
||||
// in vertical grid, this map is like: [rowIndex: rowHeight]
|
||||
std::map<int32_t, float> lineHeightMap_;
|
||||
};
|
||||
|
||||
class ACE_EXPORT GridLayoutAlgorithm : public LayoutAlgorithm {
|
||||
DECLARE_ACE_TYPE(GridLayoutAlgorithm, LayoutAlgorithm);
|
||||
|
||||
public:
|
||||
GridLayoutAlgorithm(GridLayoutInfo gridLayoutInfo, uint32_t crossCount, uint32_t mainCount)
|
||||
: gridLayoutInfo_(std::move(gridLayoutInfo)), crossCount_(crossCount), mainCount_(mainCount) {};
|
||||
~GridLayoutAlgorithm() override = default;
|
||||
|
||||
void Measure(LayoutWrapper* layoutWrapper) override;
|
||||
void Layout(LayoutWrapper* layoutWrapper) override;
|
||||
|
||||
GridLayoutInfo GetGridLayoutInfo();
|
||||
|
||||
static void PrintGridMatrix(const std::map<int32_t, std::map<int32_t, uint32_t>>& gridMatrix);
|
||||
static void PrintLineHeightMap(const std::map<int32_t, float>& lineHeightMap);
|
||||
|
||||
private:
|
||||
void FillGridViewportAndMeasureChildren(float mainSize, float crossSize,
|
||||
const RefPtr<GridLayoutProperty>& gridLayoutProperty, LayoutWrapper* layoutWrapper);
|
||||
void MeasureRecordedItems(float mainSize, float crossSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty,
|
||||
LayoutWrapper* layoutWrapper, float& mainLength);
|
||||
|
||||
// fill end of viewport
|
||||
void FillBlankAtStart(float mainSize, float crossSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty,
|
||||
LayoutWrapper* layoutWrapper, float& mainLength);
|
||||
float FillNewLineForward(float crossSize, float mainSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty,
|
||||
LayoutWrapper* layoutWrapper);
|
||||
|
||||
// fill start of viewport
|
||||
void FillBlankAtEnd(float mainSize, float crossSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty,
|
||||
LayoutWrapper* layoutWrapper, float& mainLength);
|
||||
float FillNewLineBackward(float crossSize, float mainSize, const RefPtr<GridLayoutProperty>& gridLayoutProperty,
|
||||
LayoutWrapper* layoutWrapper);
|
||||
|
||||
LayoutConstraintF MakeMeasureConstraintForGridItem(float mainSize, float crossSize, uint32_t itemFractionCount,
|
||||
const RefPtr<GridLayoutProperty>& gridLayoutProperty) const;
|
||||
void StripItemsOutOfViewport();
|
||||
void ModifyCurrentOffsetWhenReachEnd(float mainSize);
|
||||
|
||||
GridLayoutInfo gridLayoutInfo_;
|
||||
|
||||
uint32_t crossCount_ = 0;
|
||||
uint32_t mainCount_ = 0;
|
||||
int32_t currentMainLineIndex_ = 0; // it equals to row index in vertical grid
|
||||
|
||||
ACE_DISALLOW_COPY_AND_MOVE(GridLayoutAlgorithm);
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_ALGORITHM_H
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_PROPERTY_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_PROPERTY_H
|
||||
|
||||
#include "core/components_ng/layout/layout_property.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
class ACE_EXPORT GridLayoutProperty : public LayoutProperty {
|
||||
DECLARE_ACE_TYPE(GridLayoutProperty, LayoutProperty);
|
||||
|
||||
public:
|
||||
GridLayoutProperty() = default;
|
||||
~GridLayoutProperty() override = default;
|
||||
|
||||
RefPtr<LayoutProperty> Clone() const override
|
||||
{
|
||||
auto value = MakeRefPtr<GridLayoutProperty>();
|
||||
value->LayoutProperty::UpdateLayoutProperty(DynamicCast<LayoutProperty>(this));
|
||||
value->propColumnsTemplate_ = CloneColumnsTemplate();
|
||||
value->propColumnsTemplate_ = CloneColumnsTemplate();
|
||||
return value;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
LayoutProperty::Reset();
|
||||
ResetColumnsTemplate();
|
||||
ResetRowsTemplate();
|
||||
}
|
||||
bool IsVertical() const
|
||||
{
|
||||
bool columnsTemplateValid = propColumnsTemplate_.has_value() && !propColumnsTemplate_.value().empty();
|
||||
bool rowsTemplateValid = propRowsTemplate_.has_value() && !propRowsTemplate_.value().empty();
|
||||
return columnsTemplateValid ||
|
||||
(!columnsTemplateValid && !rowsTemplateValid); // TODO: take layoutDirection into account
|
||||
}
|
||||
bool IsConfiguredScrollable() const
|
||||
{
|
||||
bool columnsTemplateSet = !propColumnsTemplate_.value_or("").empty();
|
||||
bool rowsTemplateSet = !propRowsTemplate_.value_or("").empty();
|
||||
bool verticalScrollable = (columnsTemplateSet && !rowsTemplateSet);
|
||||
bool horizontalScrollable = (!columnsTemplateSet && rowsTemplateSet);
|
||||
return verticalScrollable || horizontalScrollable;
|
||||
}
|
||||
|
||||
ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(ColumnsTemplate, std::string, PROPERTY_UPDATE_LAYOUT);
|
||||
ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(RowsTemplate, std::string, PROPERTY_UPDATE_LAYOUT);
|
||||
|
||||
private:
|
||||
ACE_DISALLOW_COPY_AND_MOVE(GridLayoutProperty);
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_LAYOUT_PROPERTY_H
|
95
frameworks/core/components_ng/pattern/grid/grid_pattern.cpp
Normal file
95
frameworks/core/components_ng/pattern/grid/grid_pattern.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "core/components_ng/pattern/grid/grid_pattern.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
void GridPattern::OnAttachToFrameNode()
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
host->GetRenderContext()->SetClipToFrame(true);
|
||||
}
|
||||
|
||||
void GridPattern::OnModifyDone()
|
||||
{
|
||||
auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
|
||||
CHECK_NULL_VOID(gridLayoutProperty);
|
||||
gridLayoutInfo_.axis_ = gridLayoutProperty->IsVertical() ? Axis::VERTICAL : Axis::HORIZONTAL;
|
||||
AddScrollEvent();
|
||||
}
|
||||
|
||||
void GridPattern::AddScrollEvent()
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
auto hub = host->GetEventHub<EventHub>();
|
||||
CHECK_NULL_VOID(hub);
|
||||
auto gestureHub = hub->GetOrCreateGestureEventHub();
|
||||
CHECK_NULL_VOID(gestureHub);
|
||||
if (scrollableEvent_) {
|
||||
gestureHub->RemoveScrollableEvent(scrollableEvent_);
|
||||
}
|
||||
scrollableEvent_ = MakeRefPtr<ScrollableEvent>(gridLayoutInfo_.axis_);
|
||||
auto scrollCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
|
||||
auto gridPattern = weak.Upgrade();
|
||||
if (!gridPattern) {
|
||||
LOGE("grid pattern upgrade fail when try handle scroll event.");
|
||||
return false;
|
||||
}
|
||||
return gridPattern->UpdateScrollPosition(static_cast<float>(offset), source);
|
||||
};
|
||||
scrollableEvent_->SetScrollPositionCallback(std::move(scrollCallback));
|
||||
gestureHub->AddScrollableEvent(scrollableEvent_);
|
||||
}
|
||||
|
||||
bool GridPattern::UpdateScrollPosition(float offset, int32_t source)
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_RETURN(host, false);
|
||||
// When finger moves down, offset is positive.
|
||||
// When finger moves up, offset is negative.
|
||||
if (gridLayoutInfo_.reachEnd_) {
|
||||
if (LessOrEqual(offset, 0)) {
|
||||
return false;
|
||||
}
|
||||
gridLayoutInfo_.reachEnd_ = false;
|
||||
}
|
||||
if (gridLayoutInfo_.reachStart_) {
|
||||
if (GreatOrEqual(offset, 0.0)) {
|
||||
return false;
|
||||
}
|
||||
gridLayoutInfo_.reachStart_ = false;
|
||||
}
|
||||
gridLayoutInfo_.currentOffset_ += offset;
|
||||
host->MarkDirtyNode(PROPERTY_REQUEST_NEW_CHILD_NODE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
|
||||
{
|
||||
if (skipMeasure && skipLayout) {
|
||||
return false;
|
||||
}
|
||||
auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
|
||||
CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
|
||||
auto gridLayoutAlgorithm = DynamicCast<GridLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
|
||||
CHECK_NULL_RETURN(gridLayoutAlgorithm, false);
|
||||
gridLayoutInfo_ = gridLayoutAlgorithm->GetGridLayoutInfo();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
74
frameworks/core/components_ng/pattern/grid/grid_pattern.h
Normal file
74
frameworks/core/components_ng/pattern/grid/grid_pattern.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_PATTERN_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_PATTERN_H
|
||||
|
||||
#include "base/memory/referenced.h"
|
||||
#include "core/components_ng/pattern/grid/grid_layout_algorithm.h"
|
||||
#include "core/components_ng/pattern/grid/grid_layout_property.h"
|
||||
#include "core/components_ng/pattern/pattern.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
class ACE_EXPORT GridPattern : public Pattern {
|
||||
DECLARE_ACE_TYPE(GridPattern, Pattern);
|
||||
|
||||
public:
|
||||
GridPattern() = default;
|
||||
~GridPattern() override = default;
|
||||
|
||||
bool IsAtomicNode() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<LayoutProperty> CreateLayoutProperty() override
|
||||
{
|
||||
return MakeRefPtr<GridLayoutProperty>();
|
||||
}
|
||||
|
||||
RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
|
||||
{
|
||||
auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
|
||||
CHECK_NULL_RETURN(gridLayoutProperty, nullptr);
|
||||
std::vector<std::string> cols;
|
||||
StringUtils::StringSplitter(gridLayoutProperty->GetColumnsTemplate().value_or(""), ' ', cols);
|
||||
std::vector<std::string> rows;
|
||||
StringUtils::StringSplitter(gridLayoutProperty->GetRowsTemplate().value_or(""), ' ', rows);
|
||||
auto crossCount = cols.empty() ? Infinity<uint32_t>() : cols.size();
|
||||
auto mainCount = rows.empty() ? Infinity<uint32_t>() : rows.size();
|
||||
if (!gridLayoutProperty->IsVertical()) {
|
||||
std::swap(crossCount, mainCount);
|
||||
}
|
||||
return MakeRefPtr<GridLayoutAlgorithm>(gridLayoutInfo_, crossCount, mainCount);
|
||||
}
|
||||
|
||||
private:
|
||||
void OnAttachToFrameNode() override;
|
||||
void OnModifyDone() override;
|
||||
void AddScrollEvent();
|
||||
bool UpdateScrollPosition(float offset, int32_t source);
|
||||
bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout) override;
|
||||
|
||||
GridLayoutInfo gridLayoutInfo_;
|
||||
RefPtr<ScrollableEvent> scrollableEvent_;
|
||||
|
||||
ACE_DISALLOW_COPY_AND_MOVE(GridPattern);
|
||||
};
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_PATTERN_H
|
45
frameworks/core/components_ng/pattern/grid/grid_view.cpp
Normal file
45
frameworks/core/components_ng/pattern/grid/grid_view.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "core/components_ng/pattern/grid/grid_view.h"
|
||||
|
||||
#include "core/components_ng/base/frame_node.h"
|
||||
#include "core/components_ng/base/view_stack_processor.h"
|
||||
#include "core/components_ng/pattern/grid/grid_layout_property.h"
|
||||
#include "core/components_ng/pattern/grid/grid_pattern.h"
|
||||
#include "core/components_v2/inspector/inspector_constants.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
|
||||
void GridView::Create()
|
||||
{
|
||||
auto* stack = ViewStackProcessor::GetInstance();
|
||||
auto nodeId = stack->ClaimNodeId();
|
||||
auto frameNode =
|
||||
FrameNode::GetOrCreateFrameNode(V2::GRID_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<GridPattern>(); });
|
||||
stack->Push(frameNode);
|
||||
}
|
||||
|
||||
void GridView::SetColumnsTemplate(const std::string& value)
|
||||
{
|
||||
ACE_UPDATE_LAYOUT_PROPERTY(GridLayoutProperty, ColumnsTemplate, value);
|
||||
}
|
||||
|
||||
void GridView::SetRowsTemplate(const std::string& value)
|
||||
{
|
||||
ACE_UPDATE_LAYOUT_PROPERTY(GridLayoutProperty, RowsTemplate, value);
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
33
frameworks/core/components_ng/pattern/grid/grid_view.h
Normal file
33
frameworks/core/components_ng/pattern/grid/grid_view.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRIF_GRID_VIEW_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRIF_GRID_VIEW_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/utils/macros.h"
|
||||
#include "core/components/common/layout/constants.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
class ACE_EXPORT GridView {
|
||||
public:
|
||||
static void Create();
|
||||
static void SetColumnsTemplate(const std::string& value);
|
||||
static void SetRowsTemplate(const std::string& value);
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRIF_GRID_VIEW_H
|
Loading…
Reference in New Issue
Block a user