Android之衛星菜單的實現

  衛星菜單是現在一個非常受歡迎的“控件”,很多Android程序員都趨之若鶩,預覽如下圖。傳統的衛星菜單是用Animation實現的,需要大量的代碼,而且算法極多,一不小心就要通宵Debug。本帖貼出用屬性動畫Animator來實現衛星菜單。

一、淺析屬性動畫Animator

  Animator是Android3.0發布的新功能,代碼簡單,效果豐富。屬性動畫,顧名思義,只要是可以GET和SET的屬性,我們都可以用屬性動畫進行處理。屬性動畫中常用的屬性和方法如下:

ValueAnimator  //數值發生器,可以實現很多很靈活的動畫效果
ObjectAnimator  //ValueAnimator的子類,對ValueAnimator進行了封裝,讓我們可以更輕松的使用屬性動畫,我們通過ObjectAnimator來操縱一個對象,產生動畫效果
AnimatorListener  //對動畫的開始、結束、暫停、重復等動作的事件監聽(需要重寫四個方法)
AnimatorListenerAdapter  //對動畫的開始、結束、暫停、重復中的一個動作的事件監聽(根據選擇的動作,只需要重寫一個方法)
AnimatorSet  //動畫的集合,用來設置多個動畫之間的關系(之前、之后、同時等)
PropertyValuesHolder  //動畫的集合,和AnimatorSet類似
TypeEvaluator  //值計算器,在使用ValueAnimator.ofObject()方法時引入自定義的屬性對象
Interpolator  //插值器,設置動畫的特效(速度漸變、彈跳等)

下面對這幾個類做一下簡單的介紹:

(一)ObjectAnimator:ObjectAnimator是最簡單、最常用的屬性動畫,根據文檔上的敘述:?This subclass of ValueAnimator provides support for animating properties on target objects.?,這個ValueAnimator的子類對Object對象的屬性提供動畫。ObjectAnimator中常用的屬性如下:

translationX / translationY             水平/垂直平移
rotaionX / rotationY                    橫向/縱向旋轉
scaleX / scaleY                         水平/垂直縮放
X / Y                                   直接到達X/Y坐標
alpha                                   透明度

我們使用一些方法(?ofFloat()?、?ofInt()?、?ofObject()?、?ofPropertyValuesHolder()?等)來實現動畫,調用?start()?方法來啟動動畫。選擇哪個方法,主要是屬性值的類型決定的。我們先來看看文檔中對這幾個方法的介紹:

target指的是動畫的作用對象,一般指控件;propertyName就是上面說的“translationX”、“alpha”等屬性名;values是一個不定長數組,記錄著屬性的始末值。唯一不同的是ofPropertyValuesHolder()方法,這個方法沒有property參數,是因為這個參數在PropertyValuesHolder對象中就已經使用(下面會介紹PropertyValuesHolder的使用方法)。

(二)AnimatorListener:這是一個接口,監聽屬性動畫的狀態(開始/重復/結束/取消),Animator及其子類(包括ValueAnimator和ObjectAnimator等)都可以使用這個接口,使用?anim.addListener()?使用這個接口。具體的使用方法如下:

animator.addListener(new AnimatorListener() {@Override  // 動畫開始的監聽器public void onAnimationStart(Animator animation) { ... }@Override  // 動畫重復的監聽器public void onAnimationRepeat(Animator animation) { ... }@Override  // 動畫結束的監聽器public void onAnimationEnd(Animator animation) { ... }@Override  // 動畫取消的監聽器public void onAnimationCancel(Animator animation) { ... }
});

(三)AnimatorListenerAdapter:我們在實際開發中往往不會用到AnimatorListener中的全部四個方法,所以如果我們使用AnimatorListener,不僅浪費系統資源,代碼看上去也不好看,因此,我們需要一個適配器(Adapter),可以讓我們根據自己的意愿,只實現監聽器中的一個或幾個方法,這就要用到AnimatorListenerAdapter了。AnimatorListenerAdapter的使用方法和AnimatorListener一樣,都需要使用?anim.addListener()?方法,不同的是參數。代碼如下:

animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) { ... }@Overridepublic void onAnimationCancel(Animator animation) { ... }
});

