优化滚动类组件双指抛滑体验

Signed-off-by: shihongjie <shihongjie@huawei.com>
Change-Id: I9a382124788199a6ffdf188386a11c62b1464689
This commit is contained in:
shihongjie 2024-09-18 16:09:55 +08:00
parent baaab837eb
commit a2a856e145
16 changed files with 234 additions and 71 deletions

View File

@ -95,7 +95,8 @@ const char* PATTERN_MAP[] = {
THEME_BLUR_STYLE_COMMON,
THEME_PATTERN_SHADOW,
THEME_PATTERN_CONTAINER_MODAL,
THEME_PATTERN_LINEAR_INDICATOR
THEME_PATTERN_LINEAR_INDICATOR,
THEME_PATTERN_SCROLLABLE
};
bool IsDirExist(const std::string& path)

View File

@ -84,6 +84,7 @@ const char THEME_PATTERN_LINEAR_INDICATOR[] = "linear_indicator_pattern";
const char THEME_BLUR_STYLE_COMMON[] = "blur_style_common";
const char THEME_PATTERN_SHADOW[] = "shadow_pattern";
const char THEME_PATTERN_CONTAINER_MODAL[] = "container_modal_pattern";
const char THEME_PATTERN_SCROLLABLE[] = "scrollable_pattern";
// pattern general attributes
const char PATTERN_FG_COLOR[] = "fg_color";

View File

@ -86,6 +86,7 @@ extern const char THEME_PATTERN_SHADOW[];
extern const char THEME_PATTERN_CONTAINER_MODAL[];
extern const char THEME_PATTERN_AGING_ADAPATION_DIALOG[];
extern const char THEME_PATTERN_LINEAR_INDICATOR[];
extern const char THEME_PATTERN_SCROLLABLE[];
// pattern general attributes
extern const char PATTERN_FG_COLOR[];

View File

@ -72,6 +72,7 @@
#include "core/components_ng/pattern/menu/menu_theme.h"
#include "core/components_ng/pattern/rich_editor/rich_editor_theme.h"
#include "core/components_ng/pattern/linear_indicator/linear_indicator_theme.h"
#include "core/components_ng/pattern/scrollable/scrollable_theme.h"
namespace OHOS::Ace {
namespace {
@ -145,6 +146,7 @@ const std::unordered_map<ThemeType, RefPtr<Theme>(*)(const RefPtr<ThemeConstants
{ NG::ContainerModalTheme::TypeId(), &ThemeBuildFunc<NG::ContainerModalTheme::Builder> },
{ AgingAdapationDialogTheme::TypeId(), &ThemeBuildFunc<AgingAdapationDialogTheme::Builder> },
{ NG::LinearIndicatorTheme::TypeId(), &ThemeBuildFunc<NG::LinearIndicatorTheme::Builder> },
{ NG::ScrollableTheme::TypeId(), &ThemeBuildFunc<NG::ScrollableTheme::Builder> },
};
} // namespace

View File

@ -392,7 +392,7 @@ bool GridPattern::UpdateCurrentOffset(float offset, int32_t source)
} else {
overScroll = gridLayoutInfo_.currentOffset_ - (GetMainContentSize() - itemsHeight);
}
auto friction = ScrollablePattern::CalculateFriction(std::abs(overScroll) / GetMainContentSize());
auto friction = CalculateFriction(std::abs(overScroll) / GetMainContentSize());
offset *= friction;
}
auto userOffset = FireOnWillScroll(-offset);
@ -408,8 +408,7 @@ bool GridPattern::UpdateCurrentOffset(float offset, int32_t source)
}
if (gridLayoutInfo_.reachStart_) {
if (source == SCROLL_FROM_UPDATE) {
auto friction =
ScrollablePattern::CalculateFriction(std::abs(gridLayoutInfo_.currentOffset_) / GetMainContentSize());
auto friction = CalculateFriction(std::abs(gridLayoutInfo_.currentOffset_) / GetMainContentSize());
offset *= friction;
}
auto userOffset = FireOnWillScroll(-offset);

View File

@ -846,7 +846,7 @@ bool ListPattern::UpdateCurrentOffset(float offset, int32_t source)
// over scroll in drag update from normal to over scroll.
float overScroll = std::max(res.start, res.end);
// adjust offset.
auto friction = ScrollablePattern::CalculateFriction(std::abs(overScroll) / contentMainSize_);
auto friction = CalculateFriction(std::abs(overScroll) / contentMainSize_);
currentDelta_ = currentDelta_ * friction;
}

