生化本来就不容易啊,而我们的不努力只会让生活变得更加无赖
这一个月发生的事有点多,有那么一段时间在缓冲。然后课程也开始比较密集,一天到晚不是去上课就是在去上课的路上。但是学习不能停,本来这些个笔记是在之前就应该整理的,但是一直到现在才有心思在学习*《Android群英传》*的基础上总结学习笔记。 今天的笔记是关于安卓的动画,这个稍微接触过安卓的朋友都不会陌生,Android的动画主要分为视图动画和属性动画,在3.0之前视图动画一家独大,在一开始基本可以满足我们的需求,但是为什么会出现属性动画呢?那肯定是试图动画越来越不满足实际开发的需要了,至于是什么?接下来会涉及。首先我们先来了解一下基本用法。
Android的视图动画
说到视图动画,得先认识Animation这个类,这个是什么意思呢?可以自行请教英语老师。但我们也还是需认识它的四个扩展类:
- AlphaAnmiation(透明度动画)
- RotateAnimation(旋转动画)
- TranslateAnimation(位移动画)
- ScaleAnimation(缩放动画)
这几个类的用法十分简单,可以在代码中直接使用或者在布局文件中定义使用(直接看用法)
- MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btnAlpha ,btnRotate,btnTranslate,btnScale ,btnSet; private AlphaAnimation a; private RotateAnimation r ; private TranslateAnimation t; private ScaleAnimation scale; private AnimationSet set ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnAlpha = (Button) findViewById(R.id.btnAlpha); btnRotate = (Button) findViewById(R.id.btnRotate); btnTranslate = (Button) findViewById(R.id.btnTranslate); btnScale = (Button) findViewById(R.id.btnScale); btnSet = (Button) findViewById(R.id.btnSet); btnAlpha.setOnClickListener(this); btnRotate.setOnClickListener(this); btnTranslate.setOnClickListener(this); btnScale.setOnClickListener(this); btnSet.setOnClickListener(this); } /** * AlphaAnimation * @param v */ private void btnAlpha(View v){ a = new AlphaAnimation(0,1); a.setDuration(1000); v.startAnimation(a); } /** * RotateAnimation * @param v */ private void btnRotate(View v){ //参数分别为旋转角度和旋转中心 r = new RotateAnimation(0,360,100,100); r.setDuration(1000); v.startAnimation(r); } /** * TranslateAnimation * @param v */ private void btnTranslate(View v){ t = new TranslateAnimation(0,200,0,200); t.setDuration(1000); Toast.makeText(MainActivity.this,"Button onClick",Toast.LENGTH_SHORT).show(); //动画结束后不归位 t.setFillAfter(true); v.startAnimation(t); //动画监听 t.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); } /** * ScaleAnimation * @param view */ private void btnScale(View view){ scale = new ScaleAnimation(0,2,0,2); scale.setDuration(1000); view.startAnimation(scale); } /** * ScaleAnimation * @param v */ private void btnSet(View v){ AnimationSet set = new AnimationSet(true); set.setDuration(1000); set.addAnimation(a); set.addAnimation(r); set.addAnimation(t); set.addAnimation(scale); v.startAnimation(set); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btnAlpha: btnAlpha(view); break; case R.id.btnRotate: btnRotate(view); break; case R.id.btnTranslate: btnTranslate(view); break; case R.id.btnScale: btnScale(view); break; case R.id.btnSet: btnSet(view); break; } }}``` * 效果![Animation](http://upload-images.jianshu.io/upload_images/2605454-59620f609b79b8d2.gif?imageMogr2/auto-orient/strip) * 总结:相信大家都会从上面效果图看到视图动画到底有什么问题(请注意TRANSLATE),是的,这件诡异的事情说明视图动画**不具备交互性**是越来越满足不了用户,更别说什么良好的用户体验,所以大家也会明白为什么Google会再3.0推出属性动画了吧。那么接下来就愉快地学习属性动画的基本用法吧!### Android的属性动画学习视图动画就必须认识这两个类:1. ObjectAnimator(儿子)2. ValueAnimator (爸爸)#####ObjectAnimator的基本用法ObjectAnimatior和AnimatorSet的结合就可以一次满足所有基本需求复制代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnAlpha ,btnRotate,btnTranslate,btnScale ,btnSet;private ObjectAnimator animator;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnAlpha = (Button) findViewById(R.id.btnAlpha); btnRotate = (Button) findViewById(R.id.btnRotate); btnTranslate = (Button) findViewById(R.id.btnTranslate); btnScale = (Button) findViewById(R.id.btnScale); btnSet = (Button) findViewById(R.id.btnSet); btnAlpha.setOnClickListener(this); btnRotate.setOnClickListener(this); btnTranslate.setOnClickListener(this); btnScale.setOnClickListener(this); btnSet.setOnClickListener(this);}@Overridepublic void onClick(View view) { int id = view.getId(); switch (id){ case R.id.btnAlpha: btnAlpha(view); break; case R.id.btnRotate: btnRotate(view); break; case R.id.btnTranslate: btnTranslate(view); break; case R.id.btnScale: btnScale(view); break; case R.id.btnSet: btnSet(view); break; }}private void btnSet(View view) { ObjectAnimator o1 = ObjectAnimator.ofFloat(view,"translationX",0,200); ObjectAnimator o2 = ObjectAnimator.ofFloat(view,"rotation",0,360); ObjectAnimator o3 = ObjectAnimator.ofFloat(view,"scaleX",0,2); AnimatorSet set = new AnimatorSet(); set.setInterpolator(new BounceInterpolator());//插值器 set.setDuration(1000);复制代码
// set.playSequentially(o1,o2,o3);//顺序 set.playTogether(o1,o2,o3);//一起执行 // set.play(o1).after(o2).with(o3);//制定顺序 set.start(); //监听事件 set.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) {
} @Override public void onAnimationEnd(Animator animator) { showToast(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); //只关注一个时刻的监听 set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); showToast(); } });}private void btnScale(View view) { animator = ObjectAnimator.ofFloat(view,"scaleX",0,2); animator.setDuration(1000); animator.start();}private void btnTranslate(View view) { animator = ObjectAnimator.ofFloat(view,"translationX",0,200); animator.setDuration(1000); animator.start();}private void btnRotate(View view) { animator = ObjectAnimator.ofFloat(view,"rotation",0,360); animator.setDuration(1000); animator.start();}private void btnAlpha(View view) { animator = ObjectAnimator.ofFloat(view,"alpha",1,0); animator.setDuration(1000); animator.start();}复制代码
}```
- 同时也可以通过PropertyValuesHolder来实现类似AnimatorSet的PlayTogether()的效果
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0,200); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX",0,2); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY",0,2); PropertyValuesHolder p4 = PropertyValuesHolder.ofFloat("rotation",0,360); ObjectAnimator.ofPropertyValuesHolder(view,p1,p2,p3,p4) .setDuration(1000).start();``` * 属性说明 1. ```translationX和translationY```(坐标偏移) 2. ```rotation,rotationX和rotationY```(3D,2D旋转) 3. ```scaleX和scaleY```(2D缩放) 4. ```pivotX和pivotY```(支点,默认为view的中心点) 5. ```x和y```(最终位置) 6. ```alpha```(透明度,默认值1为不透) * 效果![ObjectAnimator](http://upload-images.jianshu.io/upload_images/2605454-da4f4836a1c173df.gif?imageMogr2/auto-orient/strip)#####ValueAnimator的基本用法(数值发生器)复制代码
final Button b = (Button) view; ValueAnimator v = ValueAnimator.ofInt(0, 100); v.setDuration(5000); v.setTarget(view); v.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { Integer i = (Integer) valueAnimator.getAnimatedValue(); b.setText("" + i); } }); v.start();```
- 如上实现一个Button在5S内实现计时器。
常用拓展
经常会在app(如QQ音乐)的某些选择操作会有个底部弹窗给用户选择,所以趁着这次学习Android动画顺便学习了一下这个弹窗的做法。顺便还复习了一遭RecyclerView
的用法,之前也写过一篇关于RecyclerView
的笔记
代码如下:
- style.xml
``` 关于style的这里有一篇博文,基本满足需求:[Style属性](http://blog.csdn.net/jflex/article/details/7854573) 2. enter_menu.xml(进入动画)复制代码
``` 3. exit_menu.xml(退出动画)
android:duration="300" android:propertyName="translationY" android:valueFrom="0" android:valueTo="100" />``` 4. item_choice.xml 复制代码
复制代码
``` 5. PopupDialog.java
public class Popupdialog extends Dialog implements View.OnClickListener { private Animator enterAnimator,exitAnimator;//进出动画 private View mContentView; private RecyclerView recyclerView; private boolean isClose;//dialog状态 private Button btnCancek; private Listlist; private RecyclerAdapter adapter; public Popupdialog(Context context) { super(context,R.style.PopupDialog);//设置基本属性 getWindow().setGravity(Gravity.BOTTOM);//底部弹窗 initView(context);//初始View initAnimator(context);//初始动画 } public Popupdialog(Context context, int themeResId) { super(context, themeResId); } public Popupdialog(Context context, boolean cancelable, OnCancelListener cancelListener) { super(context, cancelable, cancelListener); } private void initView(final Context context) { mContentView = LayoutInflater.from(context).inflate(item,null); btnCancek = (Button) mContentView.findViewById(R.id.btnCancel); btnCancek.setOnClickListener(this); recyclerView = (RecyclerView) mContentView.findViewById(R.id.popupRecycler); recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)); ItemDecoration item = new ItemDecoration(context, LinearLayoutManager.VERTICAL); recyclerView.addItemDecoration(item); recyclerView.setItemAnimator(new DefaultItemAnimator()); list = new ArrayList<>(); adapter = new RecyclerAdapter(context,list); recyclerView.setAdapter(adapter); adapter.setListener(new RecyclerAdapter.onItemClickListener() { @Override public void onItemClick(View itemView, int adapterPosition) { showToast(context,adapterPosition); if (itemClickListener != null){ itemClickListener.itemClick(adapterPosition); } dismiss(); } }); setContentView(mContentView); } public Popupdialog addItem(String str){ list.add(str); return this; } @Override public void show() { adapter.notifyDataSetChanged(); super.show(); //适配屏幕大小,必须在show()方法后 Window window = getWindow(); WindowManager.LayoutParams wl = window.getAttributes(); wl.width = MainActivity.getMetrics().widthPixels; window.setAttributes(wl); //退出动画 exitAnimator.setTarget(mContentView); enterAnimator.start(); } @Override public void dismiss() { super.dismiss(); if (isClose){ return; } isClose = true; //动画进入 exitAnimator.setTarget(mContentView); exitAnimator.start(); } public void disMissMe(){ super.dismiss(); isClose = false; } private void showToast(Context context, int adapterPosition) { Toast.makeText(context,adapterPosition + "onClick",Toast.LENGTH_SHORT).show(); } private void initAnimator(Context context) { enterAnimator = AnimatorInflater.loadAnimator(context,R.animator.menu_enter); exitAnimator = AnimatorInflater.loadAnimator(context,R.animator.menu_exit); exitAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); disMissMe(); } }); } @Override public void onClick(View view) { onBackPressed(); } public interface ItemClickListener{ void itemClick(int adapterPosition); } private ItemClickListener itemClickListener; public void setItemClickListener(ItemClickListener itemClickListener) { this.itemClickListener = itemClickListener; }}复制代码
- 效果
总结
Android的动画基本如上,但是这些都是建立在巨人的肩膀上的,希望自己以后认真学习,争取尽快拥有满足市场要求的能力。另外,这个月的事的确影响到自己,希望自己认识到个中因由,警示自己,不断向前! 如果你觉得本文有所错漏,请指出批评,交流学习共同进步