总归是逮着机会,稍微慢一点。在过去的很长一段时间内,都是在业务逻辑的复杂变化中挣扎。没有技术上的成长,内心还是蛮恐慌的。一不小心,又带有了些许的情绪在里面。。。。。
一、属性动画单个动画
1,布局文件添加动画作用目标
<?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.future.animatordemo.MainActivity"> <ImageView android:id="@+id/content_iv" android:layout_width="150dp" android:layout_height="150dp" android:src="@mipmap/koala" /> </RelativeLayout>
2,获取控件并执行动画
public class MainActivity extends AppCompatActivity implements View.OnClickListener { /** * 图片 */ private ImageView contentIV; /** * 自定义控件 */ private PointView createView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_bak); initView(); initAnimation(); initListener(); } /** * 初始化控件 */ private void initView() { contentIV = findViewById(R.id.content_iv); } /** * 初始化动画 */ private void initAnimation() { rotateAnimation(); //alpahAnimation(); } private void initListener() { contentIV.setOnClickListener(this); } /** * 旋转动画 */ private void rotateAnimation() { ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "rotation", 0f, 360f); anim.setDuration(1000); anim.start(); } /** * 透明渐变动画 */ private void alpahAnimation() { ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f); anim.setRepeatCount(-1); anim.setRepeatMode(ObjectAnimator.REVERSE); anim.setDuration(2000); anim.start(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.content_iv: Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show(); break; } } }
执行效果:
旋转动画:
透明渐变动画:
二、属性动画的合集
添加以下方法,并在onCreate()中调用
private void setAnimation() { ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f); ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f); ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f); ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360); ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400); ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600); AnimatorSet set = new AnimatorSet(); set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动 // set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim); set.setDuration(3000); set.start(); }
其中playTogether()将所有的动画组合在一起,同时开启动画。playSequentially()将动画顺序执行,当上一个动画没有结束时,下一个动画不会开始执行。
展示效果:
三、属性动画的监听
代码修改,添加动画运行更新监听,并在更新方法中刷新控件状态。使用了Layout()方法。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { /** * 图片 */ private ImageView contentIV; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initListener(); } /** * 初始化控件 */ private void initView() { contentIV = findViewById(R.id.content_iv); } private void initListener() { contentIV.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.content_iv: Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show(); break; } } public void startAnimatorAnimation(View view) { ValueAnimator animator = ValueAnimator.ofInt(0, 400); animator.setDuration(1000); animator.setInterpolator(new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int curValue = (int) animation.getAnimatedValue(); contentIV.layout(curValue, curValue, curValue + contentIV.getWidth(), curValue + contentIV.getHeight()); } }); animator.setStartDelay(1000); animator.start(); } }
备注:
相比于补间动画,属性动画直接修改了控件属性。直接反馈就是点击事件在补间动画时,只有在控件开始的位置执行才有效,其他地方无效。而属性动画在运行过程中,控件所在位置就是响应事件响应位置。
展示效果:
四、属性动画的应用
依据以上学习内容,制作自定义控件,展示属性动画的应用。
自定义控件实现如下:
public class PointView extends View { public static final float RADIUS = 20f; private Point currentPoint; private Paint mPaint; private Paint linePaint; private AnimatorSet animSet; private TimeInterpolator interpolatorType = new LinearInterpolator(); /** * 实现关于color 的属性动画 */ private int color; private float radius = RADIUS; public PointView(Context context) { super(context); init(); } public PointView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PointView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public int getColor() { return color; } public void setColor(int color) { this.color = color; mPaint.setColor(this.color); } public float getRadius() { return radius; } public void setRadius(float radius) { this.radius = radius; } private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.TRANSPARENT); linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); linePaint.setColor(Color.BLACK); linePaint.setStrokeWidth(5); } @Override protected void onDraw(Canvas canvas) { if (currentPoint == null) { currentPoint = new Point((int) RADIUS, (int) RADIUS); drawCircle(canvas); } else { drawCircle(canvas); } drawLine(canvas); } private void drawLine(Canvas canvas) { canvas.drawLine(10, getHeight() / 2, getWidth(), getHeight() / 2, linePaint); canvas.drawLine(10, getHeight() / 2 - 150, 10, getHeight() / 2 + 150, linePaint); canvas.drawPoint(currentPoint.x, currentPoint.y, linePaint); } public void startAnimation() { Point startP = new Point((int) RADIUS, (int) RADIUS); // Point endP = new Point(getWidth() - (int) RADIUS, getHeight() - (int) RADIUS); Point endP = new Point(MainApplication.getApplication().getWidth() - (int) RADIUS, MainApplication.getApplication().getHeight() - (int) RADIUS); final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP); valueAnimator.setRepeatCount(-1); valueAnimator.setRepeatMode(ValueAnimator.REVERSE); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentPoint = (Point) animation.getAnimatedValue(); postInvalidate(); } }); // ObjectAnimator animColor = ObjectAnimator.ofObject(this, "color", new ArgbEvaluator(), Color.GREEN, Color.YELLOW, Color.BLUE, Color.WHITE, Color.RED); animColor.setRepeatCount(-1); animColor.setRepeatMode(ValueAnimator.REVERSE); ValueAnimator animScale = ValueAnimator.ofFloat(20f, 80f, 60f, 10f, 35f, 55f, 10f); animScale.setRepeatCount(-1); animScale.setRepeatMode(ValueAnimator.REVERSE); animScale.setDuration(5000); animScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { radius = (float) animation.getAnimatedValue(); } }); animSet = new AnimatorSet(); animSet.play(valueAnimator).with(animColor).with(animScale); animSet.setDuration(5000); animSet.setInterpolator(interpolatorType); animSet.start(); } private void drawCircle(Canvas canvas) { float x = currentPoint.x; float y = currentPoint.y; canvas.drawCircle(x, y, radius, mPaint); } public void setInterpolatorType(int type) { switch (type) { case 1: interpolatorType = new BounceInterpolator(); break; case 2: interpolatorType = new AccelerateDecelerateInterpolator(); break; case 3: interpolatorType = new DecelerateInterpolator(); break; case 4: interpolatorType = new AnticipateInterpolator(); break; case 5: interpolatorType = new LinearInterpolator(); break; case 6: interpolatorType = new LinearOutSlowInInterpolator(); break; case 7: interpolatorType = new OvershootInterpolator(); default: interpolatorType = new LinearInterpolator(); break; } } @TargetApi(Build.VERSION_CODES.KITKAT) public void pauseAnimation() { if (animSet != null) { animSet.pause(); } } public void stopAnimation() { if (animSet != null) { animSet.cancel(); this.clearAnimation(); } } }
XML文件中使用:
<?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.future.animatordemo.MainActivity"> <ImageView android:id="@+id/content_iv" android:layout_width="150dp" android:layout_height="150dp" android:src="@mipmap/koala" /> <com.future.animatordemo.view.PointView android:id="@+id/create_view" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
初始化控件并使用控件:
public class MainActivityBak extends AppCompatActivity implements View.OnClickListener { /** * 图片 */ private ImageView contentIV; /** * 自定义控件 */ private PointView createView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_bak); initView(); initAnimation(); initListener(); } /** * 初始化控件 */ private void initView() { contentIV = findViewById(R.id.content_iv); createView = findViewById(R.id.create_view); } /** * 初始化动画 */ private void initAnimation() { setAnimation(); createView.startAnimation(); } private void initListener() { contentIV.setOnClickListener(this); } private void setAnimation() { ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f); ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f); ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f); ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360); ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400); ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600); AnimatorSet set = new AnimatorSet(); set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动 // set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim); set.setDuration(3000); set.start(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.content_iv: Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show(); break; } } }
展示效果:
有人请教我哆啦A梦和大雄最后有没有在一起,我便问他,许仙最后有没有和白蛇在一起。生之有涯‘最后'如何,也不过是蜿蜒个几十年的一件小事,而大事是他们,和我们曾经在一起过。
所有被千夫所指的困难,都是为了淘汰掉懦夫!