View File

@ -486,7 +486,21 @@ float RefreshPattern::CalculatePullDownRatio()
auto geometryNode = host->GetGeometryNode();
CHECK_NULL_RETURN(geometryNode, 1.0f);
auto contentHeight = geometryNode->GetPaddingSize().Height();
return NearZero(contentHeight) ? 1.0f : ScrollablePattern::CalculateFriction(scrollOffset_ / contentHeight);
if (NearZero(contentHeight)) {
return 1.0f;
}
if (!ratio_.has_value()) {
auto context = GetContext();
CHECK_NULL_RETURN(context, 1.0f);
auto scrollableTheme = context->GetTheme<ScrollableTheme>();
CHECK_NULL_RETURN(scrollableTheme, 1.0f);
ratio_ = scrollableTheme->GetRatio();
}
auto gamma = scrollOffset_ / contentHeight;
if (GreatOrEqual(gamma, 1.0)) {
gamma = 1.0f;
}
return exp(-ratio_.value() * gamma);
}
float RefreshPattern::GetFollowRatio()

View File

@ -170,6 +170,7 @@ private:
bool pullToRefresh_ = true;
RefPtr<NodeAnimatablePropertyFloat> offsetProperty_;
std::shared_ptr<AnimationUtils::Animation> animation_;
std::optional<float> ratio_;
// API version 10
void InitLowVersionOffset();
void UpdateChild();

View File

@ -305,7 +305,7 @@ void ScrollPattern::AdjustOffset(float& delta, int32_t source)
if (overScrollPast == 0.0f) {
return;
}
float friction = ScrollablePattern::CalculateFriction((overScrollPast - std::abs(delta)) / viewPortLength_);
float friction = CalculateFriction((overScrollPast - std::abs(delta)) / viewPortLength_);
float direction = delta > 0.0f ? 1.0f : -1.0f;
delta = direction * CalculateOffsetByFriction(overScrollPast, std::abs(delta), friction);
}

View File

@ -27,6 +27,16 @@ void ScrollSpringEffect::RegisterSpringCallback()
effect->ProcessScrollOver(velocity);
});
scrollable_->SetCurrentPositionCallback(currentPositionCallback_);
scrollable_->SetOverScrollOffsetCallback([weakEffect = AceType::WeakClaim(this)]() {
auto effect = weakEffect.Upgrade();
if (effect) {
double position = effect->currentPositionCallback_();
double minExtent = effect->leadingCallback_();
double maxExtent = effect->trailingCallback_();
return std::max(minExtent - position, position - maxExtent);
}
return 0.0;
});
}
void ScrollSpringEffect::InitialEdgeEffect()

View File

