Android动画学习(五)之属性动画实现Tween的效果和高级属性示例

来源:互联网 发布:重庆时时彩 遗漏数据 编辑:程序博客网 时间:2024/05/18 02:01

Android动画学习(五)之属性动画实现Tween的效果和高级属性示例

在上篇博客中我们学习了属性动画的使用,主要介绍了概念的知识,这篇通过实现Tween的四种效果和高级属性示例展示加深对属性动画的掌握

属性动画实现Tween的四种效果

属性动画的实现方式有两种方式:XMl和Java代码配置
animator配置
在res下新建animator文件夹,新建AAA.xml文件。在set属性下新建设置动画属性.

alpha.xml
实现透明效果

<set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="1000"        android:propertyName="alpha"        android:valueFrom="0"        android:valueTo="1"        android:valueType="floatType" /></set>

scale.xml
实现缩放效果

<set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="3000"        android:propertyName="scaleY"        android:valueFrom="3"        android:valueTo="1"        android:valueType="floatType" /></set>

translate.xml
实现平移效果

<set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="3000"        android:propertyName="translationX"        android:valueFrom="-400"        android:valueTo="1"        android:valueType="floatType" /></set>

rotate.xml
实现旋转效果

<set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="3000"        android:propertyName="rotation"        android:valueFrom="0"        android:valueTo="360"        android:valueType="floatType" /></set>

animatorset.xml
实现组合效果

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="2000"        android:propertyName="translationX"        android:valueFrom="-500"        android:valueTo="0"        android:valueType="floatType" >    </objectAnimator>    <set android:ordering="together" >        <objectAnimator            android:duration="3000"            android:propertyName="rotation"            android:valueFrom="0"            android:valueTo="360"            android:valueType="floatType" >        </objectAnimator>        <set android:ordering="sequentially" >            <objectAnimator                android:duration="1500"                android:propertyName="alpha"                android:valueFrom="1"                android:valueTo="0"                android:valueType="floatType" >            </objectAnimator>            <objectAnimator                android:duration="1500"                android:propertyName="alpha"                android:valueFrom="0"                android:valueTo="1"                android:valueType="floatType" >            </objectAnimator>        </set>    </set></set>

Layout布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <include layout="@layout/titlebar" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="0.5"            android:text="XML" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="xml_alph"            android:text="alph"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="xml_scale"            android:text="scale"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="xml_translate"            android:text="translate"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="xml_rotate"            android:text="rotate"            android:textAllCaps="false" />    </LinearLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="0.5"            android:text="JAVA" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="java_alph"            android:text="alph"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="java_scale"            android:text="scale"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="java_translate"            android:text="translate"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:onClick="java_rotate"            android:text="rotate"            android:textAllCaps="false" />    </LinearLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="组合" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:onClick="XMLSetAnimator"            android:text="XMLSet"            android:textAllCaps="false" />        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:onClick="JAVASetAnimator"            android:text="JAVAset"            android:textAllCaps="false" />    </LinearLayout>    <ImageView        android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        app:srcCompat="@drawable/mei3" /></LinearLayout>