(四)AnimatorSet:先來看文檔中的介紹:?This class plays a set of Animator objects in the specified order. Animations can be set up to play together, in sequence, or after a specified delay. ?這個類支持按順序播放一系列動畫,這些動畫可以同時播放、按順序播放,也可以在一段時間之后播放(主要通過?setStartDelay()?方法實現)。下面是文檔中對這些方法的介紹:

值得說的是play()方法,它返回的是一個Builder對象,而Builder對象可以通過?with()?、?before()?、?after()?等方法,非常方便的控制一個動畫與其他Animator動畫的先后順序。例如:

AnimatorSet s = new AnimatorSet();
s.play(anim1).with(anim2);
s.play(anim2).before(anim3);
s.play(anim4).after(anim3);

(五)PropertyValuesHolder:使用PropertyValuesHolder結合ObjectAnimator或ValueAnimator,可以達到AnimatorSet的效果。可以說,PropertyValuesHolder就是為了動畫集而存在的,它不能單獨的存在,因為它沒有target參數(因此可以節省系統資源),所以只能依靠ObjectAnimator或ValueAnimator存在。一個實例的代碼如下:

PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 0F, 200F);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("translationY", 0F, 200F);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("rotation", 0F, 360F);
ObjectAnimator.ofPropertyValuesHolder(top, pvh1, pvh2, pvh3).setDuration(2000).start();

(六)ValueAnimator:是ObjectAnimator的父類,但由于不能相應動畫,也不能設置屬性(值的是沒有target和property兩個參數),所以不常用。如果我們要監聽ValueAnimator,則只能為ValueAnimator添加一個AnimatorUpdateListener(AnimatorUpdateListener可以監聽Animator每個瞬間的變化,取出對應的值)。一個實例的代碼如下:

ValueAnimator animator = ValueAnimator.ofInt(0, 100); // 沒有target和property參數
animator.setDuration(5000);
animator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Integer value = (Integer) animation.getAnimatedValue();System.out.println("-->" + value);}
});
animator.start();

(七)TypeEvaluator:主要用于ValueAnimator的ofObject()方法。根據文檔中的介紹,?Evaluators allow developers to create animations on arbitrary property types?,Evaluators允許開發者自定義動畫參數。因此,使用TypeEvaluator,我們可以打破ObjectAnimator的動畫范圍禁錮,創造我們自己的動畫。大致代碼如下:

ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<Object>() {@Overridepublic Object evaluate(float fraction, Object startValue, Object endValue) {return null;}
});
animator.start();

(八)Interpolator:插值器,可以設置動畫的效果。Animator內置了很多插值器,如漸加速、漸減速、彈跳等等。插值器的種類可以在模擬器API DEMO應用的Views - Animation - Interpolator中查看。為Animator添加插值器只需要?animator.setInterpolator(new OvershootInterpolator());?即可。

?

二、實現衛星菜單

  實現衛星菜單,我們主要使用了ObjectAnimator。先來介紹一下這個DEMO的效果(如下組圖):開始的時候在屏幕左上角顯示一個紅色的按鈕,點擊之后彈出一列子菜單,每個子菜單之間的距離遞增,彈出的時間遞減,彈出時會有OverShoot效果,點擊每個子菜單都會彈出相應的Toast;彈出菜單后再次點擊紅色按鈕,則收回所有子菜單。

下面貼出代碼。

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:background="@color/white" >
 6 
 7     <!-- 上面的七張圖片是七個子菜單 -->
 8     <ImageView
 9         android:id="@+id/menuitem_07"
