!38390 【无障碍】【屏幕朗读】Slider无障碍阅读

Merge pull request !38390 from Zhang Jinyu/slider_acb
This commit is contained in:
openharmony_ci 2024-07-23 03:12:04 +00:00 committed by Gitee
commit 209788c8cd
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
4 changed files with 267 additions and 0 deletions

View File

@ -232,16 +232,19 @@ void SliderContentModifier::DrawStep(DrawingContext& context)
brush.SetAntiAlias(true);
brush.SetColor(ToRSColor(stepColor));
canvas.AttachBrush(brush);
stepPointVec_.clear();
if (reverse_) {
while (GreatOrEqual(endX, startX) && GreatOrEqual(endY, startY)) {
canvas.DrawCircle(RSPoint(endX, endY), stepSize * HALF);
stepPointVec_.emplace_back(PointF(endX, endY));
endX -= stepsLengthX;
endY -= stepsLengthY;
}
} else {
while (LessOrEqual(startX, endX) && LessOrEqual(startY, endY)) {
canvas.DrawCircle(RSPoint(startX, startY), stepSize * HALF);
stepPointVec_.emplace_back(PointF(startX, startY));
startX += stepsLengthX;
startY += stepsLengthY;
}

View File

@ -271,6 +271,11 @@ public:
}
}
const std::vector<PointF>& GetStepPointVec() const
{
return stepPointVec_;
}
private:
void InitializeShapeProperty();
RSRect GetTrackRect();
@ -353,6 +358,7 @@ private:
Color blockOuterEdgeColor_;
Color blockShadowColor_;
RefPtr<BasicShape> shape_;
std::vector<PointF> stepPointVec_;
ACE_DISALLOW_COPY_AND_MOVE(SliderContentModifier);
};

View File