代码实现:
XML:

 public void xml_alph(View view) {//透明度        Animator animator = AnimatorInflater.loadAnimator(AttributeAnimatonActivity.this, R.animator.alpha);        animator.setTarget(v);        animator.start();    }    public void xml_scale(View view) {//缩放        Animator animator = AnimatorInflater.loadAnimator(AttributeAnimatonActivity.this, R.animator.scale);        animator.setTarget(v);        animator.start();    }    public void xml_translate(View view) {//平移        Animator animator = AnimatorInflater.loadAnimator(AttributeAnimatonActivity.this, R.animator.translate);        animator.setTarget(v);        animator.start();    }    public void xml_rotate(View view) {//旋转        Animator animator = AnimatorInflater.loadAnimator(AttributeAnimatonActivity.this, R.animator.rotate);        animator.setTarget(v);        animator.start();    }    public void JAVASetAnimator(View view) {//组合效果        ObjectAnimator moveIn = ObjectAnimator.ofFloat(iv, "translationX", -500f, 0f);        ObjectAnimator rotate = ObjectAnimator.ofFloat(iv, "rotation", 0f, 360f);        ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(iv, "alpha", 1f, 0f, 1f);        animSet = new AnimatorSet();        animSet.play(rotate).with(fadeInOut).after(moveIn);        animSet.setDuration(5000);        animSet.start();    }    public void XMLSetAnimator(View view) {//将图片先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作        Animator animator = AnimatorInflater.loadAnimator(AttributeAnimatonActivity.this, R.animator.animatorset);        animator.setTarget(v);        animator.start();    }

Xml效果:

这里写图片描述
Java实现:

/*    View从透明到完全不透明,时间1s,先加速再减速:     */    public void java_alph(View view) {//透明效果        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "alpha", 0f, 1f);        animator.setDuration(1000);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.start();    }    /*x轴从自身50%缩放到自身200%,y轴从自身50%缩放到自身200%,中心点(10%,10%)时间1s,先加速再减速: */    public void java_scale(View view) {//缩放效果        PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1f);        PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 2f);        //两个中心点其实可以用set方法直接设置,iv.setPivotX(pivotX)        float pivotX = iv.getWidth() * 0.1f;        float pivotY = iv.getHeight() * 0.1f;        PropertyValuesHolder valuesHolderPvX = PropertyValuesHolder.ofFloat("pivotX", pivotX, pivotX);        PropertyValuesHolder valuesHolderPvY = PropertyValuesHolder.ofFloat("pivotY", pivotY, pivotY);//        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, valuesHolderX, valuesHolderY, valuesHolderPvX, valuesHolderPvY);        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "scaleY", 1f, 3f, 1f);//在垂直方向上放大3倍再还原        animator.setDuration(1000);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.start();    }    /*x轴从自身位置50%向右平移相对于自己宽度100%的距离,y轴从自身位置50%向下平移相对于自己100%高度的距离,时间1s,先加速再减速: */    public void java_translate(View view) {//平移效果        PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("translationX", iv.getWidth() * 0.5f, iv.getWidth() * 1.5f);        PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("translationY", iv.getHeight() * 0.5f, iv.getHeight() * 1.5f);//        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, valuesHolderX, valuesHolderY);        float curTranslationX = iv.getTranslationX();//TextView先向左移出屏幕,然后再移动回来        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "translationX", curTranslationX, -500f, curTranslationX);        animator.setDuration(1000);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.start();    }    /*View绕自身中心点(10%,10%)位置,从-270旋转到180,时间1s,先加速再减速 : */    public void java_rotate(View view) {//旋转效果        PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("rotation", -270f, 180f);        //两个中心点其实可以用set方法直接设置,iv.setPivotX(pivotX)        float pivotX = iv.getWidth() * 0.1f;        float pivotY = iv.getHeight() * 0.1f;        PropertyValuesHolder valuesHolderPvX = PropertyValuesHolder.ofFloat("pivotX", pivotX, pivotX);        PropertyValuesHolder valuesHolderPvY = PropertyValuesHolder.ofFloat("pivotY", pivotY, pivotY);//        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, valuesHolderX, valuesHolderPvX, valuesHolderPvY);        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "rotation", 0f, 360f);//一次360度的旋转        animator.setDuration(1000);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.start();    }

Java效果:

这里写图片描述

高级属性之自定义TypeEvaluator

自定义TypeEvaluator

public class PointEvaluator implements TypeEvaluator {    @Override    public Object evaluate(float fraction, Object startValue, Object endValue) {        Point startPoint = (Point) startValue;        Point endPoint = (Point) endValue;        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());        Point point = new Point(x, y);        return point;    }}

引用布局

 <com.example.administrator.androidanimation.View.TypeEvaluatorView        android:layout_width="match_parent"        android:layout_height="match_parent" />

Activity调用

public class TypeEvaluatorActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_type_evaluator);        Point point1 = new Point(0, 0);        Point point2 = new Point(300, 300);        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);        anim.setDuration(5000);        anim.start();    }}

实现效果:
这里写图片描述

注:代码参考郭霖大神的属性动画讲解,如有侵权,请及时联系

高级属性之自定义TimeInterpolator

自定义TimeInterpolator

 /**     * 自定义插值器     */    public class MyDecelerateAccelerateInterpolator implements TimeInterpolator {        @Override        public float getInterpolation(float input) {            if (input <= 0.5) {                return (float) (Math.sin(Math.PI * input)) / 2;            } else {                return (float) (2 - Math.sin(Math.PI * input)) / 2;            }        }    }

引用布局

  <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.administrator.androidanimation.activity.TypeEvaluatorActivity">    <include layout="@layout/titlebar"        android:id="@+id/include" />    <ImageView        android:id="@+id/imageView2"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentStart="true"        android:layout_alignParentTop="true"        app:srcCompat="@drawable/m3" />    <Button        android:id="@+id/button"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="start"        android:text="开始动画"        android:layout_below="@+id/include"        android:layout_alignParentStart="true" />    <Button        android:id="@+id/button16"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/button"        android:layout_alignParentEnd="true"        android:onClick="cancle"        android:text="结束动画" /></RelativeLayout>