@ -17,6 +17,7 @@
#include "base/log/jank_frame_report.h"
#include "core/common/layout_inspector.h"
#include "core/components_ng/pattern/scrollable/scrollable_theme.h"
#include "core/pipeline_ng/pipeline_context.h"
namespace OHOS::Ace::NG {
@ -83,30 +84,6 @@ void Scrollable::SetFriction(double sFriction)
sFriction_ = sFriction;
}
Scrollable::Scrollable()
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
velocityScale_ =
Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_VELOCITY_SCALE : VELOCITY_SCALE;
}
Scrollable::Scrollable(ScrollPositionCallback&& callback, Axis axis) : callback_(std::move(callback)), axis_(axis)
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
velocityScale_ =
Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_VELOCITY_SCALE : VELOCITY_SCALE;
}
Scrollable::Scrollable(const ScrollPositionCallback& callback, Axis axis) : callback_(callback), axis_(axis)
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
velocityScale_ =
Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_VELOCITY_SCALE : VELOCITY_SCALE;
}
Scrollable::~Scrollable()
{
// If animation still runs, force stop it.
@ -183,6 +160,23 @@ void Scrollable::Initialize(const WeakPtr<PipelineBase>& context)
panRecognizerNG_->SetOnActionCancel(actionCancel);
available_ = true;
auto pipeline = context_.Upgrade();
CHECK_NULL_VOID(pipeline);
auto scrollableTheme = pipeline->GetTheme<ScrollableTheme>();
CHECK_NULL_VOID(scrollableTheme);
flingVelocityScale_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN)
? scrollableTheme->GetFlingVelocityScale()
: VELOCITY_SCALE;
springVelocityScale_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN)
? scrollableTheme->GetSpringVelocityScale()
: VELOCITY_SCALE;
ratio_ = scrollableTheme->GetRatio();
springResponse_ = scrollableTheme->GetSpringResponse();
touchPadVelocityScaleRate_ = scrollableTheme->GetTouchPadVelocityScaleRate();
if (friction_ == -1) {
InitFriction(scrollableTheme->GetFriction());
}
}
void Scrollable::SetAxis(Axis axis)
@ -402,13 +396,16 @@ void Scrollable::HandleDragUpdate(const GestureEvent& info)
HandleScroll(mainDelta, source, NestedState::GESTURE);
}
void Scrollable::LayoutDirectionEst(double& correctVelocity)
void Scrollable::LayoutDirectionEst(double gestureVelocity, double velocityScale, bool isScrollFromTouchPad)
{
sVelocityScale_ = isScrollFromTouchPad ? velocityScale * touchPadVelocityScaleRate_ : velocityScale;
if (isReverseCallback_ && isReverseCallback_()) {
correctVelocity = -correctVelocity * sVelocityScale_.value_or(velocityScale_) * GetGain(GetDragOffset());
currentVelocity_ = -gestureVelocity * sVelocityScale_.value_or(velocityScale) * GetGain(GetDragOffset());
} else {
correctVelocity = correctVelocity * sVelocityScale_.value_or(velocityScale_) * GetGain(GetDragOffset());
currentVelocity_ = gestureVelocity * sVelocityScale_.value_or(velocityScale) * GetGain(GetDragOffset());
}
// Apply max fling velocity limit, it must be calculated after all fling velocity gain.
currentVelocity_ = std::clamp(currentVelocity_, -maxFlingVelocity_ + slipFactor_, maxFlingVelocity_ - slipFactor_);
}
void Scrollable::HandleDragEnd(const GestureEvent& info)
@ -421,24 +418,20 @@ void Scrollable::HandleDragEnd(const GestureEvent& info)
if (dragFRCSceneCallback_) {
dragFRCSceneCallback_(info.GetMainVelocity(), NG::SceneStatus::END);
}
bool isScrollFromTouchPad = info.GetSourceTool() == SourceTool::TOUCHPAD;
isDragUpdateStop_ = false;
touchUp_ = false;
scrollPause_ = false;
lastVelocity_ = GetPanDirection() == Axis::NONE ? 0.0 : info.GetMainVelocity();
double gestureVelocity = GetPanDirection() == Axis::NONE ? 0.0 : info.GetMainVelocity();
SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
LayoutDirectionEst(gestureVelocity);
// Apply max fling velocity limit, it must be calculated after all fling velocity gain.
currentVelocity_ = std::clamp(gestureVelocity, -maxFlingVelocity_ + slipFactor_, maxFlingVelocity_ - slipFactor_);
lastPos_ = GetDragOffset();
JankFrameReport::GetInstance().ClearFrameJankFlag(JANK_RUNNING_SCROLL);
double mainPosition = GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY()));
mainPosition = Round(mainPosition);
ACE_SCOPED_TRACE("HandleDragEnd, mainPosition:%f, gestureVelocity:%f, currentVelocity:%f, moved_:%u "
"canOverScroll_:%u, id:%d, tag:%s",
mainPosition, gestureVelocity, currentVelocity_, moved_, canOverScroll_, nodeId_, nodeTag_.c_str());
if (!moved_ || IsMouseWheelScroll(info)) {
LayoutDirectionEst(gestureVelocity, flingVelocityScale_, isScrollFromTouchPad);
if (calcPredictSnapOffsetCallback_) {
std::optional<float> predictSnapOffset = calcPredictSnapOffsetCallback_(0.0f, 0.0f, 0.0f);
if (predictSnapOffset.has_value() && !NearZero(predictSnapOffset.value())) {
@ -457,14 +450,23 @@ void Scrollable::HandleDragEnd(const GestureEvent& info)
#endif
} else if (!Container::IsCurrentUseNewPipeline() && outBoundaryCallback_ && outBoundaryCallback_() &&
scrollOverCallback_) {
LayoutDirectionEst(gestureVelocity, flingVelocityScale_, isScrollFromTouchPad);
ResetContinueDragCount();
ProcessScrollOverCallback(currentVelocity_);
} else if (canOverScroll_) {
LayoutDirectionEst(gestureVelocity, springVelocityScale_, isScrollFromTouchPad);
auto gamma = overScrollOffsetCallback_() / continuousSlidingCallback_();
gamma = GreatOrEqual(gamma, 1.0) ? 1.0f : gamma;
currentVelocity_ = currentVelocity_ * exp(-ratio_ * gamma);
ResetContinueDragCount();
HandleOverScroll(currentVelocity_);
} else {
StartScrollAnimation(mainPosition, currentVelocity_);
LayoutDirectionEst(gestureVelocity, flingVelocityScale_, isScrollFromTouchPad);
StartScrollAnimation(mainPosition, currentVelocity_, isScrollFromTouchPad);
}
ACE_SCOPED_TRACE("HandleDragEnd, mainPosition:%f, gestureVelocity:%f, currentVelocity:%f, moved_:%u "
"canOverScroll_:%u, id:%d, tag:%s",
mainPosition, gestureVelocity, currentVelocity_, moved_, canOverScroll_, nodeId_, nodeTag_.c_str());
SetDelayedTask();
if (dragEndCallback_) {
dragEndCallback_();
@ -472,7 +474,7 @@ void Scrollable::HandleDragEnd(const GestureEvent& info)
isTouching_ = false;
}
void Scrollable::StartScrollAnimation(float mainPosition, float correctVelocity)
void Scrollable::StartScrollAnimation(float mainPosition, float correctVelocity, bool isScrollFromTouchPad)
{
if (!isSpringAnimationStop_) {
StopSpringAnimation();
@ -501,7 +503,9 @@ void Scrollable::StartScrollAnimation(float mainPosition, float correctVelocity)
currentVelocity_ = 0.0;
return;
}
if (NearZero(correctVelocity, FRICTION_VELOCITY_THRESHOLD)) {
auto frictionVelocityTh = isScrollFromTouchPad ? FRICTION_VELOCITY_THRESHOLD * touchPadVelocityScaleRate_
: FRICTION_VELOCITY_THRESHOLD;
if (NearZero(correctVelocity, frictionVelocityTh)) {
HandleScrollEnd(correctVelocity);
currentVelocity_ = 0.0;
#ifdef OHOS_PLATFORM
@ -638,6 +642,13 @@ float Scrollable::GetFrictionVelocityByFinalPosition(float final, float position
return DEFAULT_THRESHOLD * threshold * signum - (final - position) * friction;
}
void Scrollable::InitFriction(double friction)
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN) ? friction : friction_;
}
void Scrollable::FixScrollMotion(float position, float initVelocity)
{
#ifdef WEARABLE_PRODUCT
@ -815,7 +826,7 @@ void Scrollable::StartSpringMotion(
springAnimationCount_++;
springOffsetProperty_->Set(mainPosition);
AnimationOption option;
auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(DEFAULT_SPRING_RESPONSE, DEFAULT_SPRING_DAMP, 0.0f);
auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(springResponse_, DEFAULT_SPRING_DAMP, 0.0f);
option.SetCurve(curve);
option.SetDuration(CUSTOM_SPRING_ANIMATION_DURATION);
springOffsetProperty_->SetPropertyUnit(PropertyUnit::PIXEL_POSITION);

View File

@ -74,9 +74,9 @@ class Scrollable : public TouchEventTarget {
DECLARE_ACE_TYPE(Scrollable, TouchEventTarget);
public:
Scrollable();
Scrollable(ScrollPositionCallback&& callback, Axis axis);
Scrollable(const ScrollPositionCallback& callback, Axis axis);
Scrollable() = default;
Scrollable(ScrollPositionCallback&& callback, Axis axis) : callback_(std::move(callback)), axis_(axis) {}
Scrollable(const ScrollPositionCallback& callback, Axis axis) : callback_(callback), axis_(axis) {}
~Scrollable() override;
static void SetVelocityScale(double sVelocityScale);
@ -160,7 +160,7 @@ public:
void HandleScrollEnd(const std::optional<float>& velocity);
bool HandleOverScroll(double velocity);
ScrollResult HandleScroll(double offset, int32_t source, NestedState state);
void LayoutDirectionEst(double& correctVelocity);
void LayoutDirectionEst(double correctVelocity, double velocityScale, bool isScrollFromTouchPad);
void SetMoved(bool value)
{
@ -337,7 +337,7 @@ public:
{
overScrollCallback_ = std::move(func);
}
void StartScrollAnimation(float mainPosition, float velocity);
void StartScrollAnimation(float mainPosition, float velocity, bool isScrollFromTouchPad = false);
void SetOnScrollStartRec(std::function<void(float)>&& func)
{
onScrollStartRec_ = std::move(func);
@ -470,6 +470,11 @@ public:
return nestedScrolling_;
}
void SetOverScrollOffsetCallback(std::function<double()> overScrollOffsetCallback)
{
overScrollOffsetCallback_ = overScrollOffsetCallback;
}
private:
bool UpdateScrollPosition(double offset, int32_t source) const;
void ProcessSpringMotion(double position);
@ -483,6 +488,7 @@ private:
void MarkNeedFlushAnimationStartTime();
float GetFrictionVelocityByFinalPosition(
float final, float position, float signum, float friction, float threshold = DEFAULT_MULTIPLIER);
void InitFriction(double friction);
/**
* @brief Checks if the scroll event is caused by a mouse wheel.
@ -540,7 +546,6 @@ private:
double dragEndPosition_ = 0.0;
double lastVelocity_ = 0.0;
double friction_ = -1.0;
double velocityScale_ = 0.0;
double preGain_ = 1.0;
#ifdef OHOS_PLATFORM
int64_t startIncreaseTime_ = 0;
@ -581,6 +586,12 @@ private:
bool skipRestartSpring_ = false; // set to true when need to skip repeated spring animation
uint32_t updateSnapAnimationCount_ = 0;
uint32_t springAnimationCount_ = 0;
double flingVelocityScale_ = 1.5;
double springVelocityScale_ = 1.5;
float ratio_ = 1.848f;
float springResponse_ = 0.416f;
float touchPadVelocityScaleRate_ = 1.0f;
std::function<double()> overScrollOffsetCallback_;
RefPtr<NodeAnimatablePropertyFloat> snapOffsetProperty_;
bool isSnapAnimationStop_ = true;

View File

@ -57,19 +57,6 @@ const std::string CUSTOM_SCROLL_BAR_SCENE = "custom_scroll_bar_scene";
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
ScrollablePattern::ScrollablePattern()
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
}
ScrollablePattern::ScrollablePattern(EdgeEffect edgeEffect, bool alwaysEnabled)
: edgeEffect_(edgeEffect), edgeEffectAlwaysEnabled_(alwaysEnabled)
{
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction_;
}
RefPtr<PaintProperty> ScrollablePattern::CreatePaintProperty()
{
auto defaultDisplayMode = GetDefaultScrollBarDisplayMode();
@ -513,6 +500,14 @@ void ScrollablePattern::AddScrollEvent()
scrollable->SetNodeId(host->GetAccessibilityId());
scrollable->SetNodeTag(host->GetTag());
scrollable->Initialize(host->GetContextRefPtr());
if (!ratio_.has_value()) {
auto context = GetContext();
CHECK_NULL_VOID(context);
auto scrollableTheme = context->GetTheme<ScrollableTheme>();
CHECK_NULL_VOID(scrollableTheme);
ratio_ = scrollableTheme->GetRatio();
}
AttachAnimatableProperty(scrollable);
// move HandleScroll and HandleOverScroll to ScrollablePattern by setting callbacks to scrollable
@ -579,7 +574,6 @@ void ScrollablePattern::AddScrollEvent()
};
scrollable->SetDragEndCallback(std::move(dragEnd));
scrollable->SetUnstaticFriction(friction_);
scrollable->SetMaxFlingVelocity(maxFlingVelocity_);
auto scrollSnap = [weak = WeakClaim(this)](double targetOffset, double velocity) -> bool {
@ -1088,6 +1082,12 @@ void ScrollablePattern::SetFriction(double friction)
Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN) ? API11_FRICTION : FRICTION;
friction =
Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? API12_FRICTION : friction;
if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
auto context = GetContext();
CHECK_NULL_VOID(context);
auto scrollableTheme = context->GetTheme<ScrollableTheme>();
friction = scrollableTheme->GetFriction();
}
}
friction_ = friction;
CHECK_NULL_VOID(scrollableEvent_);

View File

@ -39,6 +39,7 @@
#include "core/components_ng/pattern/scrollable/scrollable_paint_method.h"
#include "core/components_ng/pattern/scrollable/scrollable_paint_property.h"
#include "core/components_ng/pattern/scrollable/scrollable_properties.h"
#include "core/components_ng/pattern/scrollable/scrollable_theme.h"
#include "core/components_ng/render/animation_utils.h"
#include "core/event/mouse_event.h"
#include "core/components_ng/event/scrollable_event.h"
@ -62,8 +63,10 @@ class ScrollablePattern : public NestableScrollContainer {
DECLARE_ACE_TYPE(ScrollablePattern, NestableScrollContainer);
public:
ScrollablePattern();
ScrollablePattern(EdgeEffect edgeEffect, bool alwaysEnabled);
ScrollablePattern() = default;
ScrollablePattern(EdgeEffect edgeEffect, bool alwaysEnabled)
: edgeEffect_(edgeEffect), edgeEffectAlwaysEnabled_(alwaysEnabled)
{}
~ScrollablePattern()
{
@ -421,13 +424,12 @@ public:
static ScrollSource ConvertScrollSource(int32_t source);
static float CalculateFriction(float gamma)
float CalculateFriction(float gamma)
{
constexpr float RATIO = 1.848f;
if (GreatOrEqual(gamma, 1.0)) {
gamma = 1.0f;
}
return exp(-RATIO * gamma);
return exp(-ratio_.value_or(1.848f) * gamma);
}
virtual float GetMainContentSize() const;
@ -881,7 +883,8 @@ private:
bool isSheetInReactive_ = false;
bool isCoordEventNeedSpring_ = true;
double scrollBarOutBoundaryExtent_ = 0.0;
double friction_ = 0.0;
std::optional<float> ratio_;
double friction_ = -1.0;
double maxFlingVelocity_ = MAX_VELOCITY;
// scroller
RefPtr<Animator> animator_;

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2024 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_SCROLLABLE_SCROLLABLE_THEME_H
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLLABLE_SCROLLABLE_THEME_H
#include "core/components/theme/theme.h"
#include "core/components/theme/theme_constants.h"
#include "core/components/theme/theme_constants_defines.h"
namespace OHOS::Ace::NG {
class ScrollableTheme : public virtual Theme {
DECLARE_ACE_TYPE(ScrollableTheme, Theme);
public:
class Builder {
public:
Builder() = default;
~Builder() = default;
RefPtr<ScrollableTheme> Build(const RefPtr<ThemeConstants>& themeConstants) const
{
RefPtr<ScrollableTheme> theme = AceType::Claim(new ScrollableTheme());
if (!themeConstants) {
return theme;
}
ParsePattern(themeConstants, theme);
return theme;
}
private:
void ParsePattern(const RefPtr<ThemeConstants>& themeConstants, const RefPtr<ScrollableTheme>& theme) const
{
if (!theme) {
return;
}
RefPtr<ThemeStyle> pattern = themeConstants->GetPatternByName(THEME_PATTERN_SCROLLABLE);
if (!pattern) {
return;
}
theme->friction_ = pattern->GetAttr<double>("scroll_able_friction", 0.75f);
theme->flingVelocityScale_ = pattern->GetAttr<double>("scroll_able_fling_velocity_scale", 1.5f);
theme->springVelocityScale_ = pattern->GetAttr<double>("scroll_able_spring_velocity_scale", 1.5f);
theme->ratio_ = pattern->GetAttr<double>("scroll_able_over_edge_following_ratio", 1.848f);
theme->springResponse_ = pattern->GetAttr<double>("scroll_able_spring_response", 0.417f);
theme->touchPadVelocityScaleRate_ =
pattern->GetAttr<double>("scroll_able_touch_pad_velocity_scale_rate", 1.0f);
}
};
~ScrollableTheme() override = default;
float GetFriction() const
{
return friction_;
}
float GetFlingVelocityScale() const
{
return flingVelocityScale_;
}
float GetSpringVelocityScale() const
{
return springVelocityScale_;
}
float GetRatio() const
{
return ratio_;
}
float GetSpringResponse() const
{
return springResponse_;
}
float GetTouchPadVelocityScaleRate() const
{
return touchPadVelocityScaleRate_;
}
protected:
ScrollableTheme() = default;
private:
float friction_ = 0.75f;
float flingVelocityScale_ = 1.5f;
float springVelocityScale_ = 1.5f;
float ratio_ = 1.848f;
float springResponse_ = 0.416f;
float touchPadVelocityScaleRate_ = 1.0f;
};
} // namespace OHOS::Ace::NG
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLLABLE_SCROLLABLE_THEME_H

View File

@ -54,7 +54,7 @@ bool WaterFlowPattern::UpdateCurrentOffset(float delta, int32_t source)
// over scroll in drag update from normal to over scroll.
float overScroll = layoutInfo_->CalcOverScroll(GetMainContentSize(), delta);
if (source == SCROLL_FROM_UPDATE) {
auto friction = ScrollablePattern::CalculateFriction(std::abs(overScroll) / GetMainContentSize());
auto friction = CalculateFriction(std::abs(overScroll) / GetMainContentSize());
delta *= friction;
}
} else {