10         style="@style/SateliteMenu_Item_Theme"
11         android:contentDescription="@string/app_name"
12         android:src="@drawable/item_07" />
13 
14     <ImageView
15         android:id="@+id/menuitem_06"
16         style="@style/SateliteMenu_Item_Theme"
17         android:contentDescription="@string/app_name"
18         android:src="@drawable/item_06" />
19 
20     <ImageView
21         android:id="@+id/menuitem_05"
22         style="@style/SateliteMenu_Item_Theme"
23         android:contentDescription="@string/app_name"
24         android:src="@drawable/item_05" />
25 
26     <ImageView
27         android:id="@+id/menuitem_04"
28         style="@style/SateliteMenu_Item_Theme"
29         android:contentDescription="@string/app_name"
30         android:src="@drawable/item_04" />
31 
32     <ImageView
33         android:id="@+id/menuitem_03"
34         style="@style/SateliteMenu_Item_Theme"
35         android:contentDescription="@string/app_name"
36         android:src="@drawable/item_03" />
37 
38     <ImageView
39         android:id="@+id/menuitem_02"
40         style="@style/SateliteMenu_Item_Theme"
41         android:contentDescription="@string/app_name"
42         android:src="@drawable/item_02" />
43 
44     <ImageView
45         android:id="@+id/menuitem_01"
46         style="@style/SateliteMenu_Item_Theme"
47         android:contentDescription="@string/app_name"
48         android:src="@drawable/item_01" />
49 
50     <!-- 最上層的紅色按鈕,因為它顯示在最上面,因此布局代碼在最后 -->
51     <ImageView
52         android:id="@+id/menu_top"
53         android:layout_width="35.0dip"
54         android:layout_height="35.0dip"
55         android:layout_marginLeft="17.0dip"
56         android:layout_marginTop="17.0dip"
57         android:contentDescription="@string/app_name"
58         android:src="@drawable/top_toopen" />
59 
60 </RelativeLayout>
MainActivity布局代碼
 1 public class MainActivity extends Activity implements OnClickListener {
 2     private ImageView top; // 紅色按鈕
 3     // 七個子菜單的ID組成的數組
 4     private int[] ids = new int[] { R.id.menuitem_01, R.id.menuitem_02, R.id.menuitem_03, R.id.menuitem_04, R.id.menuitem_05, R.id.menuitem_06, R.id.menuitem_07, };
 5     private List<ImageView> itemList; // 七個子菜單都加到List中
 6     private boolean isMenuOpen; // 記錄子菜單是否打開了
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12         initView();
13     }
14 
15     private void initView() {
16         top = (ImageView) findViewById(R.id.menu_top);
17         top.setOnClickListener(this);
18 
19         itemList = new ArrayList<ImageView>();
20         for (int i = 0; i < ids.length; i++) {
21             ImageView imageView = (ImageView) findViewById(ids[i]);
22             imageView.setOnClickListener(this);
23             itemList.add(imageView);
24         }
25     }
26 
27     @Override
28     public void onClick(View v) {
29         switch (v.getId()) {
30         case R.id.menu_top:
31             if (!isMenuOpen) { // 如果子菜單處于關閉狀態,則使用Animator動畫打開菜單
32                 for (int i = 0; i < itemList.size(); i++) {
33                     // 子菜單之間的間距對著距離的增加而遞增
34                     ObjectAnimator animator = ObjectAnimator.ofFloat(itemList.get(i), "translationY", 0, (i + 1) * (30 + 2 * i));
35                     animator.setDuration((7 - i) * 100); // 最遠的子菜單彈出速度最快
36                     animator.setInterpolator(new OvershootInterpolator()); // 設置插值器
37                     animator.start();
38                 }
39                 top.setImageResource(R.drawable.top_toclose);
40                 isMenuOpen = true;
41             } else { // 如果子菜單處于打開狀態,則使用Animator動畫關閉菜單
42                 for (int i = 0; i < itemList.size(); i++) {
43                     ObjectAnimator animator = ObjectAnimator.ofFloat(itemList.get(i), "translationY", (i + 1) * (30 + 2 * i), 0);
44                     animator.setDuration((7 - i) * 100);
45                     animator.start();
46                 }
47                 top.setImageResource(R.drawable.top_toopen);
48                 isMenuOpen = false;
49             }
50             break;
51         default:
52             Toast.makeText(MainActivity.this, "Item" + (itemList.indexOf(v) + 1) + " Clicked...", Toast.LENGTH_SHORT).show();
53             break;
54         }
55     }
56 }
MainActivity代碼

?


三、擴展

  使用屬性動畫可以實現的功能還有很多,這里再追加一個“評分”的功能實現。直接顯示成績往往給人一種突兀的感覺,所以我們想利用屬性動畫來實現一個數字變換的“成績單”,讓成績滾動顯示,同時,越到最后滾動的越慢,最后停止在真正的分數上。

  思路:我們需要用到ValueAnimator,并用AnimatorUpdateListener作為動畫的監聽器,監聽動畫的每一個動作,并為成績的TextView設置Text。

  以下是代碼。

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:background="@color/white" >
 6 
 7     <TextView
 8         android:id="@+id/main_mark"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:layout_centerInParent="true"