Activity调用

public class TimeInterpolatorActivity extends AppCompatActivity {    private ImageView iv;    private ObjectAnimator objectAnimator;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_time_interpolaator);        TextView textView = (TextView) findViewById(R.id.tv_title);        //设置标题        textView.setText("自定义Interpolator");        iv = (ImageView) findViewById(R.id.imageView2);    }    public void start(View view) {        float curTranslationY = iv.getTranslationY();//获取到当前控件的translationX的位置        objectAnimator = ObjectAnimator.ofFloat(iv, "translationY", curTranslationY, -500f, curTranslationY);        objectAnimator.setDuration(3000);        objectAnimator.setRepeatCount(1);        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);        objectAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        objectAnimator.addPauseListener(new Animator.AnimatorPauseListener() {            @Override            public void onAnimationPause(Animator animation) {//通知动画暂停。            }            @Override            public void onAnimationResume(Animator animation) {//通知动画得到恢复,之前被暂停后。            }        });        objectAnimator.start();    }    public void cancle(View view) {        objectAnimator.cancel();    }

实现效果:

这里写图片描述

高级属性之自定义Path路径动画

自定义View设置路径Path

/** *自定义View设置Path */public class PathView extends View {    /**     * Logging tag.     */    public static final String LOG_TAG = "PathView";    /**     * The paint for the path.     */    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);    /**     * Utils to catch the paths from the svg.     */    private final SvgUtils svgUtils = new SvgUtils(paint);    /**     * All the paths provided to the view. Both from Path and Svg.     */    private List<SvgUtils.SvgPath> paths = new ArrayList<SvgUtils.SvgPath>(0);    /**     * This is a lock before the view is redrawn     * or resided it must be synchronized with this object.     */    private final Object mSvgLock = new Object();    /**     * Thread for working with the object above.     */    private Thread mLoader;    /**     * The svg image from the raw directory.     */    private int svgResourceId;    /**     * Object that build the animation for the path.     */    private AnimatorBuilder animatorBuilder;    /**     * The progress of the drawing.     */    private float progress = 0f;    /**     * If the used colors are from the svg or from the set color.     */    private boolean naturalColors;    /**     * If the view is filled with its natural colors after path drawing.     */    private boolean fillAfter;    /**     * The width of the view.     */    private int width;    /**     * The height of the view.     */    private int height;    /**     * Default constructor.     *     * @param context The Context of the application.     */    public PathView(Context context) {        this(context, null);    }    /**     * Default constructor.     *     * @param context The Context of the application.     * @param attrs   attributes provided from the resources.     */    public PathView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    /**     * Default constructor.     *     * @param context  The Context of the application.     * @param attrs    attributes provided from the resources.     * @param defStyle Default style.     */    public PathView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        paint.setStyle(Paint.Style.STROKE);        getFromAttributes(context, attrs);    }    /**     * Get all the fields from the attributes .     *     * @param context The Context of the application.     * @param attrs   attributes provided from the resources.     */    private void getFromAttributes(Context context, AttributeSet attrs) {        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PathView);        try {            if (a != null) {                paint.setColor(a.getColor(R.styleable.PathView_pathColor, 0xff0000cc));                paint.setStrokeWidth(a.getFloat(R.styleable.PathView_pathWidth, 8.0f));                svgResourceId = a.getResourceId(R.styleable.PathView_svg, 0);            }        } finally {            if (a != null) {                a.recycle();            }        }    }    /**     * Set paths to be drawn and animated.     *     * @param paths - Paths that can be drawn.     */    public void setPaths(final List<Path> paths) {        for (Path path : paths) {            this.paths.add(new SvgUtils.SvgPath(path, paint));        }        synchronized (mSvgLock) {            updatePathsPhaseLocked();        }    }    /**     * Set path to be drawn and animated.     *     * @param path - Paths that can be drawn.     */    public void setPath(final Path path) {        paths.add(new SvgUtils.SvgPath(path, paint));        synchronized (mSvgLock) {            updatePathsPhaseLocked();        }    }    /**     * Animate this property. It is the percentage of the path that is drawn.     * It must be [0,1].     *     * @param percentage float the percentage of the path.     */    public void setPercentage(float percentage) {        if (percentage < 0.0f || percentage > 1.0f) {            throw new IllegalArgumentException("setPercentage not between 0.0f and 1.0f");        }        progress = percentage;        synchronized (mSvgLock) {            updatePathsPhaseLocked();        }        invalidate();    }    /**     * This refreshes the paths before draw and resize.     */    private void updatePathsPhaseLocked() {        final int count = paths.size();        for (int i = 0; i < count; i++) {            SvgUtils.SvgPath svgPath = paths.get(i);            svgPath.path.reset();            svgPath.measure.getSegment(0.0f, svgPath.length * progress, svgPath.path, true);            // Required only for Android 4.4 and earlier            svgPath.path.rLineTo(0.0f, 0.0f);        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        synchronized (mSvgLock) {            canvas.save();            canvas.translate(getPaddingLeft(), getPaddingTop());            final int count = paths.size();            for (int i = 0; i < count; i++) {                final SvgUtils.SvgPath svgPath = paths.get(i);                final Path path = svgPath.path;                final Paint paint1 = naturalColors ? svgPath.paint : paint;                canvas.drawPath(path, paint1);            }//            fillAfter(canvas);            canvas.restore();        }    }    /**     * If there is svg , the user called setFillAfter(true) and the progress is finished.     *     * @param canvas Draw to this canvas.     */    private void fillAfter(final Canvas canvas) {        if (svgResourceId != 0 && fillAfter && progress == 1f) {            svgUtils.drawSvgAfter(canvas, width, height);        }    }    @Override    protected void onSizeChanged(final int w, final int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        if (mLoader != null) {            try {                mLoader.join();            } catch (InterruptedException e) {                Log.e(LOG_TAG, "Unexpected error", e);            }        }        if (svgResourceId != 0) {            mLoader = new Thread(new Runnable() {                @Override                public void run() {                    svgUtils.load(getContext(), svgResourceId);                    synchronized (mSvgLock) {                        width = w - getPaddingLeft() - getPaddingRight();                        height = h - getPaddingTop() - getPaddingBottom();                        paths = svgUtils.getPathsForViewport(width, height);                        updatePathsPhaseLocked();                    }                }            }, "SVG Loader");            mLoader.start();        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        if (svgResourceId != 0) {            int widthSize = MeasureSpec.getSize(widthMeasureSpec);            int heightSize = MeasureSpec.getSize(heightMeasureSpec);            setMeasuredDimension(widthSize, heightSize);            return;        }        int desiredWidth = 0;        int desiredHeight = 0;        final float strokeWidth = paint.getStrokeWidth() / 2;        for (SvgUtils.SvgPath path : paths) {            desiredWidth += path.bounds.left + path.bounds.width() + strokeWidth;            desiredHeight += path.bounds.top + path.bounds.height() + strokeWidth;        }        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(widthMeasureSpec);        int measuredWidth, measuredHeight;        if (widthMode == MeasureSpec.AT_MOST) {            measuredWidth = desiredWidth;        } else {            measuredWidth = widthSize;        }        if (heightMode == MeasureSpec.AT_MOST) {            measuredHeight = desiredHeight;        } else {            measuredHeight = heightSize;        }        setMeasuredDimension(measuredWidth, measuredHeight);    }    /**     * If the real svg need to be drawn after the path animation.     *     * @param fillAfter - boolean if the view needs to be filled after path animation.     */    public void setFillAfter(final boolean fillAfter) {        this.fillAfter = fillAfter;    }    /**     * If you want to use the colors from the svg.     */    public void useNaturalColors() {        naturalColors = true;    }    /**     * Animator for the paths of the view.     *     * @return The AnimatorBuilder to build the animation.     */    public AnimatorBuilder getPathAnimator() {        if (animatorBuilder == null) {            animatorBuilder = new AnimatorBuilder(this);        }        return animatorBuilder;    }    /**     * Get the path color.     *     * @return The color of the paint.     */    public int getPathColor() {        return paint.getColor();    }    /**     * Set the path color.     *     * @param color -The color to set to the paint.     */    public void setPathColor(final int color) {        paint.setColor(color);    }    /**     * Get the path width.     *     * @return The width of the paint.     */    public float getPathWidth() {        return paint.getStrokeWidth();    }    /**     * Set the path width.     *     * @param width - The width of the path.     */    public void setPathWidth(final float width) {        paint.setStrokeWidth(width);    }    /**     * Get the svg resource id.     *     * @return The svg raw resource id.     */    public int getSvgResource() {        return svgResourceId;    }    /**     * Set the svg resource id.     *     * @param svgResource - The resource id of the raw svg.     */    public void setSvgResource(int svgResource) {        svgResourceId = svgResource;    }    /**     * Object for building the animation of the path of this view.     */    public static class AnimatorBuilder {        /**         * Duration of the animation.         */        private int duration = 350;        /**         * Interpolator for the time of the animation.         */        private Interpolator interpolator;        /**         * The delay before the animation.         */        private int delay = 0;        /**         * ObjectAnimator that constructs the animation.         */        private final ObjectAnimator anim;        /**         * Listener called before the animation.         */        private ListenerStart listenerStart;        /**         * Listener after the animation.         */        private ListenerEnd animationEnd;        /**         * Animation listener.         */        private PathViewAnimatorListener pathViewAnimatorListener;        /**         * Default constructor.         *         * @param pathView The view that must be animated.         */        public AnimatorBuilder(final PathView pathView) {            anim = ObjectAnimator.ofFloat(pathView, "percentage", 0.0f, 1.0f);        }        /**         * Set the duration of the animation.         *         * @param duration - The duration of the animation.         * @return AnimatorBuilder.         */        public AnimatorBuilder duration(final int duration) {            this.duration = duration;            return this;        }        /**         * Set the Interpolator.         *         * @param interpolator - Interpolator.         * @return AnimatorBuilder.         */        public AnimatorBuilder interpolator(final Interpolator interpolator) {            this.interpolator = interpolator;            return this;        }        /**         * The delay before the animation.         *         * @param delay - int the delay         * @return AnimatorBuilder.         */        public AnimatorBuilder delay(final int delay) {            this.delay = delay;            return this;        }        /**         * Set a listener before the start of the animation.         *         * @param listenerStart an interface called before the animation         * @return AnimatorBuilder.         */        public AnimatorBuilder listenerStart(final ListenerStart listenerStart) {            this.listenerStart = listenerStart;            if (pathViewAnimatorListener == null) {                pathViewAnimatorListener = new PathViewAnimatorListener();                anim.addListener(pathViewAnimatorListener);            }            return this;        }        /**         * Set a listener after of the animation.         *         * @param animationEnd an interface called after the animation         * @return AnimatorBuilder.         */        public AnimatorBuilder listenerEnd(final ListenerEnd animationEnd) {            this.animationEnd = animationEnd;            if (pathViewAnimatorListener == null) {                pathViewAnimatorListener = new PathViewAnimatorListener();                anim.addListener(pathViewAnimatorListener);            }            return this;        }        /**         * Starts the animation.         */        public void start() {            anim.setDuration(duration);            anim.setInterpolator(interpolator);            anim.setStartDelay(delay);            anim.start();        }        /**         * Animation listener to be able to provide callbacks for the caller.         */        private class PathViewAnimatorListener implements Animator.AnimatorListener {            @Override            public void onAnimationStart(Animator animation) {                if (listenerStart != null) listenerStart.onAnimationStart();            }            @Override            public void onAnimationEnd(Animator animation) {                if (animationEnd != null) animationEnd.onAnimationEnd();            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        }        /**         * Called when the animation start.         */        public interface ListenerStart {            /**             * Called when the path animation start.             */            void onAnimationStart();        }        /**         * Called when the animation end.         */        public interface ListenerEnd {            /**             * Called when the path animation end.             */            void onAnimationEnd();        }    }}

引用布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#f0f0f0"    tools:context=".activity.MainActivity">    <com.example.administrator.androidanimation.View.PathView        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="#ffffff" />    <ImageView        android:id="@+id/iv"        android:layout_width="100px"        android:layout_height="100px"        android:layout_marginLeft="100px"        android:layout_marginTop="100px"        app:srcCompat="@drawable/clear" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerHorizontal="true"        android:onClick="startAnim"        android:text="太阳运动"        android:textSize="18sp" /></RelativeLayout>

Activity调用

public class PathAnimActivity extends AppCompatActivity {    private ImageView iv;    private int screenWidth;    private int screenHeight;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_path_anim);        iv = (ImageView) findViewById(R.id.iv);        screenWidth = getResources().getDisplayMetrics().widthPixels;        screenHeight = getResources().getDisplayMetrics().heightPixels;    }    public void startAnim(View view) {        Path path = new Path();        path.moveTo(100, 100);        path.quadTo(screenWidth - 300, 200, screenWidth - 100, screenHeight - 600);        ObjectAnimator animator = ObjectAnimator.ofFloat(iv, View.X, View.Y, path);        animator.setDuration(2000);        animator.setRepeatCount(1);        animator.setRepeatMode(ValueAnimator.REVERSE);        animator.start();    }

实现效果:

这里写图片描述

总结

通过对实例的学习,相信对属性动画有了深度的了解。
写博客是为了帮助开发者学习使用技术,同时巩固自己所学技术。如果此篇博客有助于您的学习,那是我的荣幸!如果此篇博客有任何瑕疵,请多多指教!在此感谢您的学习和指教!

阅读全文
0 0