make drawables's getHotspotBounds const

This commit is contained in:
houzh 2024-03-02 17:58:55 +08:00
parent 2fa549abc3
commit 80c323be8c
12 changed files with 190 additions and 27 deletions

View File

@ -74,7 +74,7 @@ void Drawable::setHotspot(float x,float y) {
void Drawable::setHotspotBounds(int left,int top,int width,int height) {
}
void Drawable::getHotspotBounds(Rect&outRect) {
void Drawable::getHotspotBounds(Rect&outRect)const{
outRect = mBounds;
}

View File

@ -102,7 +102,7 @@ public:
virtual int getOpacity();
virtual void setHotspot(float x,float y);
virtual void setHotspotBounds(int left,int top,int width,int height);
virtual void getHotspotBounds(Rect&outRect);
virtual void getHotspotBounds(Rect&outRect)const;
virtual bool getPadding(Rect&padding);
virtual Insets getOpticalInsets();
virtual bool isStateful()const;

View File

@ -607,9 +607,9 @@ void DrawableContainer::setHotspotBounds(int left, int top, int width, int heigh
}
}
void DrawableContainer::getHotspotBounds(Rect& outRect){
void DrawableContainer::getHotspotBounds(Rect& outRect)const{
if(mHotspotBounds.empty())outRect = mHotspotBounds;
else Drawable::getHotspotBounds(mBounds);
else Drawable::getHotspotBounds(outRect);
}
int DrawableContainer::getCurrentIndex()const{

View File

@ -113,7 +113,7 @@ public:
int getIntrinsicHeight()const override;
int getMinimumWidth() const override;
int getMinimumHeight()const override;
void getHotspotBounds(Rect& outRect) override;
void getHotspotBounds(Rect& outRect)const override;
void setHotspotBounds(int left, int top, int width, int height)override;
void setColorFilter(ColorFilter*colorFilter)override;
void setTintList(const ColorStateList*tint)override;

View File

@ -124,7 +124,7 @@ int DrawableWrapper::getIntrinsicHeight()const {
return mDrawable != nullptr ? mDrawable->getIntrinsicHeight() : -1;
}
void DrawableWrapper::getHotspotBounds(Rect& outRect){
void DrawableWrapper::getHotspotBounds(Rect& outRect)const{
if(mDrawable)mDrawable->getHotspotBounds(outRect);
else outRect = mBounds;
}

View File

@ -38,7 +38,7 @@ public:
int getIntrinsicWidth ()const override;
int getIntrinsicHeight()const override;
int getChangingConfigurations()const override;
void getHotspotBounds(Rect& outRect) override;
void getHotspotBounds(Rect& outRect)const override;
void setDrawable(Drawable* dr);
Drawable* getDrawable()const;
DrawableWrapper*mutate()override;

View File

@ -575,7 +575,7 @@ void LayerDrawable::setHotspotBounds(int left,int top,int width,int height){
mHotspotBounds.set(left, top, width,height);
}
void LayerDrawable::getHotspotBounds(Rect& outRect){
void LayerDrawable::getHotspotBounds(Rect& outRect)const{
if (!mHotspotBounds.empty()) {
outRect = mHotspotBounds;
} else {

View File

@ -145,7 +145,7 @@ public:
int getPaddingMode()const;
void setHotspot(float x,float y)override;
void setHotspotBounds(int left,int top,int width,int height)override;
void getHotspotBounds(Rect& outRect)override;
void getHotspotBounds(Rect& outRect)const override;
void setTintList(const ColorStateList* tint)override;
void setTintMode(int tintMode)override;
bool setVisible(bool visible,bool restart)override;

View File

@ -59,6 +59,9 @@ RippleDrawable::RippleDrawable(std::shared_ptr<RippleState> state) {
updateLocalState();
}
RippleDrawable::RippleDrawable():RippleDrawable(std::make_shared<RippleState>(nullptr,this)){
}
RippleDrawable::RippleDrawable(const ColorStateList* color,Drawable* content,Drawable* mask)
:RippleDrawable(std::make_shared<RippleState>(nullptr,nullptr)){
if(content)addLayer(content,{0},-1,0,0,0,0);
@ -129,7 +132,7 @@ void RippleDrawable::setRippleActive(bool active){
}
void RippleDrawable::setBackgroundActive(bool hovered, bool focused, bool pressed){
if (mBackground == nullptr && (hovered || focused)) {
if ((mBackground == nullptr) && (hovered || focused)) {
mBackground = new RippleBackground(this, mHotspotBounds, isBounded());
mBackground->setup(mState->mMaxRadius, mDensity);
}
@ -301,8 +304,8 @@ void RippleDrawable::setHotspotBounds(int left,int top,int w,int h){
onHotspotBoundsChanged();
}
void RippleDrawable::getHotspotBounds(Rect&out){
out=mHotspotBounds;
void RippleDrawable::getHotspotBounds(Rect&out)const{
out = mHotspotBounds;
}
void RippleDrawable::onHotspotBoundsChanged(){
@ -408,7 +411,6 @@ void RippleDrawable::drawBackgroundAndRipples(Canvas& canvas) {
if (mBackground && mBackground->isVisible()) {
mBackground->draw(canvas, 1.f);
}
for (auto ripple:mExitingRipples) {
const int alpha = 0x80 * ripple->getOpacity();
color = (color&0x00FFFFFF) | (alpha<<24);
@ -423,6 +425,140 @@ void RippleDrawable::drawBackgroundAndRipples(Canvas& canvas) {
void RippleDrawable::drawMask(Canvas& canvas) {
mMask->draw(canvas);
}
void RippleDrawable::drawSolid(Canvas& canvas){
pruneRipples();
// Clip to the dirty bounds, which will be the drawable bounds if we
// have a mask or content and the ripple bounds if we're projecting.
Rect bounds = getDirtyBounds();
canvas.save();
if (isBounded()) {
canvas.rectangle(bounds);
canvas.clip();
}
drawContent(canvas);
drawBackgroundAndRipples(canvas);
canvas.restore();
}
void RippleDrawable::exitPatternedBackgroundAnimation() {
mTargetBackgroundOpacity = 0;
if (mBackgroundAnimation) mBackgroundAnimation->cancel();
// after cancel
mRunBackgroundAnimation = true;
invalidateSelf(false);
}
void RippleDrawable::startPatternedAnimation() {
mAddRipple = true;
invalidateSelf(false);
}
void RippleDrawable::exitPatternedAnimation() {
mExitingAnimation = true;
invalidateSelf(false);
}
void RippleDrawable::enterPatternedBackgroundAnimation(bool focused, bool hovered) {
mBackgroundOpacity = 0;
mTargetBackgroundOpacity = focused ? .6f : hovered ? .2f : 0.f;
if (mBackgroundAnimation) mBackgroundAnimation->cancel();
// after cancel
mRunBackgroundAnimation = true;
invalidateSelf(false);
}
void RippleDrawable::startBackgroundAnimation() {
mRunBackgroundAnimation = false;
/*if (Looper.myLooper() == null) {
Log.w(TAG, "Thread doesn't have a looper. Skipping animation.");
return;
}*/
mBackgroundAnimation = ValueAnimator::ofFloat({mBackgroundOpacity, mTargetBackgroundOpacity});
/*mBackgroundAnimation->setInterpolator(LINEAR_INTERPOLATOR);
mBackgroundAnimation->setDuration(BACKGROUND_OPACITY_DURATION);
mBackgroundAnimation.addUpdateListener(update -> {
mBackgroundOpacity = (float) update.getAnimatedValue();
invalidateSelf(false);
});*/
mBackgroundAnimation->start();
}
void RippleDrawable::drawPatterned(Canvas& canvas) {
#if 0
Rect bounds = mHotspotBounds;
canvas.save();//Canvas.CLIP_SAVE_FLAG);
bool useCanvasProps = !mForceSoftware;
if (isBounded()) {
canvas.rectangle(getDirtyBounds());
canvas.clip();
}
float x, y, cx, cy, w, h;
bool addRipple = mAddRipple;
cx = bounds.centerX();
cy = bounds.centerY();
bool shouldExit = mExitingAnimation;
mExitingAnimation = false;
mAddRipple = false;
if (mRunningAnimations.size() > 0 && !addRipple) {
// update paint when view is invalidated
updateRipplePaint();
}
drawContent(canvas);
drawPatternedBackground(canvas, cx, cy);
if (addRipple && mRunningAnimations.size() <= MAX_RIPPLES) {
if (mHasPending) {
x = mPendingX;
y = mPendingY;
mHasPending = false;
} else {
x = bounds.exactCenterX();
y = bounds.exactCenterY();
}
h = bounds.height();
w = bounds.width();
RippleAnimationSession.AnimationProperties<Float, Paint> properties =
createAnimationProperties(x, y, cx, cy, w, h);
mRunningAnimations.add(new RippleAnimationSession(properties, !useCanvasProps)
.setOnAnimationUpdated(() -> invalidateSelf(false))
.setOnSessionEnd(session -> {
mRunningAnimations.remove(session);
})
.setForceSoftwareAnimation(!useCanvasProps)
.enter(canvas));
}
if (shouldExit) {
for (int i = 0; i < mRunningAnimations.size(); i++) {
RippleAnimationSession s = mRunningAnimations.get(i);
s.exit(canvas);
}
}
for (int i = 0; i < mRunningAnimations.size(); i++) {
RippleAnimationSession s = mRunningAnimations.get(i);
if (!canvas.isHardwareAccelerated()) {
Log.e(TAG, "The RippleDrawable.STYLE_PATTERNED animation is not supported for a "
+ "non-hardware accelerated Canvas. Skipping animation.");
break;
} else if (useCanvasProps) {
RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
CanvasProperty<Paint>>
p = s.getCanvasProperties();
RecordingCanvas can = (RecordingCanvas) canvas;
can.drawRipple(p.getX(), p.getY(), p.getMaxRadius(), p.getPaint(),
p.getProgress(), p.getNoisePhase(), p.getColor(), p.getShader());
} else {
RippleAnimationSession.AnimationProperties<Float, Paint> p =
s.getProperties();
float radius = p.getMaxRadius();
canvas.drawCircle(p.getX(), p.getY(), radius, p.getPaint());
}
}
canvas.restoreToCount(saveCount);
#endif
}
Rect RippleDrawable::getDirtyBounds() {

View File

@ -13,11 +13,15 @@ public:
static constexpr int MASK_CONTENT = 1;
static constexpr int MASK_EXPLICIT = 2;
static constexpr int MAX_RIPPLES = 10;
static constexpr int STYLE_SOLID = 0;
static constexpr int STYLE_PATTERNED = 1;
static constexpr bool FORCE_PATTERNED_STYLE = true;
private:
class RippleState:public LayerDrawable::LayerState{
public:
std::vector<int>mTouchThemeAttrs;
int mMaxRadius;
int mRippleStyle=FORCE_PATTERNED_STYLE?STYLE_PATTERNED:STYLE_SOLID;
ColorStateList*mColor;
RippleState(LayerState* orig, RippleDrawable* owner);
~RippleState();
@ -31,19 +35,25 @@ private:
Rect mDrawingBounds;
Rect mDirtyBounds;
std::shared_ptr<RippleState>mState;
Drawable* mMask;
Drawable* mMask;/*The masking layer, e.g. the layer with id R.id.mask. */
RippleBackground* mBackground;
bool mHasValidMask;
bool mRippleActive;
RippleForeground* mRipple;
bool mHasPending;
bool mOverrideBounds;
float mPendingX;
float mPendingY;
bool mHasPending;
std::vector<RippleForeground*>mExitingRipples;
int mDensity;
bool mOverrideBounds;
float mBackgroundOpacity;
float mTargetBackgroundOpacity;
bool mForceSoftware;
bool mAddRipple;
bool mRunBackgroundAnimation;
bool mExitingAnimation;
RippleForeground* mRipple;
ValueAnimator*mBackgroundAnimation;
private:
RippleDrawable(std::shared_ptr<RippleState> state);
void cancelExitingRipples();
@ -59,10 +69,19 @@ private:
void drawContent(Canvas& canvas);
void drawBackgroundAndRipples(Canvas& canvas);
void drawMask(Canvas& canvas);
void drawSolid(Canvas& canvas);
void exitPatternedBackgroundAnimation();
void startPatternedAnimation();
void exitPatternedAnimation();
void enterPatternedBackgroundAnimation(bool focused, bool hovered);
void startBackgroundAnimation();
void drawPatterned(Canvas& canvas);
void drawPatternedBackground(Canvas& c, float cx, float cy);
protected:
bool onStateChange(const std::vector<int>&stateSet)override;
void onBoundsChange(const Rect& bounds)override;
public:
RippleDrawable();
RippleDrawable(const ColorStateList* color,Drawable* content,Drawable* mask);
void jumpToCurrentState()override;
int getOpacity()override;
@ -76,7 +95,7 @@ public:
bool setDrawableByLayerId(int id, Drawable* drawable)override;
void setPaddingMode(int mode);
bool canApplyTheme()override;
void getHotspotBounds(Rect&out)override;
void getHotspotBounds(Rect&out)const override;
void setHotspot(float x,float y)override;
void setHotspotBounds(int left,int top,int w,int h)override;
void draw(Canvas& canvas);

View File

@ -22,8 +22,14 @@ RippleForeground::RippleForeground(RippleDrawable* owner,const Rect& bounds, flo
mStartRadius = std::max(bounds.width, bounds.height) * 0.3f;
clampStartingPosition();
mAnimationListener.onAnimationEnd=[this](Animator&anim,bool isReverse){
mHasFinishedExit = true;
pruneSwFinished();
mHasFinishedExit = true;
auto it = std::find(mRunningSwAnimators.begin(),mRunningSwAnimators.end(),&anim);
if(it != mRunningSwAnimators.end()){
mRunningSwAnimators.erase(it);
LOGV("Animator %p ended",&anim);
delete &anim;
}
//pruneSwFinished();
};
}
@ -38,9 +44,8 @@ void RippleForeground::onTargetRadiusChanged(float targetRadius){
for (auto animator:mRunningSwAnimators) {
animator->removeListener(mAnimationListener);
animator->end();
delete animator;
}
mRunningSwAnimators.clear();
//mRunningSwAnimators.clear();
invalidateSelf();//switchToUiThreadAnimation();
}
@ -57,11 +62,11 @@ void RippleForeground::drawSoftware(Canvas& c,float origAlpha) {
void RippleForeground::pruneSwFinished() {
if( mRunningSwAnimators.size()==0)return;
for (int i=mRunningSwAnimators.size()-1;i>=0;i--){
for (int i=mRunningSwAnimators.size();i>=0;i--){
Animator*anim=mRunningSwAnimators[i];
if (!anim->isRunning()) {
mRunningSwAnimators.erase(mRunningSwAnimators.begin()+i);
delete anim;
LOGV("erase %p",anim);
}
}
}
@ -98,6 +103,7 @@ float RippleForeground::getOpacity()const{
void RippleForeground::startSoftwareEnter() {
for (auto anim:mRunningSwAnimators) {
anim->cancel();
LOGV("delete anim %p of %d",anim,mRunningSwAnimators.size());
delete anim;
}
mRunningSwAnimators.clear();
@ -105,7 +111,6 @@ void RippleForeground::startSoftwareEnter() {
tweenRadius->setDuration(RIPPLE_ENTER_DURATION);
tweenRadius->setInterpolator(DecelerateInterpolator::gDecelerateInterpolator.get());//DECELERATE_INTERPOLATOR);
tweenRadius->addUpdateListener(ValueAnimator::AnimatorUpdateListener([this](ValueAnimator&anim){
LOGV("mTweenRadius=%f [%f,%f,%f] opacity=%f",getCurrentRadius(),mStartRadius,mTargetRadius,mOpacity);
mTweenRadius = GET_VARIANT(anim.getAnimatedValue(),float);
onAnimationPropertyChanged();
}));
@ -130,6 +135,7 @@ void RippleForeground::startSoftwareEnter() {
onAnimationPropertyChanged();
}));
opacity->start();
LOGV("add anims %p %p %p",tweenRadius,tweenOrigin,opacity);
mRunningSwAnimators.push_back(opacity);
}
@ -144,6 +150,7 @@ void RippleForeground::startSoftwareExit() {
}));
opacity->start();
LOGV("add anim %p",opacity);
mRunningSwAnimators.push_back(opacity);
}
@ -171,6 +178,7 @@ float RippleForeground::getCurrentRadius() {
void RippleForeground::end(){
for (auto anim:mRunningSwAnimators) {
anim->end();
LOGV("delete %d anim %p",mRunningSwAnimators.size(),anim);
delete anim;
}
mRunningSwAnimators.clear();

View File

@ -39,7 +39,7 @@ private:
bool mForceSoftware;
float mStartRadius = 0;
std::vector<Animator*> mRunningSwAnimators;
AnimatorListenerAdapter mAnimationListener;
Animator::AnimatorListener mAnimationListener;
private:
float getCurrentX();
float getCurrentY();
@ -50,7 +50,7 @@ private:
void onAnimationPropertyChanged();
void pruneSwFinished();
protected:
void onTargetRadiusChanged(float targetRadius);
void onTargetRadiusChanged(float targetRadius)override;
void clampStartingPosition();
public:
RippleForeground(RippleDrawable* owner,const Rect& bounds, float startingX, float startingY, bool forceSoftware);