12         android:textColor="#ff0000"
13         android:textSize="65.0sp" />
14 
15 </RelativeLayout>
MainActivity布局代碼
 1 public class MainActivity extends Activity {
 2     private TextView mark;
 3     private static final int REAL_MARK = 96;
 4 
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.activity_main);
 9         initView();
10     }
11 
12     private void initView() {
13         mark = (TextView) findViewById(R.id.main_mark);
14 
15         ValueAnimator animator = ValueAnimator.ofInt(0, REAL_MARK);
16         animator.setDuration(3000);
17         animator.setInterpolator(new DecelerateInterpolator());
18         animator.addUpdateListener(new AnimatorUpdateListener() {
19             @Override
20             public void onAnimationUpdate(ValueAnimator animation) {
21                 Integer value = (Integer) animation.getAnimatedValue();
22                 mark.setText(value + "");
23             }
24         });
25         animator.start();
26     }
27 }
MainActivity代碼

?

轉載于:https://www.cnblogs.com/blog-wzy/p/5324316.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/373358.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/373358.shtml
英文地址,請注明出處:http://en.pswp.cn/news/373358.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java中的WADL:溫和的介紹

WADL&#xff08; Web應用程序描述語言 &#xff09;對REST而言&#xff0c;WSDL對SOAP而言。 這種語言的僅僅存在引起了很多爭議&#xff08;請參閱&#xff1a; 我們需要WADL嗎&#xff1f; 或者 需要 WADL還是不需要WADL &#xff09;。 我可以想到使用WADL的一些合法用例&a…

類成員函數模板特化

//類成員函數模板特化 #include <stdio.h> class A{ public:template <class T>void Print(){printf("A template\n");} };template<> void A::Print<int>(){printf("int\n"); }int main(){A a;a.Print<double>();a.Print&l…

為云量身定制您的服務

相信大家都聽說過Amazon的AWS。作為業內最為成熟的云服務提供商&#xff0c;其運行規模&#xff0c;穩定性&#xff0c;安全性都已經經過了市場的考驗。時至今日&#xff0c;越來越多的應用被部署在了AWS之上。這其中不乏Zynga及Netflix這樣著名的服務。 然而這一切并沒有停滯不…

在Vaadin和JSF之間選擇

隨著最新版本的Primefaces 3.0的發布&#xff0c;JSF終于達到了前所未有的成熟度和實用性&#xff0c;使其與其他流行的Rich Internet Applications&#xff08;RIA&#xff09;選項如Google Web Toolkit&#xff08;GWT&#xff09;&#xff0c;ExtJS&#xff0c;Vaadin&#…

20145202馬超《信息安全系統設計基礎》實驗二總結

[實驗二]&#xff08;http://www.cnblogs.com/nizaikanwoma/p/6131778.html&#xff09; 轉載于:https://www.cnblogs.com/tuolemi/p/6131987.html

java 連接ldap_ldap java 連接demo

