From 96fefe0815a97c98cfec61b347fc06920554fb1f Mon Sep 17 00:00:00 2001 From: Daniil Vinogradov Date: Sun, 15 Dec 2024 16:40:13 +0100 Subject: [PATCH] WIP: UILabel textColor animation --- Submodules/UIKit/include/CALayer.h | 9 +++- Submodules/UIKit/include/CATextLayer.h | 14 +++++-- Submodules/UIKit/include/UILabel.h | 8 +++- Submodules/UIKit/lib/CALayer.cpp | 3 +- Submodules/UIKit/lib/CATextLayer.cpp | 57 +++++++++++++++++++------- Submodules/UIKit/lib/UILabel.cpp | 13 +++++- app/AppDelegate.cpp | 3 ++ 7 files changed, 84 insertions(+), 23 deletions(-) diff --git a/Submodules/UIKit/include/CALayer.h b/Submodules/UIKit/include/CALayer.h index 4a940ff..c4cce40 100644 --- a/Submodules/UIKit/include/CALayer.h +++ b/Submodules/UIKit/include/CALayer.h @@ -112,11 +112,17 @@ class CALayer: public enable_shared_from_this { void removeAllAnimations(); void onWillSet(std::string keyPath); void onDidSetAnimations(bool wasEmpty); - std::optional value(std::string forKeyPath); + + // Override to add new animatable + virtual std::optional value(std::string forKeyPath); void animateAt(Timer currentTime); void skiaRender(SkCanvas* canvas); +protected: + // Override to add new animatable + virtual void update(std::shared_ptr presentation, std::shared_ptr animation, float progress); + private: friend class UIView; @@ -164,7 +170,6 @@ class CALayer: public enable_shared_from_this { /// This is both a performance optimization (avoids lots of animations at the start) /// as well as a correctness fix (matches iOS behaviour). Maybe there's a better way though? bool hasBeenRenderedInThisPartOfOverallLayerHierarchy = false; - void update(std::shared_ptr presentation, std::shared_ptr animation, float progress); }; } diff --git a/Submodules/UIKit/include/CATextLayer.h b/Submodules/UIKit/include/CATextLayer.h index 364941b..64057f4 100644 --- a/Submodules/UIKit/include/CATextLayer.h +++ b/Submodules/UIKit/include/CATextLayer.h @@ -21,18 +21,26 @@ class CATextLayer: public CALayer { void setText(std::string text); [[nodiscard]] std::string text() const { return _text; } + void setFontSize(NXFloat fontSize); + [[nodiscard]] NXFloat fontSize() const { return _fontSize; } + void setTextColor(UIColor textColor); [[nodiscard]] UIColor textColor() const { return _textColor; } + + std::optional value(std::string forKeyPath) override; +protected: + void update(std::shared_ptr presentation, std::shared_ptr animation, float progress) override; + private: + NXFloat _fontSize = 17; std::string _text = "Furthermore, العربية نص جميل. द क्विक ब्राउन फ़ॉक्स jumps over the lazy 🐕."; UIColor _textColor = UIColor::black; // Skia sk_sp typeface; - skia::textlayout::ParagraphStyle paraStyle; - sk_sp fontCollection; +// skia::textlayout::ParagraphStyle paraStyle; +// sk_sp fontCollection; sk_sp unicode; - std::unique_ptr paragraphBuilder; std::unique_ptr paragraph; void updateParagraph(); diff --git a/Submodules/UIKit/include/UILabel.h b/Submodules/UIKit/include/UILabel.h index d741416..549277b 100644 --- a/Submodules/UIKit/include/UILabel.h +++ b/Submodules/UIKit/include/UILabel.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace NXKit { @@ -8,10 +9,15 @@ namespace NXKit { class UILabel: public UIView { public: UILabel(); + + void setTextColor(UIColor textColor); + [[nodiscard]] UIColor textColor(); + private: int _numberOfLines = 1; std::string _text; - UIColor _textColor = UIColor::black; + + std::shared_ptr _textLayer(); }; } diff --git a/Submodules/UIKit/lib/CALayer.cpp b/Submodules/UIKit/lib/CALayer.cpp index 626b9c1..c105a38 100644 --- a/Submodules/UIKit/lib/CALayer.cpp +++ b/Submodules/UIKit/lib/CALayer.cpp @@ -357,8 +357,7 @@ void CALayer::onWillSet(std::string keyPath) { auto animation = std::static_pointer_cast(actionForKey(animationKey)); if (animation && - (this->hasBeenRenderedInThisPartOfOverallLayerHierarchy - || animation->wasCreatedInUIAnimateBlock()) && + (this->hasBeenRenderedInThisPartOfOverallLayerHierarchy || animation->wasCreatedInUIAnimateBlock()) && !this->isPresentationForAnotherLayer && !CATransaction::disableActions()) { diff --git a/Submodules/UIKit/lib/CATextLayer.cpp b/Submodules/UIKit/lib/CATextLayer.cpp index 15f100a..b490c11 100644 --- a/Submodules/UIKit/lib/CATextLayer.cpp +++ b/Submodules/UIKit/lib/CATextLayer.cpp @@ -1,31 +1,25 @@ #include #include +#include using namespace NXKit; using namespace skia::textlayout; CATextLayer::CATextLayer(): CALayer() { - auto fontMgr = SkiaCtx::main()->getFontMgr(); - SkFontStyle fontStyle; typeface = SkiaCtx::main()->getFontMgr()->matchFamilyStyle(nullptr, fontStyle); - - fontCollection = sk_make_sp(); - fontCollection->setDefaultFontManager(SkiaCtx::main()->getFontMgr()); - unicode = SkUnicodes::ICU::Make(); - paragraphBuilder = ParagraphBuilder::make(paraStyle, fontCollection, unicode); updateParagraph(); } CATextLayer::CATextLayer(CATextLayer* layer): CALayer(layer) { + _fontSize = layer->_fontSize; + _textColor = layer->_textColor; + _text = layer->_text; + typeface = layer->typeface; - paraStyle = layer->paraStyle; - fontCollection = layer->fontCollection; unicode = layer->unicode; - - paragraphBuilder = ParagraphBuilder::make(paraStyle, fontCollection, unicode); updateParagraph(); } @@ -46,12 +40,20 @@ void CATextLayer::setText(std::string text) { void CATextLayer::setTextColor(UIColor textColor) { if (_textColor == textColor) return; + onWillSet("textColor"); _textColor = textColor; updateParagraph(); } +void CATextLayer::setFontSize(NXFloat fontSize) { + if (_fontSize == fontSize) return; + _fontSize = fontSize; + updateParagraph(); +} + void CATextLayer::updateParagraph() { - paragraphBuilder->Reset(); + auto fontCollection = sk_make_sp(); + fontCollection->setDefaultFontManager(SkiaCtx::main()->getFontMgr()); SkPaint paint; paint.setAntiAlias(true); @@ -60,12 +62,39 @@ void CATextLayer::updateParagraph() { skia::textlayout::TextStyle style; style.setForegroundColor(paint); style.setTypeface(typeface); - style.setFontSize(17); + style.setFontSize(_fontSize); + ParagraphStyle paraStyle; paraStyle.setTextStyle(style); paraStyle.setTextAlign(TextAlign::kRight); - paragraphBuilder->addText(_text.c_str()); + auto paragraphBuilder = ParagraphBuilder::make(paraStyle, fontCollection, unicode); + paragraphBuilder->addText(_text.c_str()); paragraph = paragraphBuilder->Build(); } + +std::optional CATextLayer::value(std::string forKeyPath) { + if (forKeyPath == "textColor") return _textColor; + return CALayer::value(forKeyPath); +} + +void CATextLayer::update(std::shared_ptr presentation, std::shared_ptr animation, float progress) { + if (!animation->keyPath.has_value() || !animation->fromValue.has_value()) return; + + auto keyPath = animation->keyPath.value(); + auto fromValue = animation->fromValue.value(); + + if (keyPath == "textColor") { + auto start = any_optional_cast(fromValue); + if (!start.has_value()) { return; } + + auto end = any_optional_cast(animation->toValue); + if (!end.has_value()) end = this->_textColor; + if (!end.has_value()) end = UIColor::clear; + + std::static_pointer_cast(presentation)->setTextColor(start->interpolationTo(end.value(), progress)); + } + + CALayer::update(presentation, animation, progress); +} diff --git a/Submodules/UIKit/lib/UILabel.cpp b/Submodules/UIKit/lib/UILabel.cpp index f15082e..78329ed 100644 --- a/Submodules/UIKit/lib/UILabel.cpp +++ b/Submodules/UIKit/lib/UILabel.cpp @@ -1,8 +1,19 @@ #include -#include using namespace NXKit; UILabel::UILabel(): UIView(NXRect(), new_shared()) { } + +std::shared_ptr UILabel::_textLayer() { + return std::static_pointer_cast(layer()); +} + +void UILabel::setTextColor(UIColor textColor) { + _textLayer()->setTextColor(textColor); +} + +UIColor UILabel::textColor() { + return _textLayer()->textColor(); +} diff --git a/app/AppDelegate.cpp b/app/AppDelegate.cpp index 33869aa..0dd0b56 100644 --- a/app/AppDelegate.cpp +++ b/app/AppDelegate.cpp @@ -13,9 +13,11 @@ namespace NXKit { void animateLabel(std::shared_ptr label) { UIView::animate(5, [label]() { label->setFrame({ 200, 100, 140, 88 }); + label->setTextColor(UIColor::cyan); }, [label](bool res) { UIView::animate(5, [label]() { label->setFrame({ 200, 100, 240, 88 }); + label->setTextColor(UIColor::black); }, [label](bool res) { animateLabel(label); }); @@ -56,6 +58,7 @@ bool UIApplicationDelegate::applicationDidFinishLaunchingWithOptions(UIApplicati UIView::animate(5, [imageView]() { imageView->setTransform(NXAffineTransform::identity.rotationBy(45)); + imageView->setBackgroundColor(UIColor::orange); }); auto label = new_shared();