mirror of
https://gitee.com/openharmony/arkui_ace_engine
synced 2025-01-09 02:11:26 +00:00
implement custom focus
Signed-off-by: Tianer Zhou <zhoutianer@huawei.com> Change-Id: Ic5ae43d81f339605be34aeccb11055b7088a72d8
This commit is contained in:
parent
230e32c908
commit
13f06d732e
@ -39,6 +39,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FocusPattern GetFocusPattern() const override
|
||||||
|
{
|
||||||
|
return { FocusType::SCOPE, true };
|
||||||
|
}
|
||||||
|
|
||||||
OPINC_TYPE_E OpIncType() override
|
OPINC_TYPE_E OpIncType() override
|
||||||
{
|
{
|
||||||
return OPINC_NODE;
|
return OPINC_NODE;
|
||||||
|
@ -674,11 +674,10 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
|||||||
property->IsReverse() ? DumpLog::GetInstance().AddDesc("isReverse:true")
|
property->IsReverse() ? DumpLog::GetInstance().AddDesc("isReverse:true")
|
||||||
: DumpLog::GetInstance().AddDesc("isReverse:false");
|
: DumpLog::GetInstance().AddDesc("isReverse:false");
|
||||||
info->itemStart_ ? DumpLog::GetInstance().AddDesc("itemStart:true")
|
info->itemStart_ ? DumpLog::GetInstance().AddDesc("itemStart:true")
|
||||||
: DumpLog::GetInstance().AddDesc("itemStart:false");
|
: DumpLog::GetInstance().AddDesc("itemStart:false");
|
||||||
info->itemEnd_ ? DumpLog::GetInstance().AddDesc("itemEnd:true")
|
info->itemEnd_ ? DumpLog::GetInstance().AddDesc("itemEnd:true") : DumpLog::GetInstance().AddDesc("itemEnd:false");
|
||||||
: DumpLog::GetInstance().AddDesc("itemEnd:false");
|
|
||||||
info->offsetEnd_ ? DumpLog::GetInstance().AddDesc("offsetEnd:true")
|
info->offsetEnd_ ? DumpLog::GetInstance().AddDesc("offsetEnd:true")
|
||||||
: DumpLog::GetInstance().AddDesc("offsetEnd:false");
|
: DumpLog::GetInstance().AddDesc("offsetEnd:false");
|
||||||
footer_.Upgrade() ? DumpLog::GetInstance().AddDesc("footer:true") : DumpLog::GetInstance().AddDesc("footer:false");
|
footer_.Upgrade() ? DumpLog::GetInstance().AddDesc("footer:true") : DumpLog::GetInstance().AddDesc("footer:false");
|
||||||
|
|
||||||
property->GetItemMinSize().has_value()
|
property->GetItemMinSize().has_value()
|
||||||
@ -692,7 +691,7 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
|||||||
DumpLog::GetInstance().AddDesc("-----------start print sections_------------");
|
DumpLog::GetInstance().AddDesc("-----------start print sections_------------");
|
||||||
std::string res = std::string("");
|
std::string res = std::string("");
|
||||||
int32_t index = 0;
|
int32_t index = 0;
|
||||||
for (auto §ion : sections_->GetSectionInfo()) {
|
for (auto& section : sections_->GetSectionInfo()) {
|
||||||
res.append("[section:" + std::to_string(index) + "]");
|
res.append("[section:" + std::to_string(index) + "]");
|
||||||
res.append("{ itemCount:" + std::to_string(section.itemsCount) + " },")
|
res.append("{ itemCount:" + std::to_string(section.itemsCount) + " },")
|
||||||
.append("{ crossCount:" + std::to_string(section.crossCount.value_or(1)) + " },")
|
.append("{ crossCount:" + std::to_string(section.crossCount.value_or(1)) + " },")
|
||||||
@ -706,4 +705,78 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
|||||||
DumpLog::GetInstance().AddDesc("-----------end print sections_------------");
|
DumpLog::GetInstance().AddDesc("-----------end print sections_------------");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopeFocusAlgorithm WaterFlowPattern::GetScopeFocusAlgorithm()
|
||||||
|
{
|
||||||
|
return { layoutInfo_->axis_ == Axis::VERTICAL, true, ScopeType::OTHERS,
|
||||||
|
[wp = WeakClaim(this)](
|
||||||
|
FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) {
|
||||||
|
auto self = wp.Upgrade();
|
||||||
|
if (self) {
|
||||||
|
nextFocusNode = self->GetNextFocusNode(step, currFocusNode);
|
||||||
|
}
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
WeakPtr<FocusHub> WaterFlowPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
|
||||||
|
{
|
||||||
|
auto cur = currentFocusNode.Upgrade();
|
||||||
|
CHECK_NULL_RETURN(cur, nullptr);
|
||||||
|
auto host = GetHost();
|
||||||
|
CHECK_NULL_RETURN(host, nullptr);
|
||||||
|
int32_t curIdx = host->GetChildTrueIndex(cur->GetFrameNode());
|
||||||
|
int32_t diff = 0;
|
||||||
|
switch (step) {
|
||||||
|
case FocusStep::DOWN:
|
||||||
|
case FocusStep::DOWN_END:
|
||||||
|
case FocusStep::RIGHT:
|
||||||
|
case FocusStep::RIGHT_END:
|
||||||
|
case FocusStep::TAB:
|
||||||
|
diff = 1;
|
||||||
|
break;
|
||||||
|
case FocusStep::LEFT:
|
||||||
|
case FocusStep::LEFT_END:
|
||||||
|
case FocusStep::UP:
|
||||||
|
case FocusStep::UP_END:
|
||||||
|
case FocusStep::SHIFT_TAB:
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return currentFocusNode;
|
||||||
|
}
|
||||||
|
int32_t idx = curIdx + diff;
|
||||||
|
int32_t footerOffset = layoutInfo_->footerIndex_ + 1; // 1 if footer present, 0 if not
|
||||||
|
while (idx - footerOffset >= 0 && idx < GetChildrenCount()) {
|
||||||
|
int32_t itemIdx = idx - footerOffset;
|
||||||
|
if (itemIdx >= layoutInfo_->endIndex_ || itemIdx <= layoutInfo_->startIndex_) {
|
||||||
|
ScrollToIndex(itemIdx, false, ScrollAlign::AUTO);
|
||||||
|
host->SetActive();
|
||||||
|
host->CreateLayoutTask();
|
||||||
|
}
|
||||||
|
auto next = host->GetChildByIndex(idx);
|
||||||
|
CHECK_NULL_RETURN(next, nullptr);
|
||||||
|
auto focus = next->GetHostNode()->GetFocusHub();
|
||||||
|
if (focus && focus->IsFocusable()) {
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
idx += diff;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<bool(int32_t)> WaterFlowPattern::GetScrollIndexAbility()
|
||||||
|
{
|
||||||
|
return [wp = WeakClaim(this)](int32_t index) -> bool {
|
||||||
|
auto self = wp.Upgrade();
|
||||||
|
CHECK_NULL_RETURN(self, false);
|
||||||
|
if (index == FocusHub::SCROLL_TO_HEAD) {
|
||||||
|
self->ScrollToEdge(ScrollEdgeType::SCROLL_TOP, false);
|
||||||
|
} else if (index == FocusHub::SCROLL_TO_TAIL) {
|
||||||
|
self->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false);
|
||||||
|
} else {
|
||||||
|
self->ScrollToIndex(index, false, ScrollAlign::AUTO);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
} // namespace OHOS::Ace::NG
|
} // namespace OHOS::Ace::NG
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_PATTERN_H
|
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_PATTERN_H
|
||||||
|
|
||||||
#include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
|
#include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
|
||||||
|
#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h"
|
||||||
|
#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h"
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_accessibility_property.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_accessibility_property.h"
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_content_modifier.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_content_modifier.h"
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_event_hub.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_event_hub.h"
|
||||||
#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h"
|
|
||||||
#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h"
|
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_layout_property.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_layout_property.h"
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_sections.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_sections.h"
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TriggerModifyDone();
|
void TriggerModifyDone();
|
||||||
|
|
||||||
RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
|
RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
|
||||||
|
|
||||||
bool UpdateStartIndex(int32_t index);
|
bool UpdateStartIndex(int32_t index);
|
||||||
@ -148,11 +148,18 @@ public:
|
|||||||
* @param start the index of the first modified section.
|
* @param start the index of the first modified section.
|
||||||
*/
|
*/
|
||||||
void OnSectionChanged(int32_t start);
|
void OnSectionChanged(int32_t start);
|
||||||
|
|
||||||
void OnSectionChangedNow(int32_t start);
|
void OnSectionChangedNow(int32_t start);
|
||||||
|
|
||||||
void DumpAdvanceInfo() override;
|
void DumpAdvanceInfo() override;
|
||||||
|
|
||||||
|
// ------------------------ Focus adapter --------------------------------
|
||||||
|
FocusPattern GetFocusPattern() const override
|
||||||
|
{
|
||||||
|
return { FocusType::SCOPE, true };
|
||||||
|
}
|
||||||
|
ScopeFocusAlgorithm GetScopeFocusAlgorithm() override;
|
||||||
|
std::function<bool(int32_t)> GetScrollIndexAbility() override;
|
||||||
|
// ------------------------ Focus ^^^ --------------------------------
|
||||||
private:
|
private:
|
||||||
DisplayMode GetDefaultScrollBarDisplayMode() const override
|
DisplayMode GetDefaultScrollBarDisplayMode() const override
|
||||||
{
|
{
|
||||||
@ -171,6 +178,14 @@ private:
|
|||||||
void OnScrollEndCallback() override;
|
void OnScrollEndCallback() override;
|
||||||
bool ScrollToTargetIndex(int32_t index);
|
bool ScrollToTargetIndex(int32_t index);
|
||||||
bool NeedRender();
|
bool NeedRender();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param step FocusStep
|
||||||
|
* @param currentFocusNode the currently focused FlowItem.
|
||||||
|
* @return WeakPtr<FocusHub> of the next FlowItem to focus on.
|
||||||
|
*/
|
||||||
|
WeakPtr<FocusHub> GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode);
|
||||||
|
|
||||||
std::optional<int32_t> targetIndex_;
|
std::optional<int32_t> targetIndex_;
|
||||||
RefPtr<WaterFlowLayoutInfoBase> layoutInfo_ = WaterFlowLayoutInfoBase::Create(LayoutMode::TOP_DOWN);
|
RefPtr<WaterFlowLayoutInfoBase> layoutInfo_ = WaterFlowLayoutInfoBase::Create(LayoutMode::TOP_DOWN);
|
||||||
RefPtr<WaterFlowSections> sections_;
|
RefPtr<WaterFlowSections> sections_;
|
||||||
|
@ -539,4 +539,53 @@ HWTEST_F(WaterFlowScrollerTestNg, ScrollToIndex003, TestSize.Level1)
|
|||||||
FlushLayoutTask(frameNode_);
|
FlushLayoutTask(frameNode_);
|
||||||
EXPECT_FLOAT_EQ(pattern_->finalPosition_, 2100.f);
|
EXPECT_FLOAT_EQ(pattern_->finalPosition_, 2100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tc.name: Focus001
|
||||||
|
* @tc.desc: Test WaterFlow scroll during focus change
|
||||||
|
* @tc.type: FUNC
|
||||||
|
*/
|
||||||
|
HWTEST_F(WaterFlowScrollerTestNg, Focus001, TestSize.Level1)
|
||||||
|
{
|
||||||
|
Create([](WaterFlowModelNG model) {
|
||||||
|
model.SetColumnsTemplate("1fr 1fr");
|
||||||
|
CreateFocusableItem(30);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto next = pattern_->GetNextFocusNode(FocusStep::DOWN, GetChildFocusHub(frameNode_, 5)).Upgrade();
|
||||||
|
auto cmp = GetChildFocusHub(frameNode_, 6);
|
||||||
|
EXPECT_EQ(AceType::RawPtr(next), AceType::RawPtr(cmp));
|
||||||
|
|
||||||
|
cmp = GetChildFocusHub(frameNode_, 4);
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::UP, GetChildFocusHub(frameNode_, 5)).Upgrade();
|
||||||
|
EXPECT_EQ(AceType::RawPtr(next), AceType::RawPtr(cmp));
|
||||||
|
auto info = pattern_->layoutInfo_;
|
||||||
|
|
||||||
|
EXPECT_EQ(info->startIndex_, 0);
|
||||||
|
EXPECT_EQ(info->endIndex_, 10);
|
||||||
|
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::LEFT, GetChildFocusHub(frameNode_, 0)).Upgrade();
|
||||||
|
EXPECT_FALSE(next);
|
||||||
|
|
||||||
|
EXPECT_EQ(info->startIndex_, 0);
|
||||||
|
EXPECT_EQ(info->endIndex_, 10);
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::RIGHT, GetChildFocusHub(frameNode_, 10)).Upgrade();
|
||||||
|
EXPECT_EQ(GetChildRect(frameNode_, 11).Bottom(), WATERFLOW_HEIGHT);
|
||||||
|
cmp = GetChildFocusHub(frameNode_, 11);
|
||||||
|
EXPECT_EQ(AceType::RawPtr(next), AceType::RawPtr(cmp));
|
||||||
|
|
||||||
|
pattern_->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false);
|
||||||
|
FlushLayoutTask(frameNode_);
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::LEFT, GetChildFocusHub(frameNode_, 29)).Upgrade();
|
||||||
|
cmp = GetChildFocusHub(frameNode_, 28);
|
||||||
|
EXPECT_EQ(AceType::RawPtr(next), AceType::RawPtr(cmp));
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::DOWN_END, GetChildFocusHub(frameNode_, 29)).Upgrade();
|
||||||
|
EXPECT_FALSE(next);
|
||||||
|
|
||||||
|
EXPECT_EQ(info->startIndex_, 19);
|
||||||
|
next = pattern_->GetNextFocusNode(FocusStep::UP_END, GetChildFocusHub(frameNode_, info->startIndex_)).Upgrade();
|
||||||
|
cmp = GetChildFocusHub(frameNode_, 18);
|
||||||
|
EXPECT_EQ(AceType::RawPtr(next), AceType::RawPtr(cmp));
|
||||||
|
EXPECT_EQ(GetChildY(frameNode_, 18), 0.0f);
|
||||||
|
}
|
||||||
} // namespace OHOS::Ace::NG
|
} // namespace OHOS::Ace::NG
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "core/components/button/button_theme.h"
|
#include "core/components/button/button_theme.h"
|
||||||
#include "core/components/common/layout/constants.h"
|
#include "core/components/common/layout/constants.h"
|
||||||
#include "core/components_ng/base/view_stack_processor.h"
|
#include "core/components_ng/base/view_stack_processor.h"
|
||||||
|
#include "core/components_ng/pattern/button/button_model_ng.h"
|
||||||
#include "core/components_ng/pattern/linear_layout/row_model_ng.h"
|
#include "core/components_ng/pattern/linear_layout/row_model_ng.h"
|
||||||
#include "core/components_ng/pattern/scrollable/scrollable.h"
|
#include "core/components_ng/pattern/scrollable/scrollable.h"
|
||||||
#include "core/components_ng/pattern/waterflow/water_flow_accessibility_property.h"
|
#include "core/components_ng/pattern/waterflow/water_flow_accessibility_property.h"
|
||||||
@ -142,6 +143,29 @@ void WaterFlowTestNg::CreateItem(int32_t number)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaterFlowTestNg::CreateFocusableItem(int32_t number)
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < number; i++) {
|
||||||
|
WaterFlowItemModelNG waterFlowItemModel;
|
||||||
|
waterFlowItemModel.Create();
|
||||||
|
ViewAbstract::SetWidth(CalcLength(FILL_LENGTH));
|
||||||
|
// set irregular height
|
||||||
|
int32_t two = 2;
|
||||||
|
if (i % two == 0) {
|
||||||
|
ViewAbstract::SetHeight(CalcLength(Dimension(ITEM_HEIGHT)));
|
||||||
|
} else {
|
||||||
|
ViewAbstract::SetHeight(CalcLength(Dimension(BIG_ITEM_HEIGHT)));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ButtonModelNG buttonModelNG;
|
||||||
|
std::list<RefPtr<Component>> buttonChildren;
|
||||||
|
buttonModelNG.CreateWithLabel({ .label = "label" }, buttonChildren);
|
||||||
|
ViewStackProcessor::GetInstance()->Pop();
|
||||||
|
}
|
||||||
|
ViewStackProcessor::GetInstance()->Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WaterFlowTestNg::CreateRandomItem(int32_t number)
|
void WaterFlowTestNg::CreateRandomItem(int32_t number)
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < number; i++) {
|
for (int32_t i = 0; i < number; i++) {
|
||||||
|
@ -58,6 +58,7 @@ protected:
|
|||||||
void CreateWithItem(const std::function<void(WaterFlowModelNG)>& callback = nullptr);
|
void CreateWithItem(const std::function<void(WaterFlowModelNG)>& callback = nullptr);
|
||||||
static void CreateItem(int32_t number = 10);
|
static void CreateItem(int32_t number = 10);
|
||||||
static void CreateRandomItem(int32_t number);
|
static void CreateRandomItem(int32_t number);
|
||||||
|
static void CreateFocusableItem(int32_t number);
|
||||||
static void CreateItemWithHeight(float height);
|
static void CreateItemWithHeight(float height);
|
||||||
void UpdateCurrentOffset(float offset, int32_t source = SCROLL_FROM_UPDATE);
|
void UpdateCurrentOffset(float offset, int32_t source = SCROLL_FROM_UPDATE);
|
||||||
void MouseSelect(Offset start, Offset end);
|
void MouseSelect(Offset start, Offset end);
|
||||||
|
Loading…
Reference in New Issue
Block a user