@ -15,6 +15,8 @@
#include "core/components_ng/pattern/slider/slider_pattern.h"
#include "base/geometry/ng/point_t.h"
#include "base/geometry/ng/size_t.h"
#include "base/geometry/offset.h"
#include "base/i18n/localization.h"
#include "base/utils/utils.h"
@ -22,10 +24,13 @@
#include "core/components/theme/app_theme.h"
#include "core/components_ng/pattern/image/image_layout_property.h"
#include "core/components_ng/pattern/image/image_pattern.h"
#include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
#include "core/components_ng/pattern/slider/slider_accessibility_property.h"
#include "core/components_ng/pattern/slider/slider_layout_property.h"
#include "core/components_ng/pattern/slider/slider_paint_property.h"
#include "core/components_ng/pattern/slider/slider_style.h"
#include "core/components_ng/pattern/text/text_layout_property.h"
#include "core/components_ng/pattern/text/text_pattern.h"
#include "core/components_ng/pattern/text/text_styles.h"
#include "core/components_ng/property/property.h"
#include "core/components_v2/inspector/inspector_constants.h"
@ -87,6 +92,239 @@ void SliderPattern::OnModifyDone()
InitOnKeyEvent(focusHub);
InitializeBubble();
SetAccessibilityAction();
InitAccessibilityHoverEvent();
AccessibilityVirtualNodeRenderTask();
}
void SliderPattern::InitAccessibilityHoverEvent()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto eventHub = host->GetOrCreateInputEventHub();
eventHub->SetAccessibilityHoverEvent([weak = WeakClaim(this)](bool isHover, AccessibilityHoverInfo& info) {
auto slider = weak.Upgrade();
CHECK_NULL_VOID(slider);
slider->HandleAccessibilityHoverEvent(isHover, info);
});
}
void SliderPattern::HandleAccessibilityHoverEvent(bool isHover, const AccessibilityHoverInfo& info)
{
auto accessibilityHoverAction = info.GetActionType();
if (isHover && (accessibilityHoverAction == AccessibilityHoverAction::HOVER_ENTER ||
accessibilityHoverAction == AccessibilityHoverAction::HOVER_MOVE)) {
for (const auto& pointNode : pointAccessibilityNodeVec_) {
pointNode->GetAccessibilityProperty<AccessibilityProperty>()->SetAccessibilityLevel(
AccessibilityProperty::Level::YES);
}
} else if (!isHover) {
for (const auto& pointNode : pointAccessibilityNodeVec_) {
pointNode->GetAccessibilityProperty<AccessibilityProperty>()->SetAccessibilityLevel(
AccessibilityProperty::Level::NO);
}
auto host = GetHost();
auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::YES);
}
}
void SliderPattern::AccessibilityVirtualNodeRenderTask()
{
if (!AceApplicationInfo::GetInstance().IsAccessibilityEnabled()) {
return;
}
auto host = GetHost();
CHECK_NULL_VOID(host);
auto pipeline = host->GetContextRefPtr();
CHECK_NULL_VOID(pipeline);
if (!isInitAccessibilityVirtualNode_) {
pipeline->AddAfterRenderTask(
[weak = WeakClaim(this), &isInitAccessibilityVirtualNode = isInitAccessibilityVirtualNode_]() {
auto sliderPattern = weak.Upgrade();
CHECK_NULL_VOID(sliderPattern);
isInitAccessibilityVirtualNode = sliderPattern->InitAccessibilityVirtualNode();
});
} else {
pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
auto sliderPattern = weak.Upgrade();
CHECK_NULL_VOID(sliderPattern);
sliderPattern->ModifyAccessibilityVirtualNode();
});
}
}
bool SliderPattern::InitAccessibilityVirtualNode()
{
auto host = GetHost();
CHECK_NULL_RETURN(host, false);
parentAccessibilityNode_ = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG,
ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<LinearLayoutPattern>(true));
auto parentNodeContext = parentAccessibilityNode_->GetRenderContext();
CHECK_NULL_RETURN(parentNodeContext, false);
parentNodeContext->UpdatePosition(OffsetT(Dimension(0.0f), Dimension(0.0f)));
AddStepPointsAccessibilityVirtualNode();
parentAccessibilityNode_->SetAccessibilityNodeVirtual();
parentAccessibilityNode_->SetAccessibilityVirtualNodeParent(AceType::DynamicCast<NG::UINode>(host));
parentAccessibilityNode_->SetFirstAccessibilityVirtualNode();
FrameNode::ProcessOffscreenNode(parentAccessibilityNode_);
auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
accessibilityProperty->SaveAccessibilityVirtualNode(parentAccessibilityNode_);
accessibilityProperty->SetAccessibilityText(" ");
ModifyAccessibilityVirtualNode();
host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
return true;
}
void SliderPattern::ModifyAccessibilityVirtualNode()
{
if (pointAccessibilityNodeVec_.empty()) {
return;
}
UpdateStepAccessibilityVirtualNode();
UpdateStepPointsAccessibilityVirtualNodeSelected();
auto host = GetHost();
host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
}
void SliderPattern::AddStepPointsAccessibilityVirtualNode()
{
CHECK_NULL_VOID(parentAccessibilityNode_);
CHECK_NULL_VOID(sliderContentModifier_);
parentAccessibilityNode_->GetRenderContext()->ClearChildren();
pointAccessibilityNodeVec_.clear();
for (uint32_t i = 0; i < sliderContentModifier_->GetStepPointVec().size(); i++) {
auto pointNode = FrameNode::CreateFrameNode(
V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
parentAccessibilityNode_->AddChild(pointNode);
pointAccessibilityNodeVec_.emplace_back(pointNode);
}
}
void SliderPattern::UpdateStepAccessibilityVirtualNode()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
CHECK_NULL_VOID(parentAccessibilityNode_);
auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
float step = sliderPaintProperty->GetStep().value_or(1.0f);
if (pointAccessibilityNodeVec_.empty() || NearZero(step)) {
return;
}
auto pointSize = GetStepPointAccessibilityVirtualNodeSize();
auto pointOffsetWidth = pointSize.Width() * HALF;
auto pointOffsetHeight = pointSize.Height() * HALF;
uint32_t pointCount = pointAccessibilityNodeVec_.size();
uint32_t rangeFromPointIndex = 0;
uint32_t rangeToPointIndex = pointCount;
if (sliderPaintProperty->GetValidSlideRange().has_value()) {
auto range = sliderPaintProperty->GetValidSlideRange().value();
rangeFromPointIndex = range->GetToValue() / step;
rangeToPointIndex = range->GetFromValue() / step;
}
double min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
double max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
const std::vector<PointF>& stepPointVec = sliderContentModifier_->GetStepPointVec();
for (uint32_t i = 0; i < pointCount; i++) {
std::string txt = GetPointAccessibilityTxt(sliderPaintProperty, i, stepRatio_, min, max);
SetStepPointAccessibilityVirtualNode(pointAccessibilityNodeVec_[i], pointSize,
PointF(stepPointVec[i].GetX() - pointOffsetWidth, stepPointVec[i].GetY() - pointOffsetHeight),
(i < rangeFromPointIndex || i > rangeToPointIndex) ? " " : txt);
}
parentAccessibilityNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
}
std::string SliderPattern::GetPointAccessibilityTxt(
const RefPtr<SliderPaintProperty>& paintProperty, uint32_t pointIndex, float stepRatio, float min, float max)
{
auto pointPercent = pointIndex * stepRatio;
auto pointValue = std::clamp(pointPercent * (max - min) + min, min, max);
auto cPointValue = static_cast<int32_t>(pointValue);
if (cPointValue == pointValue) {
return std::to_string(cPointValue);
}
std::string str = std::to_string(pointValue);
return str.substr(0, str.find('.') + 3); // 3 : length with "." + two decimal
}
void SliderPattern::SetStepPointAccessibilityVirtualNode(
const RefPtr<FrameNode>& pointNode, const SizeF& size, const PointF& point, const std::string& txt)
{
auto pointNodeProperty = pointNode->GetLayoutProperty<TextLayoutProperty>();
pointNodeProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(size.Width()), CalcLength(size.Height())));
pointNodeProperty->UpdateContent(txt);
auto pointNodeContext = pointNode->GetRenderContext();
pointNodeContext->UpdatePosition(OffsetT(Dimension(point.GetX()), Dimension(point.GetY())));
auto pointAccessibilityProperty = pointNode->GetAccessibilityProperty<AccessibilityProperty>();
pointAccessibilityProperty->SetAccessibilityText(txt);
pointAccessibilityProperty->SetOnAccessibilityFocusCallback([weak = WeakClaim(this)](bool focus) {
if (focus) {
auto slider = weak.Upgrade();
CHECK_NULL_VOID(slider);
slider->HandleTextOnAccessibilityFocusCallback();
}
});
}
void SliderPattern::HandleTextOnAccessibilityFocusCallback()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO);
host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
}
void SliderPattern::UpdateStepPointsAccessibilityVirtualNodeSelected()
{
if (pointAccessibilityNodeVec_.empty()) {
return;
}
int32_t pointCount = pointAccessibilityNodeVec_.size();
int32_t currentStepIndex = GetCurrentStepIndex();
for (int32_t i = 0; i < pointCount; i++) {
RefPtr<FrameNode> pointNode = pointAccessibilityNodeVec_[i];
auto pointAccessibilityProperty = pointNode->GetAccessibilityProperty<TextAccessibilityProperty>();
if (currentStepIndex == i) {
pointAccessibilityProperty->SetSelected(true);
} else {
pointAccessibilityProperty->SetSelected(false);
}
}
}
int32_t SliderPattern::GetCurrentStepIndex()
{
auto host = GetHost();
CHECK_NULL_RETURN(host, false);
auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
const float step = sliderPaintProperty->GetStep().value_or(1.0f);
const float currentValue = sliderPaintProperty->GetValueValue(value_);
const double min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
if (NearZero(step)) {
return 0;
}
return static_cast<int32_t>(std::ceil((currentValue - min) / step));
}
SizeF SliderPattern::GetStepPointAccessibilityVirtualNodeSize()
{
auto host = GetHost();
auto& hostContent = host->GetGeometryNode()->GetContent();
float pointNodeHeight = blockHotSize_.Height();
float pointNodeWidth = blockHotSize_.Width();
if (direction_ == Axis::HORIZONTAL) {
pointNodeHeight = hostContent->GetRect().Height();
} else {
pointNodeWidth = hostContent->GetRect().Width();
}
return SizeF(pointNodeWidth, pointNodeHeight);
}
void SliderPattern::CalcSliderValue()

