設計模式(三)Animation中的策略模式

猥瑣發育_別浪發表於2019-03-06

一、基本概念

1、定義:

定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變換。

2、類圖:

設計模式(三)Animation中的策略模式

  • Context物件: 封裝可能存在的策略變化,遮蔽其他模組對演算法的直接訪問
  • Stategy抽象策略:定義通用演算法規則
  • ConcreteStategy具體策略:含有具體的演算法

3、應用場景:

  • 對呼叫者隱藏演算法具體實現細節
  • 針對同一問題有多種處理方式,需要通過if else等形式選擇某一種方式

4、優點:

  • 避免多種處理方式存在的if else語句。方便擴充,多一種處理方式,就多加一個實現類
  • 結構比較清晰,封裝性更好

5、缺點:

演算法過多會造成多個演算法實現類。Context需要了解所有的演算法,並做出相應的呼叫。

二、例項:

例如租房可以通過各種途徑,包括中介、房東、朋友等。每一種途徑都可以當成一種策略,可以互相切換。

1、抽象策略:

public interface RentingStrategy {
    void renting();
}
複製程式碼

2、具體策略

中介:

public class AgencyStrategy implements RentingStrategy {
    @Override
    public void renting() {
        System.out.println("通過中介租房");
    }
}
複製程式碼

房東:

public class LandlordStrategy implements RentingStrategy {
    @Override
    public void renting() {
        System.out.println("通過房東租房");
    }
}
複製程式碼

朋友:

public class FriendStrategy implements RentingStrategy {
    @Override
    public void renting() {
        System.out.println("通過朋友租房");
    }
}
複製程式碼

3、Context

public class Context {
    private RentingStrategy mRentingStrategy;

    public Context(RentingStrategy rentingStrategy) {
        this.mRentingStrategy = rentingStrategy;
    }

    public void rentHouse() {
        this.mRentingStrategy.renting();
    }
}
複製程式碼

4、呼叫

public class StrategyTest{
    public static void main(String[] args) {
        RentingStrategy friendStrategy = new FriendStrategy();
        Context context = new Context(friendStrategy);
        context.rentHouse();
    }
}
複製程式碼

三、動畫插值器

動畫插值器的作用就是根據時間流逝的百分比來來計算出當前屬性值改變的百分比。比如LinearInterpolator用於勻速動畫、AccelerateDecelerateInterpolator用於加速減速動畫等等。

設計模式(三)Animation中的策略模式

1、Interpolator

public interface Interpolator extends TimeInterpolator { }

public interface TimeInterpolator {

    /**
     * 返回流逝時間的百分比
     */
    float getInterpolation(float input);
}
複製程式碼

定義介面和策略可提供的方法

2、LinearInterpolator

@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }

}
複製程式碼

3、AccelerateDecelerateInterpolator

@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    
}
複製程式碼

不同的插值器區別在於getInterpolation返回值不同,也就是說演算法不同。

4、插值器呼叫

(1)setInterpolator設定插值器

#Animation
public void setInterpolator(Interpolator i) {
    mInterpolator = i;
}
複製程式碼

通過setInterpolator設定某個插值器(某種策略)

(2)View的startAnimation

#View
public void startAnimation(Animation animation) {
    animation.setStartTime(Animation.START_ON_FIRST_FRAME);
    //設定動畫
    setAnimation(animation);
    //重新整理父類快取
    invalidateParentCaches();
    //重新整理View跟子View
    invalidate(true);
}
複製程式碼

invalidate會對View進行重繪,呼叫View的draw方法
(3)draw

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
    ......
    final Animation a = getAnimation();
    if (a != null) {
        more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
        ......
    }
}
複製程式碼
private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
        Animation a, boolean scalingRequired) {
        ......
        //設定動畫開始監聽
        onAnimationStart();
    }

        ......
        invalidationTransform = parent.mInvalidationTransformation;
        //獲取到動畫的相關值
        a.getTransformation(drawingTime, invalidationTransform, 1f);
    } else {
        invalidationTransform = t;
    }

    if (more) {
            ......
            // 獲取重繪的區域
            final RectF region = parent.mInvalidateRegion;
            a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
                    invalidationTransform);

            parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
            // 重新計算區域
            final int left = mLeft + (int) region.left;
            final int top = mTop + (int) region.top;
            // 進行更新
            parent.invalidate(left, top, left + (int) (region.width() + .5f),
                    top + (int) (region.height() + .5f));
        }
    }
    return more;
}
複製程式碼

(4)Animation.getTransformation
裡面實現了動畫的具體值的改變

public boolean getTransformation(long currentTime, Transformation outTransformation) {
    ......
        //通過插值器獲取動畫執行百分比
        final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
        applyTransformation(interpolatedTime, outTransformation);
    }
    ......

    return mMore;
}

複製程式碼

內部通過呼叫Interpolator的getInterpolation方法來獲取動畫執行百分比

相關文章