Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
// 可操控的屬性有:alpha;x/y;scaleX/scaleY;rotation/rotationX/rotationY;transitionX/transitionY;pivotX/pivotY public class MainActivity extends ListActivity { private ImageView iv_src; private boolean b = true; private String[] array = {"重啓當前Activity,啓動一個新的Activity", "最簡單的ObjectAnimator,控制scaleX、rotationX", "不存在get/set方法時不會有任何效果\n爲Object的某個屬性手動提供get/set方法", "只有set沒有get方法時,get的值不存在,可是set能夠正常使用", "監聽動畫更新:AnimatorUpdateListener\n監聽動畫狀態:AnimatorListener", "組合動畫:AnimatorSet.playTogether\n組合動畫:AnimatorSet.with/before/after", "組合動畫:AnimatorUpdateListener\n組合動畫:PropertyValuesHolder", "組合動畫:PVHolder + KeyFrame\nView的animate動畫,最簡潔的屬性動畫", "View的animate動畫也能夠組合動畫\n能夠在animate動畫前/後執行一些操做", "最簡單的ValueAnimator,控制translationY\n要明白ValueAnimator只是幫你計算插值的"}; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array)); iv_src = new ImageView(this); iv_src.setBackgroundColor(0x330000ff); iv_src.setImageResource(R.drawable.icon); getListView().addHeaderView(iv_src); } @Override protected void onListItemClick(ListView l, View view, int position, long id) { switch (position) { case 0: b = !b; Toast.makeText(this, "目前爲:" + b, Toast.LENGTH_SHORT).show(); break; case 1: if (b) recreate();//重啓當前Activity else startActivity(new Intent(this, SecondActivity.class)); break; case 2://最簡單的ObjectAnimator,控制scaleX、rotationX if (b) ObjectAnimator.ofFloat(iv_src, "scaleX", 1f, 0.1f, 3f, 0.1f, 1f)//X軸縮放 .setDuration(1000) .start(); else ObjectAnimator.ofFloat(iv_src, "rotationX", 0.0f, 720.0f)//沿X軸旋轉 .setDuration(500) .start(); break; case 3://不存在get/set方法時不會有任何效果,能夠爲Object的某個屬性手動提供get/set方法 int i = new Random().nextInt(8) + 1; if (b) ObjectAnimator.ofFloat(iv_src, "width", 100 * i)//沒任何效果,但並不會報錯 .setDuration(500) .start(); else ObjectAnimator.ofInt(new WrapperView(iv_src), "width", 100 * i) //提供set方法 .setDuration(500) .start(); break; case 4://只有set沒有get方法時,get的值不存在,可是set能夠正常使用 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { iv_src.setBackgroundColor(Color.WHITE); //有set方法,可是沒有get方法,因此get結果爲0 if (b) ObjectAnimator.ofArgb(iv_src, "backgroundColor", Color.RED) .setDuration(1000) .start(); else ObjectAnimator.ofArgb(iv_src, "backgroundColor", Color.RED, Color.GREEN, Color.BLUE) .setDuration(3000) .start(); } break; case 5://監聽動畫更新:AnimatorUpdateListener,監聽動畫狀態:AnimatorListener AnimHelper.addAnimListener(iv_src).start(); break; case 6://組合動畫:AnimatorSet.playTogether/with/before/after if (b) AnimHelper.combinedAnimPlayTogether(iv_src).start(); else AnimHelper.combinedAnimAfterBefore(iv_src).start(); break; case 7://組合動畫:AnimatorUpdateListener,PropertyValuesHolder if (b) AnimHelper.combinedAnimUpdate(iv_src).start(); else AnimHelper.propertyValuesHolder(iv_src).start(); break; case 8://組合動畫:PVHolder + KeyFrame,View的animate動畫,最簡潔的屬性動畫 if (b) AnimHelper.pVHolderKeyFrame(iv_src).start(); else iv_src.animate().y(200 * (new Random().nextInt(8))).setDuration(500).start();//ViewPropertyAnimator break; case 9://View的animate動畫也能夠組合動畫,也能夠在animate動畫前/後執行一些操做 if (b) iv_src.animate() .setDuration(1000) .rotation(360 * new Random().nextInt(8)) .scaleX(new Random().nextInt(8) * 0.5f) .setInterpolator(new DecelerateInterpolator()) .start(); else iv_src.animate() .alpha(0.1f) .y(1500) .setDuration(800) .withStartAction(() -> iv_src.setX(300)) .withEndAction(() -> { iv_src.setX(0); iv_src.setY(0); iv_src.setAlpha(1f); }) .start(); break; case 10://最簡單的ValueAnimator,控制translationY,要明白ValueAnimator只是幫你計算插值的 if (b) AnimHelper.valueAnimator(iv_src).start(); else AnimHelper.valueAnimator(iv_src, getListView()).start(); break; } } }
View包裝類,爲不存在get/set方法的屬性提供get/set方法java
// View包裝類,爲不存在get/set方法的屬性提供get/set方法 public class WrapperView { private View mTarget; public WrapperView(View target) { mTarget = target; } public int getWidth() { return mTarget.getLayoutParams().width; } public void setWidth(int width) { mTarget.getLayoutParams().width = width; mTarget.requestLayout(); } public int getHeight() { return mTarget.getLayoutParams().height; } public void setHeight(int height) { mTarget.getLayoutParams().height = height; mTarget.requestLayout();//Call this when something has changed which has invalidated the layout of this view } }
public class AnimHelper { //監聽動畫繪製過程 public static ObjectAnimator addAnimListener(View view) { ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.1f, 1f).setDuration(1000); //方法一,實現AnimatorListener接口,監聽開始Start、結束End、被取消Cancel、重複Repeat等事件 //方法二,繼承AnimatorListenerAdapter,只實現本身想實現的事件 anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { Log.i("bqt", "【onAnimationStart】"); } @Override public void onAnimationEnd(Animator animation) { Log.i("bqt", "【onAnimationEnd】"); } }); anim.addUpdateListener(animation -> { Float value = (Float) animation.getAnimatedValue(); view.setRotationX((1 - value) * 360); Log.i("bqt", "onAnimationUpdate--" + value); //很是頻繁 }); return anim; } public static AnimatorSet combinedAnimPlayTogether(View view) { ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "scaleX", 0, 2f, 1f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "alpha", 0, 1f); ObjectAnimator anim3 = ObjectAnimator.ofFloat(view, "rotationY", 360); AnimatorSet animSet = new AnimatorSet().setDuration(2000); animSet.playTogether(anim1, anim2, anim3); return animSet; } public static AnimatorSet combinedAnimAfterBefore(View view) { ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 2f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "scaleY", 0.1f, 1f); ObjectAnimator anim3 = ObjectAnimator.ofFloat(view, "x", 0, -view.getWidth(), 0); ObjectAnimator anim4 = ObjectAnimator.ofFloat(view, "y", 0, view.getY() + 500f, 0); ObjectAnimator anim5 = ObjectAnimator.ofFloat(view, "rotationX", 360 * 2); AnimatorSet animSet = new AnimatorSet(); animSet.play(anim1).with(anim2);//anim1,anim2同時執行 animSet.play(anim2).with(anim3);//anim1,anim2,anim3同時執行 animSet.play(anim4).after(anim3).before(anim5);//anim4在anim1,anim2,anim3以後,在anim5以前 animSet.setDuration(1000); return animSet; } public static Animator combinedAnimUpdate(View view) { //ObjectAnimator anim = ObjectAnimator.ofFloat(view, "包青天", 0.5f, 0.1f, 2f).setDuration(2000); ValueAnimator anim = ValueAnimator.ofFloat(0.5f, 0.1f, 2f).setDuration(2000); //效果和上面的ObjectAnimator徹底同樣 anim.addUpdateListener(animation -> { float cVal = (Float) animation.getAnimatedValue(); view.setScaleX(cVal); view.setAlpha(cVal); view.setRotationX(cVal * 360); }); return anim; } public static ObjectAnimator propertyValuesHolder(View view) { PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 0.2f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 0.8f, 0, 2f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("rotationY", 360 * 2f, 0); return ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ).setDuration(1000);//三個動畫是同時執行的 } public static ObjectAnimator pVHolderKeyFrame(View view) { Keyframe kf0 = Keyframe.ofFloat(0f, 0f); Keyframe kf1 = Keyframe.ofFloat(0.5f, 360f); Keyframe kf2 = Keyframe.ofFloat(1f, 0f); kf1.setInterpolator(new AccelerateInterpolator()); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2); return ObjectAnimator.ofPropertyValuesHolder(view, pvhRotation).setDuration(1000); } public static ValueAnimator valueAnimator(View view) { ValueAnimator animator = ValueAnimator.ofFloat(0, 800, 0).setDuration(500);//沒有設置要操做的【對象】及【對象的屬性】 //animator.setTarget(view);//對ValueAnimator來講,這個方法是空方法(沒有意義),由於它不會做用在任何View上 //對ValueAnimator來講,是經過addUpdateListener,在回調中根據動畫的值來手動設置屬性的值的 animator.addUpdateListener(animation -> { Float f = (Float) animation.getAnimatedValue();//這裏只能強轉爲of**時指定的類型 view.setTranslationY(f);//設置要操做的對象的屬性。或者你可使用獲取到的值作任何事情 }); return animator; } public static ValueAnimator valueAnimator(View view, ListView listView) { ValueAnimator animator = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { animator = ValueAnimator.ofArgb(Color.GREEN).setDuration(5000); animator.addUpdateListener(animation -> { Integer greenColor = (Integer) animation.getAnimatedValue(); //實時獲取值 int myColor = (int) (animation.getAnimatedFraction() * Color.YELLOW); int count = listView.getAdapter().getCount(); for (int i = 1; i < count; i++) { if (i % 2 == 0) listView.getChildAt(i).setBackgroundColor(greenColor); else listView.getChildAt(i).setBackgroundColor(myColor); } }); } return animator; } }
// 自定義TypeEvaluator實現拋物線動畫效果 public class TypeEvaluatorActivity extends Activity { private static final int RADIUS_BALL = 10; //小球的半徑 private static final int RADIUS_TRACE = 3; //軌跡的半徑 private ImageView iv_src; RelativeLayout layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 initView(); layout = new RelativeLayout(this); layout.setBackgroundColor(Color.LTGRAY); layout.setOnClickListener(v -> anim()); layout.addView(iv_src, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); setContentView(layout); } private void initView() { Bitmap bitmap = Bitmap.createBitmap(2 * RADIUS_BALL, 2 * RADIUS_BALL, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setAntiAlias(true); paint.setDither(true); canvas.drawCircle(RADIUS_BALL, RADIUS_BALL, RADIUS_BALL, paint); iv_src = new ImageView(this); iv_src.setImageBitmap(bitmap); } private void anim() { final int color = 0xFF000000 + new Random().nextInt(0xFFFFFF); Point point = new Point(); ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(point); PointF startPointF = new PointF(0, 0); PointF endPointF = new PointF(point.x - iv_src.getWidth(), point.y - iv_src.getHeight()); ValueAnimator animator = new ValueAnimator().setDuration(1000); animator.setInterpolator(new LinearInterpolator()); //插值器,默認爲AccelerateDecelerateInterpolator【慢-快-慢】 //經過new建立的ValueAnimator必須setObjectValues和setEvaluator,而且必定要先setObjectValues,再setEvaluator animator.setObjectValues(startPointF, endPointF); animator.setEvaluator((TypeEvaluator<PointF>) (fraction, startValue, endValue) -> { //估值器 //只要能保證:當fraction=0時返回值爲startValue,而且當fraction=1時返回值爲endValue,就是一個比較合理的函數 PointF pointF = new PointF(); pointF.x = startValue.x + fraction * (endValue.x - startValue.x);// x方向勻速移動 pointF.y = startValue.y + fraction * fraction * (endValue.y - startValue.y);// y方向拋物線加速移動 return pointF; }); animator.addUpdateListener(animation -> { PointF pointf = (PointF) animation.getAnimatedValue(); iv_src.setX(pointf.x); iv_src.setY(pointf.y); addTrace(pointf, color); }); animator.start(); } private void addTrace(PointF pointf, int color) { View view = new View(this); view.setBackgroundColor(color); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(2 * RADIUS_TRACE, 2 * RADIUS_TRACE); layoutParams.leftMargin = (int) pointf.x + RADIUS_TRACE; layoutParams.topMargin = (int) pointf.y + RADIUS_TRACE; layout.addView(view, layoutParams); } }
public class LayoutTransitionActivity extends ListActivity { private GridLayout gl_container;//父佈局 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] array = {"點擊添加一個View,點擊添加的View刪除此View"}; setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array)); gl_container = new GridLayout(this); gl_container.setColumnCount(4); gl_container.setLayoutTransition(new LayoutTransition());//佈局動畫,當容器中的視圖發生變化時存在過渡的動畫效果 getListView().addFooterView(gl_container); addCheckBox(LayoutTransition.APPEARING, "APPEARING");//當一個View在VG中【出現】時設置的動畫 addCheckBox(LayoutTransition.CHANGE_APPEARING, "CHANGE_APPEARING"); //當一個View在ViewGroup中【出現】時,對此View對其餘View位置形成影響,對【其餘View】設置的動畫 addCheckBox(LayoutTransition.DISAPPEARING, "DISAPPEARING");//當一個View在VG中【消失】時設置的動畫 addCheckBox(LayoutTransition.CHANGE_DISAPPEARING, "CHANGE_DISAPPEARING"); //當一個View在ViewGroup中【消失】時,對此View對其餘View位置形成影響,對【其餘View】設置的動畫 addCheckBox(-1, "等價因而否設置xml中GridLayout的animateLayoutChanges屬性爲true"); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { Button button = new Button(this); button.setText(gl_container.getChildCount() + 1 + ""); gl_container.addView(button, gl_container.getChildCount());//放置在最後那個位置 button.setOnClickListener(view -> gl_container.removeView(button)); } private void addCheckBox(int transitionType, String text) { CheckBox checkBox = new CheckBox(this); checkBox.setText(text); checkBox.setChecked(true); checkBox.setOnCheckedChangeListener((v, isChecked) -> { LayoutTransition mTransition = new LayoutTransition(); //默認爲所有開啓狀態,默認的動畫效果都是能夠更改的 if (transitionType == -1) mTransition = isChecked ? mTransition : null; else mTransition.setAnimator(transitionType, isChecked ? mTransition.getAnimator(transitionType) : null); gl_container.setLayoutTransition(mTransition); }); getListView().addFooterView(checkBox); } }
public class LayoutAnimationControllerActivity extends ListActivity { LinearLayout linearLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] array = {"點擊添加HeaderView", "點擊添加的HeaderView", "移除添加移除View時沒任何動畫效果", "ListView不支持addView操做"//UnsupportedOperationException:addView(View) is not supported in AdapterView }; setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array)); getListView().setLayoutAnimation(getLayoutAnimationController());//android:layoutAnimation="@anim/layout_anim" addFooterView(); } private void addFooterView() { linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); new Handler().postDelayed(() -> linearLayout.addView(getView(v -> linearLayout.removeView(v))), 500); new Handler().postDelayed(() -> linearLayout.addView(getView(v -> linearLayout.removeView(v))), 1500); new Handler().postDelayed(() -> linearLayout.addView(getView(v -> linearLayout.removeView(v))), 3500); linearLayout.setLayoutAnimation(getLayoutAnimationController()); getListView().addHeaderView(linearLayout); } private LayoutAnimationController getLayoutAnimationController() { Animation animation = AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left);//補間動畫 LayoutAnimationController lac = new LayoutAnimationController(animation);//佈局動畫 lac.setOrder(LayoutAnimationController.ORDER_NORMAL);//顯示順序 normal=0 默認,reverse=1 倒序,random=2 隨機 lac.setDelay(0.6f);//顯示間隔時間,注意單位是秒,能夠爲70%,也能夠是一個浮點數 return lac; } @Override protected void onListItemClick(ListView l, View v, int position, long id) { int index = position - getListView().getHeaderViewsCount(); if (index == 0) { getListView().addHeaderView((getView(view -> getListView().removeHeaderView(view)))); } else if (index == 1) { linearLayout.addView(getView(view -> linearLayout.removeView(view))); } } private ImageView getView(View.OnClickListener listener) { ImageView iv = new ImageView(this); iv.setImageResource(R.drawable.ic_launcher); iv.setOnClickListener(listener); return iv; } }
public class SecondActivity extends ListActivity { private final String[][] array = {INTERPOLATORS1, INTERPOLATORS2, INTERPOLATORS3, INTERPOLATORS4, INTERPOLATORS5, INTERPOLATORS6,}; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 requestWindowFeature(Window.FEATURE_NO_TITLE);//取消標題欄 String[] names = {"-1-", "-2-", "-3-", "-4-", "-5-", "-6-", // "自定義TypeEvaluator實現拋物線動畫效果", // "使用LayoutTransition爲佈局容器中子View的顯示與消失設置過渡動畫", // "使用LayoutAnimationController爲佈局容器中的控件播放一樣的動畫",}; setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, names)); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { switch (position) { case 6: startActivity(new Intent(this, TypeEvaluatorActivity.class)); break; case 7: startActivity(new Intent(this, LayoutTransitionActivity.class)); break; case 8: startActivity(new Intent(this, LayoutAnimationControllerActivity.class)); break; default: Intent intent = new Intent(this, InterpolatorActivity.class); intent.putExtra(InterpolatorActivity.EXTRA_NAME, array[position]); startActivity(intent); break; } } public static final String[] INTERPOLATORS1 = new String[]{"EaseBackInInterpolator", "EaseBackInOutInterpolator", "EaseBackOutInterpolator", "EaseBounceInInterpolator", "EaseBounceInOutInterpolator", "EaseBounceOutInterpolator", "EaseBreathInterpolator", "EaseCircularInInterpolator", "EaseCircularInOutInterpolator", "EaseCircularOutInterpolator",}; public static final String[] INTERPOLATORS2 = new String[]{"EaseCubicInInterpolator", "EaseCubicInOutInterpolator", "EaseCubicOutInterpolator", "EaseExponentialInInterpolator", "EaseExponentialInOutInterpolator", "EaseExponentialOutInterpolator", "EaseInBackInterpolator", "EaseInBounceInterpolator", "EaseInCircInterpolator", "EaseInCubicInterpolator",}; public static final String[] INTERPOLATORS3 = new String[]{"EaseInElasticInterpolator", "EaseInExpoInterpolator", "EaseInOutBackInterpolator", "EaseInOutBounceInterpolator", "EaseInOutCircInterpolator", "EaseInOutCubicInterpolator", "EaseInOutElasticInterpolator", "EaseInOutExpoInterpolator", "EaseInOutQuadInterpolator", "EaseInOutQuartInterpolator",}; public static final String[] INTERPOLATORS4 = new String[]{"EaseInOutQuintInterpolator", "EaseInOutSineInterpolator", "EaseInQuadInterpolator", "EaseInQuartInterpolator", "EaseInQuintInterpolator", "EaseInSineInterpolator", "EaseOutBackInterpolator", "EaseOutBounceInterpolator", "EaseOutCircInterpolator", "EaseOutCubicInterpolator",}; public static final String[] INTERPOLATORS5 = new String[]{"EaseOutElasticInterpolator", "EaseOutExpoInterpolator", "EaseOutQuadInterpolator", "EaseOutQuartInterpolator", "EaseOutQuintInterpolator", "EaseOutSineInterpolator", "EaseQuadInInterpolator", "EaseQuadInOutInterpolator", "EaseQuadOutInterpolator", "EaseQuartInInterpolator",}; public static final String[] INTERPOLATORS6 = new String[]{"EaseQuartInOutInterpolator", "EaseQuartOutInterpolator", "EaseQuintInInterpolator", "EaseQuintInOutInterpolator", "EaseQuintOutInterpolator",}; }
public class InterpolatorActivity extends ListActivity { private ObjectAnimator mAnimator; private static final String IN_PG_NAME = "com.bqt.anim.interpolator."; public static final String EXTRA_NAME = "interpolators"; private String[] mInterpolators; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 mInterpolators = getIntent().getStringArrayExtra(EXTRA_NAME); //傳過來的名字 setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mInterpolators)); ImageView iv_src = new ImageView(this); iv_src.setBackgroundColor(0x330000ff); iv_src.setImageResource(R.drawable.icon); getListView().addHeaderView(iv_src); DisplayMetrics metric = new DisplayMetrics(); ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metric); mAnimator = ObjectAnimator.ofFloat(iv_src, "y", 0, metric.heightPixels, 0).setDuration(1500); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { if (position == 0) recreate(); else anim(position - 1); } private void anim(int position) { String name = mInterpolators[position]; try { Class<?> clazz = Class.forName(IN_PG_NAME + name); TimeInterpolator interpolator = (TimeInterpolator) clazz.newInstance(); mAnimator.cancel(); mAnimator.setInterpolator(interpolator); mAnimator.start(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
public class MainActivity extends ListActivity { private ImageView iv; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] array = {"alpha", "trans", "scale", "rotate", "set", "fillAfter = true時,無論其餘怎麼設置,都是使用最後一幀", "fillAfter = false時,無論其餘怎麼設置,都是使用第一幀",}; setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array)); iv = new ImageView(this); iv.setBackgroundColor(0x330000ff); iv.setImageResource(R.drawable.icon); iv.setOnClickListener(v -> Toast.makeText(this, "點擊了View", Toast.LENGTH_SHORT).show()); getListView().addHeaderView(iv); } @Override protected void onListItemClick(ListView l, View view, int position, long id) { Animation animation = null; switch (position - getListView().getHeaderViewsCount()) { case 0: animation = AnimHelper.alpha(); break; case 1: animation = AnimHelper.trans(); break; case 2: animation = AnimHelper.scale(); break; case 3: animation = AnimHelper.rotate(); break; case 4: animation = AnimHelper.set(); break; case 5: animation = AnimHelper.scale(); animation.setFillEnabled(new Random().nextBoolean()); animation.setFillBefore(new Random().nextBoolean()); animation.setFillAfter(true);//動做結束後停留在最後一幀 break; case 6: animation = AnimHelper.scale(); animation.setFillEnabled(new Random().nextBoolean()); animation.setFillBefore(new Random().nextBoolean()); animation.setFillAfter(false);//動做結束後停留在第一幀(沒有進行任何縮放) break; } iv.startAnimation(animation); } }
public class AnimHelper { //透明度動畫 public static Animation alpha() { AlphaAnimation animation = new AlphaAnimation(1.0f, 0.1f);//開始、結束時的透明度。1爲全不透明,0爲全透明 animation.setDuration(2000);//播放時間 animation.setRepeatCount(1);//重複次數,默認爲0。播放次數=重複次數+1。Animation.INFINITE表示不中止的播放 animation.setRepeatMode(Animation.RESTART);//【REVERSE】倒序重複播放,【RESTART】從新開始執行(默認) animation.setInterpolator(new AccelerateInterpolator());//加速 return animation; } //位移動畫 public static Animation trans() { TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f,//8個參數:fromXType, fromXValue, toXType, toXValue Animation.RELATIVE_TO_SELF, -1f, //【開始/結束】時【相對誰】的距離 Animation.RELATIVE_TO_PARENT, 1f); animation.setDuration(1000); animation.setRepeatCount(Animation.INFINITE); //不中止的播放 animation.setRepeatMode(Animation.REVERSE); //倒序重複播放 animation.setInterpolator(new BounceInterpolator());//動畫結束的時候彈起 return animation; } //縮放動畫 public static Animation scale() { ScaleAnimation animation = new ScaleAnimation(0.5f, 2.5f, //開始、結束時x的縮放比例 0.1f, 1.5f, //開始、結束時y的縮放比例 Animation.RELATIVE_TO_SELF, 0.5f, //x縮放時所使用的模式和中心點 Animation.RELATIVE_TO_SELF, 0.5f); //y縮放時所使用的模式和中心點 animation.setDuration(1000); animation.setInterpolator(new AccelerateDecelerateInterpolator());//先加速後減速 return animation; } //旋轉動畫 public static Animation rotate() { RotateAnimation animation = new RotateAnimation(0, 360 * 5, //開始、結束時旋轉角度 Animation.RELATIVE_TO_SELF, 0.5f, //x旋轉時所使用的模式和中心點 Animation.RELATIVE_TO_SELF, 0.5f); //y旋轉時所使用的模式和中心點 animation.setDuration(1000); animation.setInterpolator(new LinearInterpolator());//勻速 return animation; } //組合動畫 public static AnimationSet set() { AnimationSet animationSet = new AnimationSet(false);//是否使用共同的插值器 //位移 TranslateAnimation ta = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.5f); ta.setDuration(800); ta.setInterpolator(new AccelerateInterpolator());//快-慢 //縮放 ScaleAnimation sa = new ScaleAnimation(2f, 1f, 0.5f, 2f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.5f); sa.setDuration(800); sa.setStartOffset(1000);//延遲時間 When this Animation should start //旋轉 RotateAnimation ra = new RotateAnimation(0, 360 * 5, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); ra.setDuration(1500); ra.setStartOffset(2000); sa.setInterpolator(new DecelerateInterpolator()); //慢-快 //將上面這些動畫放到集合中 animationSet.addAnimation(ta); animationSet.addAnimation(sa); animationSet.addAnimation(ra); //set.setFillEnabled(true); animationSet.setFillAfter(true); //set.setFillBefore(false); return animationSet; } }
public class SecondActivity extends ListActivity { int[] array_id = {R.anim.alpha_in, R.anim.disappear_bottom_right_in, R.anim.disappear_bottom_right_out, R.anim.disappear_top_left_in, R.anim.disappear_top_left_out, R.anim.drawroll_ani_in, R.anim.drawroll_ani_out, R.anim.fade_out, R.anim.flip_horizontal_in, R.anim.flip_horizontal_out, R.anim.flip_vertical_in, R.anim.flip_vertical_out, R.anim.gallery_in, R.anim.grow_from_top, R.anim.left_in, R.anim.left_out, R.anim.mi_laucher_alpha, R.anim.mi_laucher_del_done, R.anim.mi_laucher_del_down, R.anim.mi_laucher_out, R.anim.mi_laucher_scale_in, R.anim.mi_laucher_scale_out, R.anim.pophidden_anim, R.anim.popshow_anim, R.anim.push_left_in, R.anim.push_left_out, R.anim.push_up_in, R.anim.push_up_out, R.anim.rbm_in_from_left, R.anim.rbm_out_to_left, R.anim.refreshable_list_rotate, R.anim.right_in, R.anim.right_out, R.anim.shrink_from_bottom, R.anim.slide_down_out, R.anim.slide_left, R.anim.slide_right, R.anim.slide_up_in, R.anim.small_2_big, R.anim.umeng_fb_slide_in_from_left, R.anim.umeng_fb_slide_in_from_right, R.anim.umeng_fb_slide_out_from_left, R.anim.umeng_fb_slide_out_from_right, R.anim.umeng_socialize_fade_in, R.anim.umeng_socialize_fade_out, R.anim.umeng_socialize_shareboard_animation_in, R.anim.umeng_socialize_shareboard_animation_out, R.anim.umeng_socialize_slide_in_from_bottom, R.anim.umeng_socialize_slide_out_from_bottom, R.anim.unzoom_in, R.anim.unzoom_out, R.anim.welcome_fade_in_scale, R.anim.welcome_fade_out, R.anim.zoom_enter, R.anim.zoom_exit}; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] array_name = new String[array_id.length]; for (int i = 0; i < array_id.length; i++) { String name = getResources().getResourceName(array_id[i]); array_name[i] = name.replace(getPackageName() + ":anim/", ""); } setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array_name)); getListView().setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { Log.i("bqt", "【onScrollStateChanged】" + scrollState); //臥槽,我發現滑動時這個方法並不必定會回調 // AbsListView.OnScrollListener.SCROLL_STATE_FLING; //屏幕處於甩動狀態 // AbsListView.OnScrollListener.SCROLL_STATE_IDLE; //中止滑動狀態 // AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;// 手指接觸狀態 if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { int visibleCount = getListView().getLastVisiblePosition() - getListView().getFirstVisiblePosition() + 1; //可見的數量 for (int i = 0; i < visibleCount; i++) { int reallyIndex = i + getListView().getFirstVisiblePosition();//真正的位置 int alpha = 255 * reallyIndex / view.getCount(); int color; if (reallyIndex % 2 == 0) color = Color.argb(alpha, 0, 255, 0); else color = Color.argb(alpha, 0, 0, 255); getListView().getChildAt(i).setBackgroundColor(color); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //當前窗口中能看見的第一個列表項ID,當前窗口中能看見的列表項的個數,列表項的總數 //Log.i("bqt", "【onScroll】" + firstVisibleItem + "," + visibleItemCount + "," + totalItemCount); } }); } @Override protected void onResume() { super.onResume(); Log.i("bqt", "【onResume】"); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { v.setAnimation(AnimationUtils.loadAnimation(this, array_id[position])); } }
默認轉場動畫:android
overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right);
自定義轉場動畫:git
public class BaseActivity extends Activity { @Override public void startActivity(Intent intent) { super.startActivity(intent); overridePendingTransition(R.anim.activity_in_from_down, R.anim.activity_out_to_up); } @Override public void finish() { super.finish(); overridePendingTransition(R.anim.activity_in_from_top, R.anim.activity_out_to_down); } }
public class Activity1 extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ImageView imageView = new ImageView(this); imageView.setImageResource(R.drawable.icon); imageView.setBackgroundColor(0xFF000000 + new Random().nextInt(0xFFFFFF)); imageView.setOnClickListener(v -> startActivity(new Intent(this, Activity1.class))); setContentView(imageView); } }
存放位置:android_sdk\platforms\android-28\data\res\anim
默認時間:<integer name="config_mediumAnimTime">400</integer>
github
fade_in 淡入canvas
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="@android:integer/config_longAnimTime" android:fromAlpha="0.0" android:interpolator="@interpolator/decelerate_quad" android:toAlpha="1.0"/>
fade_out 淡出微信
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="1.0" android:interpolator="@interpolator/accelerate_quad" android:toAlpha="0.0"/>
slide_out_right 淡出到右邊屏幕app
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="@android:integer/config_mediumAnimTime" android:fromXDelta="0" android:toXDelta="50%p"/> <alpha android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="1.0" android:toAlpha="0.0"/> </set>
slide_out_leftdom
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="@android:integer/config_mediumAnimTime" android:fromXDelta="0" android:toXDelta="-50%p"/> <alpha android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="1.0" android:toAlpha="0.0"/> </set>
slide_in_rightide
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="@android:integer/config_mediumAnimTime" android:fromXDelta="50%p" android:toXDelta="0"/> <alpha android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="0.0" android:toAlpha="1.0"/> </set>
slide_in_left 從左邊淡入到屏幕函數
<set xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.android.com/apk/res/android "> <translate android:duration="@android:integer/config_mediumAnimTime" android:fromXDelta="-50%p" android:toXDelta="0"/> <alpha android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="0.0" android:toAlpha="1.0"/> </set>
slide_in_child_bottom
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad"> <translate android:duration="@android:integer/config_mediumAnimTime" android:fromYDelta="100%" android:toYDelta="0"/> <alpha android:duration="@android:integer/config_mediumAnimTime" android:fromAlpha="0.0" android:toAlpha="1.0"/> </set>
經過下面代碼能夠實如今Dialog或AlertDialog顯示、消失時的具備可愛的動畫效果:
dialog.getWindow().setWindowAnimations(R.style.dialog_anim);
經過下面代碼能夠實如今popupWindow 顯示、消失時的具備可愛的動畫效果:
popWindow.setAnimationStyle(R.style.dialog_anim);
其中,R.style.dialog_anim
爲在styles.xml
中定義的一個樣式:
<style name="dialog_animation" parent="@android:style/Animation"> <!--窗體進入動畫--><item name="android:windowEnterAnimation">@anim/popshow_anim</item> <!--窗體退出動畫--><item name="android:windowExitAnimation">@anim/pophidden_anim</item> </style>
其中引用的即是兩個自定義的補間動畫,經常使用的效果的設置以下:
popshow_anim.xml 由下往上淡入
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="100%p" android:toYDelta="0" /> <alpha android:duration="1000" android:fromAlpha="0.0" android:toAlpha="1.0" /> </set>
pophidden_anim.xml 由上往下淡出
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="0" android:toYDelta="50%p" /> <alpha android:duration="1000" android:fromAlpha="1.0" android:toAlpha="0.0" /> </set>
一、在res/drawable/
目錄下定義動畫:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <item android:drawable="@drawable/icon" android:duration="200"/> <item android:drawable="@drawable/ic_launcher" android:duration="200"/> <item android:drawable="@drawable/pic" android:duration="200"/> </animation-list>
二、設置爲背景
view.setBackgroundResource(R.drawable.frame_anim); //必須設爲背景
三、開啓動畫
Drawable drawable = view.getBackground(); if (drawable instanceof AnimationDrawable) { AnimationDrawable animationDrawable = (AnimationDrawable) drawable; Toast.makeText(this, "是否正在運行:" + animationDrawable.isRunning(), Toast.LENGTH_SHORT).show(); animationDrawable.stop(); animationDrawable.start(); }
注意事項:
It's important to note that the start()
method called on the AnimationDrawable cannot be called during the onCreate()
method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged()
method in your Activity, which will get called when Android brings your window into focus.
請注意,在Activity的
onCreate()
方法中,不能調用AnimationDrawable的start()
方法,由於AnimationDrawable還沒有徹底附加到窗口。若是要當即播放動畫,而不須要交互,那麼您可能但願在Activity中的onWindowFocusChanged()
方法中調用它,當Android將您的窗口置於焦點時,該動畫將被調用。
Drawable Animation
或者 Frame Animation
,幀動畫,就像GIF圖片(或電影)同樣,是經過依次顯示一系列的 Drawable 來模擬動畫的效果。
以<animation-list>
爲根元素,一個<item>
表示一幀要輪換顯示的圖片
oneshot
表明着是否只展現一遍,設置爲false會不停的循環播放動畫duration
屬性表示此幀顯示的時間注意事項:
background
屬性爲指定的幀動畫,或在代碼中經過 setBackgroundResource(R.drawable.amin_id)
指定幀動畫,可是不能設置 src
屬性爲指定的幀動畫。固然二者能夠同時設置,此時src保持不變,背景是個動畫會改變。getBackground()
強轉過來的,可能不存在!onCreate()
中調用start方法開啓幀動畫,由於此時幀動畫尚未徹底跟Window相關聯,若是想要在界面顯示時就當即開始動畫的話,能夠在onWindowFoucsChanged()
方法中調用start方法。雖然定義三種動畫的xml文件均可以放置在res/anim/
文件夾中,可是建議:
res/drawable
文件夾中res/anim
文件夾中res/animator
文件夾中public class AnimationDrawable extends DrawableContainer implements Runnable, Animatable
AnimationDrawable
是 Drawable
的間接子類。
Drawable 相關的方法:
void addFrame(Drawable frame, int duration)
:Adds a frame to the animationDrawable getFrame(int index)
:Return the Drawable at the specified frame indexDrawable mutate()
:Make this drawable mutable易變的. This operation cannot be reversed反轉. 動畫相關的方法:
int getDuration(int i)
:Return the duration in milliseconds of the frame at the specified indexint getNumberOfFrames()
:Return the number of frames in the animationboolean isOneShot()
:Return true of the animation will play once, false otherwisevoid setOneShot(boolean oneShot)
:Sets whether the animation should play once or repeat.其餘不經常使用的方法:
void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Resources.Theme theme)
:Inflate this Drawable from an XML resource optionally styled by a theme.void run()
:This method exists for implementation purpose only and should not be called directly. Invoke start()
instead.boolean setVisible(boolean visible, boolean restart)
:Sets whether this AnimationDrawable is visible.void unscheduleSelf(Runnable what)
:Use the current Drawable.Callback
implementation to have this Drawable unscheduled.最經常使用的是 Animatable
接口中定義的三個方法:
public interface Animatable { void start(); //Starts the drawable's animation. This method has no effect if the animation is running. void stop(); //Stops the drawable's animation. This method has no effect if the animation is not running. boolean isRunning(); //Indicates whether the animation is running. }
<activity android:name="com.bqt.anim.property.MainActivity"/> <activity android:name="com.bqt.anim.property.SecondActivity"/> <activity android:name="com.bqt.anim.property.InterpolatorActivity"/> <activity android:name="com.bqt.anim.property.TypeEvaluatorActivity"/> <activity android:name="com.bqt.anim.property.LayoutTransitionActivity"/> <activity android:name="com.bqt.anim.property.LayoutAnimationControllerActivity"/> <activity android:name="com.bqt.anim.tweened.MainActivity"/> <activity android:name="com.bqt.anim.tweened.SecondActivity"/> <activity android:name="com.bqt.anim.tweened.transition.Activity1"/>
2019-5-11