View File

@ -233,6 +233,22 @@ private:
RefPtr<FrameNode> BuildContentModifierNode();
float GetValueInValidRange(const RefPtr<SliderPaintProperty>& paintProperty, float value, float min, float max);
void UpdateToValidValue();
void AccessibilityVirtualNodeRenderTask();
void InitAccessibilityHoverEvent();
void HandleAccessibilityHoverEvent(bool state, const AccessibilityHoverInfo& info);
bool InitAccessibilityVirtualNode();
void ModifyAccessibilityVirtualNode();
void AddStepPointsAccessibilityVirtualNode();
void HandleTextOnAccessibilityFocusCallback();
void UpdateStepAccessibilityVirtualNode();
std::string GetPointAccessibilityTxt(
const RefPtr<SliderPaintProperty>& paintProperty, uint32_t pointIndex, float stepRatio, float min, float max);
int32_t GetCurrentStepIndex();
SizeF GetStepPointAccessibilityVirtualNodeSize();
void UpdateStepPointsAccessibilityVirtualNodeSelected();
void SetStepPointAccessibilityVirtualNode(
const RefPtr<FrameNode>& pointNode, const SizeF& size, const PointF& point, const std::string& txt);
std::optional<SliderMakeCallback> makeFunc_;
RefPtr<FrameNode> contentModifierNode_;
void SetSkipGestureEvents()
@ -302,6 +318,10 @@ private:
std::function<void(bool)> isFocusActiveUpdateEvent_;
bool isFocusActive_ = false;
RefPtr<FrameNode> parentAccessibilityNode_;
std::vector<RefPtr<FrameNode>> pointAccessibilityNodeVec_;
bool isInitAccessibilityVirtualNode_ = false;
ACE_DISALLOW_COPY_AND_MOVE(SliderPattern);
};
} // namespace OHOS::Ace::NG