在做安卓UI的時候有時候需自定義具有動畫效果的按鈕或需要自定義一下actionbar~
本節用一個簡單的demo講如何自定義具有動畫效果的按鈕,以及個性化的actionbar
下面是效果:
其中:
△ 自定義button是由 3 個ImageView + animation動畫構成
△ actionbar是自定義的效果,按鈕按動也用到了動畫
下面是整個工程的結構:
需要引用v7工程,因為繼承了v7的ActionBarActivity
其中MyAnimation.java包含按鈕動畫的方法
其中MyActionBar.java封裝自定義ActionBar的構造和監聽函數
其中MyButton.java封裝自定義Button的構造和監聽函數
MainActivity.java是主Activity
自定義actionbar上面的按鈕偶數次按下施加的動畫定義(順時針旋轉90度)
自定義actionbar上面的按鈕奇數次按下施加的動畫定義(逆時針選轉90度)
自定義button偶數次按下施加的旋轉動畫(順時針360度)
自定義button奇數次按下施加的旋轉動畫(逆時針360度)
bar1-4自定義actionbar上面的從左到右四個圖片
icon
...down自定義button黃色
...up自定義button綠色
自定義button橙色
activity_main.xml 主頁面
layout_actionbar.xml 自定義actionbar樣式
colors.xml 定義了actionbar和主頁面的背景顏色(銀灰色)
styles.xml 定義了主頁面的主題(需要在Manifiest文件中用到,且一定得是Theme.Base.AppCompat.Light同一款的主題,否則出錯)
首先來看MainActivity.java
其中黃色的是自定義Button相關的部分,紅色的是自定義ActionBar相關的部分
其中自定義Button包含3個ImageView,所以第18行要用這三個ImageView構造自定義Button
1 public class MainActivity extends ActionBarActivity{ 2 3 private ImageView mImageViewMain, mImageViewMainUp, mImageViewMainDown; 4 private MyButton mMyButton; 5 private MyActionBar mMyActionBar; 6 7 8 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 12 WindowManager.LayoutParams.FLAG_FULLSCREEN); 13 setContentView(R.layout.activity_main); 14 15 mImageViewMain = (ImageView) findViewById(R.id.imageView_btn_bottom); 16 mImageViewMainUp = (ImageView) findViewById(R.id.imageView_btn_top); 17 mImageViewMainDown = (ImageView) findViewById(R.id.imageView_btn_middle); 18 mMyButton=new MyButton(this,mImageViewMain,mImageViewMainUp,mImageViewMainDown); 19 20 mMyActionBar=new MyActionBar(this); 21 mMyActionBar.setActionBar(); 22 } 23 24 public void onMyButtonClick(View view){ 25 mMyButton.onClick(view); 26 } 27 28 public void onMyActionBarClick(View view){ 29 mMyActionBar.onClick(view); 30 } 31 }
這里重點說一下自定義按鈕和自定義actionBar的監聽函數:
其實在MyButton和MyActionBar中實現的只是onClick監聽函數,並沒有和具體事件綁定
我們最常見的是XXXX.setOnClickListener(....)
這里是用了直接在相應控件的XML中定義:
類似的也采用同樣的方法給ActionBar上的左1、3、4按鈕加了一個同樣的onMyActionBarClick監聽事件
注:一旦在MXL中注冊一定要在activity.java中實現!!!
接着看MyButton.java的具體實現:
構造函數不說了~
在onClick函數中用view.getId()區分點擊的按鈕是哪一個
這個自定義按鈕有兩種狀態:
未被按——橙紅色的按鈕在上面不透明;黃色和綠色按鈕在下面透明
被按下——黃色按鈕向上移200單位,綠色向上400單位,兩個均變成不透明
在未被按狀態點擊橙紅色按鈕——橙紅色逆時針旋轉360度,黃色和綠色同時向上移動200和400單位,同時兩個ImageView大小從0倍到1倍放大,透明度從完全透明到不透明
在被點擊狀態點擊三個按鈕中任何一個——所有按鈕的動畫逆向回歸
1 public class MyButton { 2 3 private ImageView mImageViewMain, mImageViewMainUp, mImageViewMainDown; 4 private Context context; 5 private boolean isPressed; 6 private MyAnimation mMyAnimation;//動畫相關 7 8 public MyButton(Context context, 9 ImageView mImageViewMain,ImageView mImageViewMainUp,ImageView mImageViewMainDown){ 10 isPressed=false; 11 this.context=context; 12 this.mImageViewMain=mImageViewMain; 13 this.mImageViewMainUp=mImageViewMainUp; 14 this.mImageViewMainDown=mImageViewMainDown; 15 mMyAnimation=new MyAnimation(context); 16 } 17 18 /** 19 * 三個按鈕的點擊事件 20 * @param view 21 */ 22 private static int[] button_animation_id={R.anim.my_button_rotate_go,R.anim.my_button_rotate_back}; 23 public void onClick(View view) { 24 25 switch (view.getId()) { 26 case R.id.imageView_btn_bottom: 27 mMyAnimation.rotation(view,button_animation_id[isPressed==false ? 0:1]); 28 mMyAnimation.animationShow(mImageViewMainUp, 400,!isPressed); 29 mMyAnimation.animationShow(mImageViewMainDown, 200,!isPressed); 30 break; 31 case R.id.imageView_btn_top: 32 mMyAnimation.rotation(mImageViewMain,button_animation_id[isPressed==false ? 0:1]); 33 mMyAnimation.animationShow(mImageViewMainUp, 400,!isPressed); 34 mMyAnimation.animationShow(mImageViewMainDown, 200,!isPressed); 35 break; 36 case R.id.imageView_btn_middle: 37 mMyAnimation.rotation(mImageViewMain,button_animation_id[isPressed==false ? 0:1]); 38 mMyAnimation.animationShow(mImageViewMainUp, 400,!isPressed); 39 mMyAnimation.animationShow(mImageViewMainDown, 200,!isPressed); 40 break; 41 default: 42 break; 43 } 44 isPressed=!isPressed; 45 } 46 }
相同的,MyActionBar.java中:
左1、3、4三個按鈕有一個旋轉90度的動畫效果~
1 public class MyActionBar { 2 3 private ActionBar actionBar; 4 private LayoutInflater inflator; 5 private Context context; 6 private MyAnimation mMyAnimation;//動畫相關 7 private boolean bar1_isPressed,bar2_isPressed,bar3_isPressed,bar4_isPressed; 8 9 public MyActionBar(Context context){ 10 this.context=context; 11 bar1_isPressed=bar2_isPressed=bar3_isPressed=bar4_isPressed=false; 12 mMyAnimation=new MyAnimation(context); 13 } 14 15 public void setActionBar() {// 自定義actionbar 16 inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 17 actionBar = ((ActionBarActivity)context).getSupportActionBar(); 18 actionBar.setDisplayShowHomeEnabled(false); 19 actionBar.setDisplayShowCustomEnabled(true); 20 actionBar.setDisplayShowTitleEnabled(false); 21 actionBar.setDisplayHomeAsUpEnabled(false); 22 23 View view = inflator.inflate(R.layout.layout_actionbar, null); 24 ActionBar.LayoutParams layout = new ActionBar.LayoutParams( 25 LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 26 actionBar.setCustomView(view, layout); 27 } 28 29 private static int[] actionbar_animation_id={R.anim.my_actionbar_rotate_go,R.anim.my_actionbar_rotate_back}; 30 public void onClick(View view) { 31 switch (view.getId()) { 32 case R.id.imageView_bar1: 33 mMyAnimation.rotation(view,actionbar_animation_id[bar1_isPressed==false ? 0:1]); 34 bar1_isPressed=!bar1_isPressed; 35 break; 36 case R.id.imageView_bar3: 37 mMyAnimation.rotation(view,actionbar_animation_id[bar3_isPressed==false ? 0:1]); 38 bar3_isPressed=!bar3_isPressed; 39 break; 40 case R.id.imageView_bar4: 41 mMyAnimation.rotation(view,actionbar_animation_id[bar4_isPressed==false ? 0:1]); 42 bar4_isPressed=!bar4_isPressed; 43 break; 44 } 45 } 46 }
上面兩個自定義控件中的動畫效果功能函數封裝在Animation.java中:
rotation函數負責將id所指的動畫資源作用於view上
animationShow是作用與view使之出現或消失並可以帶有向上或向下、變大或變小的運動效果
1 public class MyAnimation { 2 3 private Context context; 4 5 public MyAnimation(Context context){ 6 this.context=context; 7 } 8 9 /** 10 * 讓view執行id的動畫 11 * @param view 12 * @param id 13 */ 14 public void rotation(View view,int id) { 15 16 Animation operatingAnim; 17 operatingAnim = AnimationUtils.loadAnimation(context,id); 18 LinearInterpolator lin = new LinearInterpolator(); 19 operatingAnim.setInterpolator(lin); 20 view.clearAnimation(); 21 view.startAnimation(operatingAnim); 22 } 23 24 /** 25 * 讓view從無到有顯示出來(大小1:1,up為正為向下走,為負向上走) 26 * @param view 27 * @param up 28 */ 29 /** 30 * 讓view從無到有顯示出來 31 * @param view 32 * @param dis 去或者回來的距離(去是從原點到上面dis距離),來是從dis距離向下到原點 33 * @param isGo 為true是去,為fasle是回 34 */ 35 public void animationShow(View view, int dis,boolean isGo) { 36 37 AnimatorSet set = new AnimatorSet(); 38 if(isGo==true){ 39 set.playTogether(ObjectAnimator.ofFloat(view, "translationY", 0, -dis), 40 ObjectAnimator.ofFloat(view, "scaleX", 0f, 1f), 41 ObjectAnimator.ofFloat(view, "scaleY", 0f, 1f), 42 ObjectAnimator.ofFloat(view, "alpha", 0f, 1f)); 43 }else{ 44 set.playTogether(ObjectAnimator.ofFloat(view, "translationY", -dis, 0), 45 ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f), 46 ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f), 47 ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)); 48 } 49 50 set.start(); 51 } 52 }
下面是res/anim下的四個動畫集合,他們的id就是傳入rotation的id~
其中button相關的兩個負責自定義button中橙紅色按鈕旋轉360用;其中actionbar相關的負責actionbar上的按鈕旋轉90度用
注意:下面綠色的部分是為了防止動畫結束之后又恢復原狀而加的屬性,一定要加在set中!!!
其中from和to表示:該動畫從角度為from旋轉到to的位置,其中正表示順時針角度,負表示逆時針角度,0為最初狀態角度
其中duration表示:該動畫持續的時間ms
其中pivotX/Y表示:該旋轉繞哪里旋轉
my_button_rotate_back.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android" 2 android:fillAfter="true" > 3 4 <rotate 5 android:fromDegrees="0" 6 android:toDegrees="359" 7 android:duration="200" 8 android:pivotX="50%" 9 android:pivotY="50%"/> 10 </set>
my_button_rotate_go.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android" 2 android:fillAfter="true" > 3 4 <rotate 5 android:fromDegrees="0" 6 android:toDegrees="-359" 7 android:duration="200" 8 android:pivotX="50%" 9 android:pivotY="50%"/> 10 </set>
my_actionbar_rotate_go.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <set xmlns:android="http://schemas.android.com/apk/res/android" 3 android:fillAfter="true" > 4 5 <rotate 6 android:fromDegrees="0" 7 android:toDegrees="-90" 8 android:duration="200" 9 android:pivotX="50%" 10 android:pivotY="50%"/> 11 </set>
my_actionbar_rotate_back.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android" 2 android:fillAfter="true" > 3 4 <rotate 5 android:fromDegrees="-90" 6 android:toDegrees="0" 7 android:duration="200" 8 android:pivotX="50%" 9 android:pivotY="50%"/> 10 </set>
其中:shape_main_adding.xml負責自定按鈕下面遮罩層的從上到下的白色模糊效果(類似於iPad上面的扁平狀ICON條)
1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android"> 3 <gradient 4 android:startColor="#AAFFFFFF" 5 android:endColor="#00EEEEEE" 6 android:angle="90" /> 7 </shape> 8 9 <!-- http://l62s.iteye.com/blog/1659433 -->
相關鏈接:
本講的工程代碼:http://pan.baidu.com/s/1o65ZOca
Android使用Animation完成動畫淡出效果避免重新恢復最后一幀亮度的辦法(用這個解決了動畫播放完就恢復的問題,加了代碼中綠色的那條)
Android應用開發筆記(10):制作自定義背景Button按鈕、自定義形狀Button的全攻略(我沒用這個的)
Android自定義ActionBar(我沒用這個的)
android 圍繞中心旋轉動畫(這個我有參考,設計旋轉360度view效果的時候,里面比較詳細)
Android屬性動畫(Property Animation) 完全解析 (上)(這個講的挺全的,我沒仔細看)
android用NineOldAndroid實現的彈出按鈕(我從這個找到靈感設計自己的button)
Android背景漸變色(shape,gradient)(用這個解決了設計模糊遮罩的效果,很好的)
Android布局----讓一個控件居底部(有看看,沒用)
@beautifulzzzz
2015-11-18 持續更新中~