public class LDAPHelper {/*** LDAP可以理解為一個多級目錄&#xff0c;這里&#xff0c;表示要連接到那個具體的目錄*/private final String baseDn "ouPeople,dcchangyeyi,dccom";private LdapContext ctx null;private final Control[] connCtls null;private…

flask開發restful api系列(1)

在此之前&#xff0c;向大家說明的是&#xff0c;我們整個框架用的是flask sqlalchemy redis。如果沒有開發過web&#xff0c;還是先去學習一下&#xff0c;這邊只是介紹如果從開發web轉換到開發移動端。如果flask還不是很熟悉&#xff0c;我建議先到這個網站簡單學習一下&am…

Apache Commons Lang StringUtils

因此&#xff0c;認為最好談論我喜歡的另一個Java庫。 它已經存在了一段時間&#xff0c;也許不是最令人興奮的庫&#xff0c;但是它非常有用。 我可能每天都使用它。 org.apache.commons.lang.StringUtils StringUtils是Apache Commons Lang&#xff08; http://commons.apac…

JEE7:展望新時代

計劃于2012年下半年發布的Java EE 7預計的JSR都已啟動并正在運行。 Java EE 7發行版是日期驅動的&#xff0c;它將反映該行業遷移到云中時不斷變化的需求&#xff1a;任何未準備就緒的內容將推遲到Java EE 8中使用 。 這是Java EE 7平臺中不同規范的關鍵功能的更新和摘要。 1。…

Cocos2d-JS項目之UI界面的優化

測試環境&#xff1a; iphone4、iOS6.1.2、chrome 37.2062.60&#xff0c;Cocos2d-js 3.6 之前寫了不少&#xff0c;實際項目也按這個去優化了&#xff0c;也有效果&#xff0c;但到最后才發現&#xff0c;尼瑪&#xff0c;之前都搞錯了&#xff0c;之所以有效果是歪打正著。。…

java數_java大數

java大數還是很好用的&#xff01;基本加入&#xff1a;import java.math.BigInteger;import jave.math.BigDecimal;分別是大數和大浮點數。首先讀入可以用&#xff1a;Scanner input new Scanner(System.in);BigInteger a input.nextBigInteger();這樣讀還是很方便的當然還有…

【Qt之Quick模塊】6. QML語法詳解_2類型系統

描述 在QML文檔中對象層次結構的定義中可能使用的類型可以來自各種來源。它們可能是: 由QML語言原生提供通過QML模塊通過c注冊由QML模塊作為QML文檔提供 此外&#xff0c;應用程序開發人員可以通過直接注冊c類型&#xff0c;或者通過在QML文檔中定義可重用的組件(然后可以導…

JS顯示當前時間(包含農歷時間)

時間格式&#xff1a; JavaScript代碼&#xff1a; var sWeek new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");var dNow new Date();var CalendarData new Arra…

Maven原型創建技巧

我最近需要為姜黃SOA項目創建一些Maven原型。 對于不了解的人來說&#xff0c; Maven原型是一種基于一些預先罐裝的項目模板生成項目的方法。 對于當前的姜黃SOA原型&#xff0c;它將創建一個多模塊Maven項目&#xff0c;該項目包含Interface和Service項目以及基本的WSDL和適當…

MyBatis操作指南-與Spring集成(基于注解)

轉載于:https://www.cnblogs.com/weilu2/p/mybatis_spring_integration_basic_on_annotation.html

Windows mysql boost_Win7下Boost庫的安裝

Boost庫是C領域公認的經過千錘百煉的知名C類庫&#xff0c;涉及編程中的方方面面&#xff0c;簡單記錄一下使用時的安裝過程1.boost庫的下載boost庫官網主頁&#xff1a;www.boost.org2.安裝將下載的壓縮包解壓到指定的目錄3.建立編譯工具bjam.exe在源碼目錄下執行bootstrap.ba…

5.2與終端進行對話

Linux提供了一個特殊的設備 /dev/tty &#xff0c;該設備始終是指向當前終端或者當前的登錄會話。 FILE* output fopen("/dev/tty", "w"); //向終端寫入字符串 fprintf(output, "%s\n", "world"); FILE* input fopen("/dev/tty…

JVM:如何分析線程轉儲

本文將教您如何分析JVM線程轉儲&#xff0c;并查明問題的根本原因。 從我的角度來看&#xff0c;線程轉儲分析是掌握Java EE生產支持的任何個人最重要的技能。 您可以從線程轉儲快照中獲取的信息量通常遠遠超出您的想象。 我的目標是與您分享我在過去10年中積累的有關線程轉儲分…

極光推送JPush的快速集成

首先到極光推送的官網上創建一個應用&#xff0c;填寫對應的應用名和包名。 創建好之后下載Demo 提取Sdk里面的圖片和xml等資源文件放自己項目的相應位置&#xff0c;然后要注意的是.so文件的放置位置&#xff1a; 在main目錄下新建一個jniLibs文件夾&#xff0c;放在這個文件夾…

c遺傳算法的終止條件一般_Matlab2 :Matlab遺傳算法(GA)優4~-r-具箱是基于基本操作 聯合開發網 - pudn.com...

Matlab2所屬分類&#xff1a;matlab例程開發工具&#xff1a;PDF文件大小&#xff1a;115KB下載次數&#xff1a;76上傳日期&#xff1a;2007-09-07 20:04:29上 傳 者&#xff1a;錢廣說明&#xff1a; &#xff1a;Matlab遺傳算法(GA)優4~-r-具箱是基于基本操作及終止條件、二…