设计模式(四)Animation中的策略模式

542 阅读3分钟

一、基本概念

1、定义:

定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变换。

2、类图:

  • 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用于加速减速动画等等。

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方法来获取动画执行百分比

汇总:设计模式总结