mirror of
https://gitee.com/openharmony/arkui_ace_engine
synced 2025-01-08 09:53:20 +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;
|
||||
}
|
||||
|
||||
FocusPattern GetFocusPattern() const override
|
||||
{
|
||||
return { FocusType::SCOPE, true };
|
||||
}
|
||||
|
||||
OPINC_TYPE_E OpIncType() override
|
||||
{
|
||||
return OPINC_NODE;
|
||||
|
@ -674,11 +674,10 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
||||
property->IsReverse() ? DumpLog::GetInstance().AddDesc("isReverse:true")
|
||||
: DumpLog::GetInstance().AddDesc("isReverse:false");
|
||||
info->itemStart_ ? DumpLog::GetInstance().AddDesc("itemStart:true")
|
||||
: DumpLog::GetInstance().AddDesc("itemStart:false");
|
||||
info->itemEnd_ ? DumpLog::GetInstance().AddDesc("itemEnd:true")
|
||||
: DumpLog::GetInstance().AddDesc("itemEnd:false");
|
||||
: DumpLog::GetInstance().AddDesc("itemStart:false");
|
||||
info->itemEnd_ ? DumpLog::GetInstance().AddDesc("itemEnd:true") : DumpLog::GetInstance().AddDesc("itemEnd:false");
|
||||
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");
|
||||
|
||||
property->GetItemMinSize().has_value()
|
||||
@ -692,7 +691,7 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
||||
DumpLog::GetInstance().AddDesc("-----------start print sections_------------");
|
||||
std::string res = std::string("");
|
||||
int32_t index = 0;
|
||||
for (auto §ion : sections_->GetSectionInfo()) {
|
||||
for (auto& section : sections_->GetSectionInfo()) {
|
||||
res.append("[section:" + std::to_string(index) + "]");
|
||||
res.append("{ itemCount:" + std::to_string(section.itemsCount) + " },")
|
||||
.append("{ crossCount:" + std::to_string(section.crossCount.value_or(1)) + " },")
|
||||
@ -706,4 +705,78 @@ void WaterFlowPattern::DumpAdvanceInfo()
|
||||
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
|
||||
|
@ -17,11 +17,11 @@
|
||||
#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/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_content_modifier.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_sections.h"
|
||||
|
||||
@ -72,7 +72,7 @@ public:
|
||||
}
|
||||
|
||||
void TriggerModifyDone();
|
||||
|
||||
|
||||
RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
|
||||
|
||||
bool UpdateStartIndex(int32_t index);
|
||||
@ -148,11 +148,18 @@ public:
|
||||
* @param start the index of the first modified section.
|
||||
*/
|
||||
void OnSectionChanged(int32_t start);
|
||||
|
||||
void OnSectionChangedNow(int32_t start);
|
||||
|
||||
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:
|
||||
DisplayMode GetDefaultScrollBarDisplayMode() const override
|
||||
{
|
||||
@ -171,6 +178,14 @@ private:
|
||||
void OnScrollEndCallback() override;
|
||||
bool ScrollToTargetIndex(int32_t index);
|
||||
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_;
|
||||
RefPtr<WaterFlowLayoutInfoBase> layoutInfo_ = WaterFlowLayoutInfoBase::Create(LayoutMode::TOP_DOWN);
|
||||
RefPtr<WaterFlowSections> sections_;
|
||||
|
@ -539,4 +539,53 @@ HWTEST_F(WaterFlowScrollerTestNg, ScrollToIndex003, TestSize.Level1)
|
||||
FlushLayoutTask(frameNode_);
|
||||
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
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "core/components/button/button_theme.h"
|
||||
#include "core/components/common/layout/constants.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/scrollable/scrollable.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)
|
||||
{
|
||||
for (int32_t i = 0; i < number; i++) {
|
||||
|
@ -58,6 +58,7 @@ protected:
|
||||
void CreateWithItem(const std::function<void(WaterFlowModelNG)>& callback = nullptr);
|
||||
static void CreateItem(int32_t number = 10);
|
||||
static void CreateRandomItem(int32_t number);
|
||||
static void CreateFocusableItem(int32_t number);
|
||||
static void CreateItemWithHeight(float height);
|
||||
void UpdateCurrentOffset(float offset, int32_t source = SCROLL_FROM_UPDATE);
|
||||
void MouseSelect(Offset start, Offset end);
|
||||
|
Loading…
Reference in New Issue
Block a user